Skip to content

Commit

Permalink
Move the check for setup_complete from the pluginInitialize to the sync
Browse files Browse the repository at this point in the history
Before this, we would check and reinitialize the state machine when the plugin
was initialized. But the plugin was only invoked when the user launched the
app. If the app was silently upgraded in the background, then basically all
tracking would be turned off until the user launched the app again.

This change moves the setup_complete initialize check from plugin_initialize
into the TripDiaryReceiver, where it will be called as part of
validateAndCleanupState by the sync adapter. This will ensure that tracking
starts at the next sync, and we get at most an hour of missing time.

It may be possible for us to listen to package manager updates and do something
smarter instead.
  • Loading branch information
shankari committed Mar 5, 2016
1 parent c217577 commit 5544afd
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 18 deletions.
36 changes: 18 additions & 18 deletions src/android/DataCollectionPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,35 @@
import edu.berkeley.eecs.emission.*;
import edu.berkeley.eecs.emission.BuildConfig;
import edu.berkeley.eecs.emission.cordova.tracker.location.LocationTrackingConfig;
import edu.berkeley.eecs.emission.cordova.tracker.location.TripDiaryStateMachineReceiver;
import edu.berkeley.eecs.emission.cordova.tracker.location.TripDiaryStateMachineService;
import edu.berkeley.eecs.emission.cordova.unifiedlogger.Log;

public class DataCollectionPlugin extends CordovaPlugin {
public static String TAG = "DataCollectionPlugin";
private static final String SETUP_COMPLETE_KEY = "setup_complete";

@Override
public void pluginInitialize() {
Activity myActivity = cordova.getActivity();
final Activity myActivity = cordova.getActivity();
int connectionResult = GooglePlayServicesUtil.isGooglePlayServicesAvailable(myActivity);
if (connectionResult == ConnectionResult.SUCCESS) {
Log.d(myActivity, TAG, "google play services available, initializing state machine");
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(myActivity);
System.out.println("All preferences are "+sp.getAll());
int currentCompleteVersion = sp.getInt(SETUP_COMPLETE_KEY, 0);
if(currentCompleteVersion != BuildConfig.VERSION_CODE) {
Log.d(myActivity, TAG, "Setup not complete, sending initialize");
myActivity.sendBroadcast(new Intent(myActivity.getString(R.string.transition_initialize)));
SharedPreferences.Editor prefsEditor = sp.edit();
// TODO: This is supposed to be set from the javascript as part of the onboarding process.
// However, it looks like it doesn't actually work - it looks like the app preferences plugin
// saves to local storage by default. Need to debug the app preferences plugin and maybe ask
// some questions of the maintainer. For now, setting it here for the first time should be fine.
prefsEditor.putInt(SETUP_COMPLETE_KEY, BuildConfig.VERSION_CODE);
prefsEditor.commit();
} else {
Log.d(myActivity, TAG, "Setup complete, skipping initialize");
// we want to run this in a separate thread, since it may take some time to get the
// current location and create a geofence
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
TripDiaryStateMachineReceiver.initOnUpgrade(myActivity);
}
});
} else {
Log.e(myActivity, TAG, "unable to connect to google play services");
}
}


@Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
public boolean execute(String action, JSONArray data, final CallbackContext callbackContext) throws JSONException {
if (action.equals("launchInit")) {
Log.d(cordova.getActivity(), TAG, "application launched, init is nop on android");
callbackContext.success();
Expand Down Expand Up @@ -83,9 +77,15 @@ public boolean execute(String action, JSONArray data, CallbackContext callbackCo
callbackContext.success(ctxt.getString(R.string.transition_exited_geofence));
return true;
} else if (action.equals("forceTripEnd")) {
// we want to run this in a background thread because it may wait to get the current location
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
Context ctxt = cordova.getActivity();
ctxt.sendBroadcast(new Intent(ctxt.getString(R.string.transition_stopped_moving)));
callbackContext.success(ctxt.getString(R.string.transition_stopped_moving));
}
});
return true;
} else if (action.equals("forceRemotePush")) {
Log.i(cordova.getActivity(), TAG, "on android, we don't handle remote pushes");
Expand Down
41 changes: 41 additions & 0 deletions src/android/location/TripDiaryStateMachineReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.HashSet;
import java.util.Set;

import edu.berkeley.eecs.emission.BuildConfig;
import edu.berkeley.eecs.emission.R;
import edu.berkeley.eecs.emission.cordova.unifiedlogger.Log;

Expand All @@ -28,6 +29,7 @@ public class TripDiaryStateMachineReceiver extends BroadcastReceiver {

public static Set<String> validTransitions = null;
private static String TAG = "TripDiaryStateMachineReceiver";
private static final String SETUP_COMPLETE_KEY = "setup_complete";

public TripDiaryStateMachineReceiver() {
// The automatically created receiver needs a default constructor
Expand Down Expand Up @@ -68,6 +70,45 @@ public void onReceive(Context context, Intent intent) {
context.startService(serviceStartIntent);
}

/*
* TODO: Need to find a place to put this.
*/
public static void validateAndCleanupState(Context ctxt) {
/*
* Check for being in geofence if in waiting_for_trip_state.
*/
if (TripDiaryStateMachineService.getState(ctxt).equals(ctxt.getString(R.string.state_start))) {
ctxt.sendBroadcast(new Intent(ctxt.getString(R.string.transition_initialize)));
} else if (TripDiaryStateMachineService.getState(ctxt).equals(
ctxt.getString(R.string.state_waiting_for_trip_start))) {
// We cannot check to see whether there is an existing geofence and whether we are in it.
// In particular, there is no method to get a geofence given an ID, and no method to get the status of a geofence
// even if we did have it. So this is not a check that we can do.
}
initOnUpgrade(ctxt);
}

public static void initOnUpgrade(Context ctxt) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(ctxt);
System.out.println("All preferences are "+sp.getAll());

int currentCompleteVersion = sp.getInt(SETUP_COMPLETE_KEY, 0);
if(currentCompleteVersion != BuildConfig.VERSION_CODE) {
Log.d(ctxt, TAG, "Setup not complete, sending initialize");
ctxt.sendBroadcast(new Intent(ctxt.getString(R.string.transition_initialize)));
SharedPreferences.Editor prefsEditor = sp.edit();
// TODO: This is supposed to be set from the javascript as part of the onboarding process.
// However, it looks like it doesn't actually work - it looks like the app preferences plugin
// saves to local storage by default. Need to debug the app preferences plugin and maybe ask
// some questions of the maintainer. For now, setting it here for the first time should be fine.
prefsEditor.putInt(SETUP_COMPLETE_KEY, BuildConfig.VERSION_CODE);
prefsEditor.commit();
} else {
Log.d(ctxt, TAG, "Setup complete, skipping initialize");
}
}


private Intent getStateMachineServiceIntent(Context context) {
if (LocationTrackingConfig.getConfig(context).isDutyCycling()) {
return new Intent(context, TripDiaryStateMachineService.class);
Expand Down

0 comments on commit 5544afd

Please sign in to comment.