Skip to content

Commit

Permalink
Merge pull request #197 from shankari/native_upgrade_2021
Browse files Browse the repository at this point in the history
Initial fix for the issue in which calling `getUnusedAppRestrictions.get` twice in the same thread hangs
  • Loading branch information
shankari authored Mar 23, 2022
2 parents 8dcd9b4 + 25e1142 commit 8f7a40a
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 6 deletions.
2 changes: 1 addition & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
id="cordova-plugin-em-datacollection"
version="1.7.0">
version="1.7.1">

<name>DataCollection</name>
<description>Background data collection FTW! This is the part that I really
Expand Down
32 changes: 28 additions & 4 deletions src/android/verification/SensorControlBackgroundChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
import org.json.JSONObject;

import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import edu.berkeley.eecs.emission.cordova.tracker.Constants;
import edu.berkeley.eecs.emission.cordova.tracker.ExplicitIntent;
Expand Down Expand Up @@ -90,8 +94,7 @@ public static void checkAppState(final Context ctxt) {
boolean[] allOtherChecks = new boolean[]{
SensorControlChecks.checkLocationPermissions(ctxt),
SensorControlChecks.checkMotionActivityPermissions(ctxt),
SensorControlChecks.checkNotificationsEnabled(ctxt),
SensorControlChecks.checkUnusedAppsUnrestricted(ctxt)
SensorControlChecks.checkNotificationsEnabled(ctxt)
};
boolean allOtherChecksPass = true;
for (boolean check: allOtherChecks) {
Expand All @@ -113,14 +116,14 @@ public static void checkAppState(final Context ctxt) {
}
else if (allOtherChecks[0]) {
Log.i(ctxt, TAG, "all checks = "+allOtherChecksPass+" but location permission status "+allOtherChecks[0]+" should be true "+
" so one of the non-location checks must be false: loc permission, motion permission, notification, unused apps" + Arrays.toString(allOtherChecks));
" so one of the non-location checks must be false: loc permission, motion permission, notification" + Arrays.toString(allOtherChecks));
Log.i(ctxt, TAG, "a non-local check failed, generating only user visible notification");
generateOpenAppSettingsNotification(ctxt);
}
else {
Log.i(ctxt, TAG, "location settings are valid, but location permission is not, generating tracking error and visible notification");
Log.i(ctxt, TAG, "curr status check results = " +
" loc permission, motion permission, notification, unused apps "+ Arrays.toString(allOtherChecks));
" loc permission, motion permission, notification "+ Arrays.toString(allOtherChecks));
ctxt.sendBroadcast(new ExplicitIntent(ctxt, R.string.transition_tracking_error));
generateOpenAppSettingsNotification(ctxt);
}
Expand All @@ -130,6 +133,27 @@ else if (allOtherChecks[0]) {
generateOpenAppSettingsNotification(ctxt);
}
});

/*
* AsyncTask is deprecated, so let's try to use the standard concurrent utilities here.
* Haven't used raw java concurrent utilities for 20 years (new Thread(...)) anyone?
* So this code snippet is based on
* https://stackoverflow.com/a/64969640/4040267
*
* Do we need to do anything in the UI thread. The `checkUnusedAppsUnrestricted`
* doesn't say anything about which thread to call it from. What about
* generateOpenAppSettingsNotification? Nothing in the NotificationManager indicates that
* it needs to run on the UI thread either.
*/
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

executor.schedule(() -> {
if (!SensorControlChecks.checkUnusedAppsUnrestricted(ctxt)) {
Log.i(ctxt, TAG, "all current settings and permissions are probably valid, but could be reset later");
Log.i(ctxt, TAG, "don't generate a tracking error right now, but let's ask the user to avoid the reset ");
generateOpenAppSettingsNotification(ctxt);
}
}, 1, TimeUnit.MINUTES);
}

public static void generateOpenAppSettingsNotification(Context ctxt) {
Expand Down
4 changes: 4 additions & 0 deletions src/android/verification/SensorControlChecks.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ public static boolean checkNotificationsUnpaused(final Context ctxt) {
public static boolean checkUnusedAppsUnrestricted(final Context ctxt) {
ListenableFuture<Integer> future = PackageManagerCompat.getUnusedAppRestrictionsStatus(ctxt);
try {
Log.i(ctxt, TAG, "About to call future.get to read the restriction status");
Integer appRestrictionStatus = future.get();
Log.i(ctxt, TAG, "Received "+appRestrictionStatus+" from future.get");
switch(appRestrictionStatus) {
case UnusedAppRestrictionsConstants.ERROR: return false;
case UnusedAppRestrictionsConstants.FEATURE_NOT_AVAILABLE: return true;
Expand All @@ -116,8 +118,10 @@ public static boolean checkUnusedAppsUnrestricted(final Context ctxt) {
return false;
}
} catch (ExecutionException | InterruptedException e) {
Log.e(ctxt, TAG, "Got exception from future.get" + e);
return false;
}
Log.e(ctxt, TAG, "Random final false");
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.provider.Settings;

Expand Down Expand Up @@ -552,12 +553,17 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
case SensorControlConstants.REMOVE_UNUSED_APP_RESTRICTIONS:
Log.d(mAct, TAG, requestCode + " is our code, handling callback");
Log.d(mAct, TAG, "Got unused app restrictions callback from launching app settings");
AsyncTask.execute(new Runnable() {
@Override
public void run() {
if (SensorControlChecks.checkUnusedAppsUnrestricted(cordova.getActivity())) {
SensorControlBackgroundChecker.restartFSMIfStartState(cordova.getActivity());
// SensorControlBackgroundChecker.restartFSMIfStartState(cordova.getActivity());
cordovaCallback.success();
} else {
cordovaCallback.error(cordova.getActivity().getString(R.string.unused_apps_restricted));
}
}
});
break;
default:
Log.d(cordova.getActivity(), TAG, "Got unsupported request code " + requestCode + " , ignoring...");
Expand Down

0 comments on commit 8f7a40a

Please sign in to comment.