package org.edx.mobile.services;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import com.google.inject.Inject;
import org.edx.mobile.R;
import org.edx.mobile.http.RestApiManager;
import org.edx.mobile.logger.Logger;
import org.edx.mobile.model.DownloadDescriptor;
import org.edx.mobile.module.analytics.ISegment;
import org.edx.mobile.module.prefs.PrefManager;
import org.edx.mobile.util.NetworkUtil;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import roboguice.service.RoboService;
/**
* Created by marcashman on 2014-12-01.
*/
public class DownloadSpeedService extends RoboService {
private static final String TAG = DownloadSpeedService.class.getCanonicalName();
private static final long NS_PER_SEC = 1000000000;
private static final int BLOCK_SIZE = 4096;
public static final String EXTRA_FILE_DESC = TAG + ".file_desc";
public static final String EXTRA_REPORT_PROGRESS = TAG + ".report_progress";
public static final String EXTRA_KBPS = TAG + ".kbps";
public static final String EXTRA_SECONDS = TAG + ".seconds";
public static final String EXTRA_ERROR = TAG + ".error";
public static final String ACTION_DOWNLOAD_DONE = TAG + ".download_done";
private static final int RUN_SPEED_TEST_MESSAGE = 5555;
private int DELAY_IN_MILLISECONDS = 5000;
private static final Logger logger = new Logger(DownloadSpeedService.class);
@Inject
private ISegment segIO;
@Inject
RestApiManager apiManager;
SpeedTestHandler messageHandler;
Timer timer = null;
TimerTask timerTask = null;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
Message msg = messageHandler.obtainMessage();
DownloadDescriptor descriptor = intent.getParcelableExtra(EXTRA_FILE_DESC);
if (descriptor != null) {
msg.obj = descriptor;
msg.what = RUN_SPEED_TEST_MESSAGE;
messageHandler.sendMessage(msg);
} else {
logger.warn("missing file description");
}
}
return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
startThread();
DELAY_IN_MILLISECONDS = getResources().getInteger(R.integer.delay_speed_test_in_milliseconds);
super.onCreate();
}
private void startThread(){
HandlerThread thread = new HandlerThread("SpeedTestThread", android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Looper serviceLooper = thread.getLooper();
messageHandler = new SpeedTestHandler(serviceLooper);
}
private synchronized void performDownload(DownloadDescriptor file) {
final long startTime;
try {
startTime = System.nanoTime();
Request request = new Request.Builder()
.url(file.getUrl())
.build();
apiManager.createSpeedTestClient().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException throwable) {
logger.error(throwable);
//If it times out, set a low value for download speed
setCurrentDownloadSpeed(0.01f);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (!response.isSuccessful()) {
logger.debug("Download Speed Test Failed");
} else {
long length = response.body().string().length();
double seconds = (System.nanoTime() - startTime) / NS_PER_SEC;
if( seconds != 0 ) {
final float downloadSpeedKps = (float) ((length / seconds) / 1024);
setCurrentDownloadSpeed(downloadSpeedKps);
reportDownloadSpeed(downloadSpeedKps);
}
}
}
});
}catch (Exception ex){
logger.error(ex);
}
}
private void reportDownloadSpeed(float downloadSpeedKps){
try{
if (NetworkUtil.isConnectedWifi(DownloadSpeedService.this)) {
segIO.trackUserConnectionSpeed(ISegment.Values.WIFI, downloadSpeedKps);
} else if (NetworkUtil.isConnectedMobile(DownloadSpeedService.this)) {
segIO.trackUserConnectionSpeed(ISegment.Values.CELL_DATA, downloadSpeedKps);
}
}catch(Exception e){
logger.error(e);
}
}
private void setCurrentDownloadSpeed(float downloadSpeedKps){
PrefManager manager = new PrefManager(this, PrefManager.Pref.WIFI);
manager.put(PrefManager.Key.SPEED_TEST_KBPS, downloadSpeedKps);
}
public class SpeedTestHandler extends Handler {
public SpeedTestHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int messageType = msg.what;
if(messageType == RUN_SPEED_TEST_MESSAGE){
final DownloadDescriptor file = (DownloadDescriptor) msg.obj;
if(file != null){
scheduleNewDownload(file);
}
}
}
}
private void scheduleNewDownload(final DownloadDescriptor file) {
if(timerTask != null) {
timerTask.cancel();
timer.cancel();
timerTask = null;
timer = null;
}
if(file.shouldForceDownload()) {
performDownload(file);
} else {
timerTask = new TimerTask() {
@Override
public void run() {
performDownload(file);
}
};
timer = new Timer();
timer.schedule(timerTask, DELAY_IN_MILLISECONDS);
}
}
}