package edu.berkeley.cs.amplab.carat.android.protocol;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeSet;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import edu.berkeley.cs.amplab.carat.android.CaratApplication;
import edu.berkeley.cs.amplab.carat.android.Constants;
import edu.berkeley.cs.amplab.carat.android.R;
import edu.berkeley.cs.amplab.carat.android.sampling.SamplingLibrary;
import edu.berkeley.cs.amplab.carat.android.storage.CaratSampleDB;
import edu.berkeley.cs.amplab.carat.thrift.Sample;
/**
* Communicates with the Carat Server. Sends samples stored in CaratDB every
* COMMS_INTERVAL ms.
*
* @author Eemil Lagerspetz
*
*/
public class SampleSender {
private static final String TAG = "sendSamples";
private static final String TRY_AGAIN = " will try again later.";
private static final Object sendLock = new Object();
CaratApplication app = null;
// Prevent instantiation
private SampleSender(){}
public static void sendSamples(CaratApplication app) {
synchronized(sendLock){
Context c = app.getApplicationContext();
String networkStatus = SamplingLibrary.getNetworkStatus(c);
String networkType = SamplingLibrary.getNetworkType(c);
final SharedPreferences p = PreferenceManager
.getDefaultSharedPreferences(c);
final boolean useWifiOnly = p.getBoolean(Constants.WIFI_ONLY_PREFERENCE_KEY, false);
Log.i("wifi-preference-SampleSender", String.valueOf(useWifiOnly));
boolean connected = (!useWifiOnly && networkStatus == SamplingLibrary.NETWORKSTATUS_CONNECTED)
|| networkType.equals("WIFI");
if (connected) {
CaratSampleDB db = CaratSampleDB.getInstance(c);
int samples = db.countSamples();
/* Click Tracking: Track sample sending. */
String uuId = p.getString(CaratApplication.getRegisteredUuid(), "UNKNOWN");
HashMap<String, String> options = new HashMap<String, String>();
options.put("count", samples+"");
ClickTracking.track(uuId, "sendingsamples", options, c);
/* End Click Tracking: Track sample sending. */
int successSum = 0;
for (int batches = 0; batches < Constants.COMMS_MAX_BATCHES
&& batches < samples
/ Constants.COMMS_MAX_UPLOAD_BATCH + 1; batches++) {
SortedMap<Long, Sample> map = CaratSampleDB.getInstance(c)
.queryOldestSamples(
Constants.COMMS_MAX_UPLOAD_BATCH);
if (map.size() > 0) {
int progress = (int) (successSum * 1.0 / samples * 100.0);
CaratApplication.setActionProgress(progress, successSum + "/"
+ samples +" "+ app.getString(R.string.samplesreported), false);
if (app.commManager != null) {
int tries = 0;
while (tries < 2) {
try {
int success = app.commManager.uploadSamples(map.values());
tries = 2;
// FlurryAgent.logEvent("UploadSamples");
Log.d(TAG, "Uploaded " + success
+ " samples out of " + map.size());
if (success > 0)
CaratApplication.storage.samplesReported(success);
Sample last = map.get(map.lastKey());
/*
* converting (to human readable date-time format)
* the "timestamp" of the last sample (which is
* uploaded now, and should be deleted along the other
* uploaded samples). The "timestamp" is computed this way:
* CurrentTimeMillis / 1000
* (see getSample() in SamplingLibrary)
*/
long lastSampleTime = (long) last.getTimestamp() * 1000; // in currentTimeMillis
SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm");
Date resultdate = new Date(lastSampleTime);
Log.d(TAG,
"Deleting " + success
+ " samples older than "
+ sdf.format(resultdate));
/*
* Log.i(TAG, "Sent samples:"); for (Sample k:
* map.values()){ Log.i(TAG, k.getTimestamp() +
* " " + k.getBatteryLevel()); }
*/
SortedSet<Long> uploaded = new TreeSet<Long>();
int i = 0;
for (Long s : map.keySet()) {
if (i < success)
uploaded.add(s);
i += 1;
}
int deleted = CaratSampleDB.getInstance(c)
.deleteSamples(uploaded);
// Log.d(TAG, "Deleted " + deleted + " samples.");
successSum += success;
} catch (Throwable th) {
// Any sort of malformed response, too short
// string, etc...
Log.w(TAG, "Failed to refresh reports: "
+ th
+ (tries < 1 ? "Trying again now"
: TRY_AGAIN), th);
tries++;
}
}
} else {
Log.w(TAG, "CommunicationManager is not ready yet."
+ TRY_AGAIN);
}
} else {
Log.w(TAG, "No samples to send." + TRY_AGAIN);
}
}
/* Click Tracking: Track sample sending. */
options.put("count", successSum+"");
ClickTracking.track(uuId, "sentsamples", options, c);
/* End Click Tracking: Track sample sending. */
}/* else if (networkStatus
.equals(SamplingLibrary.NETWORKSTATUS_CONNECTING)) {
Log.w(TAG, "Network status: " + networkStatus
+ ", trying again in 10s.");
connecting = true;
} else {
Log.w(TAG, "Network status: " + networkStatus + TRY_AGAIN);
connecting = false;
}
if (connecting) {
// wait for wifi to come up
try {
Thread.sleep(CaratApplication.COMMS_WIFI_WAIT);
} catch (InterruptedException e1) {
// ignore
}
connecting = false;
} else {
try {
Thread.sleep(CaratApplication.COMMS_INTERVAL);
} catch (InterruptedException e) {
// wait for wifi to come up
try {
Thread.sleep(CaratApplication.COMMS_WIFI_WAIT);
} catch (InterruptedException e1) {
// ignore
}
}
}*/
}
}
}