e-mission / e-mission-transition-notify

Generate local notifications for various transitions of the finite state machine
BSD 3-Clause "New" or "Revised" License
0 stars 2 forks source link

android crashes reported in android play #12

Closed shankari closed 7 years ago

shankari commented 7 years ago

Mutiple crashes with minor differences in line number

Caused by: java.lang.RuntimeException: 

  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.getFirstLocation (TransitionNotificationReceiver.java:279)
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.getTripStartEndData (TransitionNotificationReceiver.java:238)
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.fireGenericTransition (TransitionNotificationReceiver.java:107)
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.onReceive (TransitionNotificationReceiver.java:88)
  at android.app.ActivityThread.handleReceiver (ActivityThread.java:3011)
Caused by: java.lang.RuntimeException: 
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.getFirstLocation (TransitionNotificationReceiver.java:279)
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.getTripStartEndData (TransitionNotificationReceiver.java:238)
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.fireGenericTransition (TransitionNotificationReceiver.java:107)
  at edu.berkeley.eecs.emission.cordova.transitionnotify.TransitionNotificationReceiver.onReceive (TransitionNotificationReceiver.java:88)
  at android.app.ActivityThread.handleReceiver (ActivityThread.java:2743)
shankari commented 7 years ago

Related code:

            if (startTransition.getTransition().equals(context.getString(R.string.transition_exited_geofence))) {
                UserCache.TimeQuery tq = new UserCache.TimeQuery("write_ts",
                        startTransition.getTs() - 5 * 60, //
                        startTransition.getTs() + 5 * 60);

                SimpleLocation[] firstLocArray = UserCacheFactory.getUserCache(context).getSensorDataForInterval(
                        R.string.key_usercache_filtered_location, tq, SimpleLocation.class);

                if (firstLocArray.length == 0) { // no locations found, switch to default
                    Log.d(context, TAG, "Found no locations before exiting geofence while ending trip!");
                    SimpleLocation firstLoc = getDefaultLocation(context);
                    if (firstLoc.getTs() < startTransition.getTs()) {
                        throw new RuntimeException("firstLocArray[0].ts "+firstLoc.getTs()
                            +" < startTransition.ts "+startTransition.getTs());
                    }
                    return firstLoc;

So it looks like we have no points within +/- 5 minutes of the geofence exit.

so we get the default location, and it is before the transition, so we throw the exception. How do we get the default location? We get the first point. So basically, there are no points within 5 minutes of the transition, but we haven't yet pushed any points, so the first point is before the transition.

    private SimpleLocation getDefaultLocation(Context context) {
        SimpleLocation[] firstLocArray = UserCacheFactory.getUserCache(context).getFirstSensorData(
                R.string.key_usercache_filtered_location,
                1,
                SimpleLocation.class);

        if (firstLocArray.length == 0) {
            Log.e(context, TAG, "Found no locations while ending trip!");
            throw new RuntimeException("Found no locations while ending trip!");
        }

        return firstLocArray[0];
    }
shankari commented 7 years ago

We want to stop throwing a RuntimeException in this case, but then we want to figure out what to do. We have two choices.

  1. return null. We do that for some earlier cases, e.g. where there are insufficient transitions, but it is within a DEBUG block.
        if (BuildConfig.DEBUG) {
            Log.d(context, TAG, "number of transitions = "+lastTwoTransitions.length);
            if (lastTwoTransitions.length == 0) {
                Log.e(context, TAG, "found no transitions at trip end, skipping notification");
                return null;
            }
            if (lastTwoTransitions.length > 2) {
                Log.e(context, TAG, "found too many transitions "
                        +lastTwoTransitions.length+ " at trip end, skipping notification");
                return null;
            }
        }

If we return null, the notification is skipped.

        SimpleLocation firstLoc = getFirstLocation(context, lastTwoTransitions);
        if(firstLoc == null) {
            Log.e(context, TAG, "error determining first location, skipping notification");
            return null;
        }

If we return null, then we will not show a transition in this case.

We can return the first point. We appear to do that for all kinds of other error cases. In that case, we will display a notification with the start timestamp from the first point.

            } else { // there were at least two transitions in the cache, but the second one
                // was not a geofence exit
                Log.d(context, TAG, "startTransition is "+startTransition.getTransition()
                        +" not "+context.getString(R.string.transition_exited_geofence));
                return getDefaultLocation(context);
            }
        } else {
            // Not enough transitions (have only one transition, presumably the stopping one)
            return getDefaultLocation(context);
        }
shankari commented 7 years ago

so the current behavior will not show any notifications because of the exception. Let's try to stick with that by returning null