Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Geofence eventually stop getting transition intents

I have an app that started with the Google's geofencing sample code. It works great for a few days, and I get all the transition intents as I anticipate. However, after a bit of time, something like 3 days, the app stops getting these intents, and I don't know why.

When I create my fences, I'm setting the expiration duration to Geofence.NEVER_EXPIRE

Here is my IntentService where I get the transition intents before they stop working:

public class ReceiveTransitionsIntentService extends IntentService {     @Override     protected void onHandleIntent(Intent intent) {          Intent broadcastIntent = new Intent();          broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);          // First check for errors         if (LocationClient.hasError(intent)) {                 ...handle errors         } else {              // Get the type of transition (entry or exit)             int transition = LocationClient.getGeofenceTransition(intent);              // Test that a valid transition was reported             if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER)                     || (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {                  // Post a notification                 NEVER GETS HERE             } else {                 ...log error             }         }     } } 

Here is pertinent part of the manifest:

<service             android:name="com.aol.android.geofence.ReceiveTransitionsIntentService"             android:exported="false" >         </service> 

In my GeofenceRequester class, it is almost identical to the sample code. Here are the pertinent parts:

// Get a PendingIntent that Location Services issues when a geofence transition occurs         mGeofencePendingIntent = createRequestPendingIntent();          // Send a request to add the current geofences         mLocationClient.addGeofences(mCurrentGeofences, mGeofencePendingIntent, this);  private PendingIntent createRequestPendingIntent() {              // Create an Intent pointing to the IntentService             Intent intent = new Intent(context, ReceiveTransitionsIntentService.class);              return PendingIntent.getService(                     context,                     0,                     intent,                     PendingIntent.FLAG_UPDATE_CURRENT);         }     } 

Can anyone see why this would stop working?

like image 565
b-ryce Avatar asked Oct 21 '13 22:10

b-ryce


People also ask

How do you stop Geofences?

To delete a Geofence, go to the list of Geofences, tap the Geofence you wish to delete, tap the Edit button, then the Delete button at the bottom of the screen. Once deleted, the Geofence can never be retrieved and any users currently using it will stop monitoring it.

What is the recommended radius for geofence?

For best results, the minimum radius of the geofence should be set between 100 - 150 meters.

What is geofence notification?

This app allows you to designate an area on the digital map and receive notifications whenever the target enters or leaves that specified area.


2 Answers

So after playing around with this a bit, it looks like the ReceiveTransitionsIntentService as defined in the sample code will stop getting the notifications when the app is not around. I think this is a big problem with the example code... Seems like that will trip folks like me up.

So I used a broadcast receiver instead, and so far it seems to be working from my tests.

Add this to the manifest:

<receiver android:name="com.aol.android.geofence.GeofenceReceiver"         android:exported="false">         <intent-filter >             <action android:name="com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"/>         </intent-filter>     </receiver> 

Then in the GeofenceRequester class you need to change the createRequestPendingIntent method so that it goes to your BroadcastReceiver instead of the ReceiveTransitionsIntentService

private PendingIntent createRequestPendingIntent() {          // If the PendingIntent already exists         if (null != mGeofencePendingIntent) {              // Return the existing intent             return mGeofencePendingIntent;          // If no PendingIntent exists         } else {              // Create an Intent pointing to the IntentService             Intent intent = new Intent("com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE"); //            Intent intent = new Intent(context, ReceiveTransitionsIntentService.class);             /*              * Return a PendingIntent to start the IntentService.              * Always create a PendingIntent sent to Location Services              * with FLAG_UPDATE_CURRENT, so that sending the PendingIntent              * again updates the original. Otherwise, Location Services              * can't match the PendingIntent to requests made with it.              */             return PendingIntent.getBroadcast(                     context,                     0,                     intent,                     PendingIntent.FLAG_UPDATE_CURRENT);         }     } 

Then I added the GeofenceReceiver class that looks something like this:

public class GeofenceReceiver extends BroadcastReceiver {     Context context;      Intent broadcastIntent = new Intent();      @Override     public void onReceive(Context context, Intent intent) {         this.context = context;          broadcastIntent.addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES);          if (LocationClient.hasError(intent)) {             handleError(intent);         } else {             handleEnterExit(intent);         }     }      private void handleError(Intent intent){         // Get the error code         int errorCode = LocationClient.getErrorCode(intent);          // Get the error message         String errorMessage = LocationServiceErrorMessages.getErrorString(                 context, errorCode);          // Log the error         Log.e(GeofenceUtils.APPTAG,                 context.getString(R.string.geofence_transition_error_detail,                         errorMessage));          // Set the action and error message for the broadcast intent         broadcastIntent                 .setAction(GeofenceUtils.ACTION_GEOFENCE_ERROR)                 .putExtra(GeofenceUtils.EXTRA_GEOFENCE_STATUS, errorMessage);          // Broadcast the error *locally* to other components in this app         LocalBroadcastManager.getInstance(context).sendBroadcast(                 broadcastIntent);     }       private void handleEnterExit(Intent intent) {         // Get the type of transition (entry or exit)         int transition = LocationClient.getGeofenceTransition(intent);          // Test that a valid transition was reported         if ((transition == Geofence.GEOFENCE_TRANSITION_ENTER)                 || (transition == Geofence.GEOFENCE_TRANSITION_EXIT)) {              // Post a notification             List<Geofence> geofences = LocationClient                     .getTriggeringGeofences(intent);             String[] geofenceIds = new String[geofences.size()];             String ids = TextUtils.join(GeofenceUtils.GEOFENCE_ID_DELIMITER,                     geofenceIds);             String transitionType = GeofenceUtils                     .getTransitionString(transition);              for (int index = 0; index < geofences.size(); index++) {                 Geofence geofence = geofences.get(index);                 ...do something with the geofence entry or exit. I'm saving them to a local sqlite db              }             // Create an Intent to broadcast to the app             broadcastIntent                     .setAction(GeofenceUtils.ACTION_GEOFENCE_TRANSITION)                     .addCategory(GeofenceUtils.CATEGORY_LOCATION_SERVICES)                     .putExtra(GeofenceUtils.EXTRA_GEOFENCE_ID, geofenceIds)                     .putExtra(GeofenceUtils.EXTRA_GEOFENCE_TRANSITION_TYPE,                             transitionType);              LocalBroadcastManager.getInstance(MyApplication.getContext())                     .sendBroadcast(broadcastIntent);              // Log the transition type and a message             Log.d(GeofenceUtils.APPTAG, transitionType + ": " + ids);             Log.d(GeofenceUtils.APPTAG,                     context.getString(R.string.geofence_transition_notification_text));              // In debug mode, log the result             Log.d(GeofenceUtils.APPTAG, "transition");              // An invalid transition was reported         } else {             // Always log as an error             Log.e(GeofenceUtils.APPTAG,                     context.getString(R.string.geofence_transition_invalid_type,                             transition));         }     }      /**      * Posts a notification in the notification bar when a transition is      * detected. If the user clicks the notification, control goes to the main      * Activity.      *       * @param transitionType      *            The type of transition that occurred.      *       */     private void sendNotification(String transitionType, String locationName) {          // Create an explicit content Intent that starts the main Activity         Intent notificationIntent = new Intent(context, MainActivity.class);          // Construct a task stack         TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);          // Adds the main Activity to the task stack as the parent         stackBuilder.addParentStack(MainActivity.class);          // Push the content Intent onto the stack         stackBuilder.addNextIntent(notificationIntent);          // Get a PendingIntent containing the entire back stack         PendingIntent notificationPendingIntent = stackBuilder                 .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);          // Get a notification builder that's compatible with platform versions         // >= 4         NotificationCompat.Builder builder = new NotificationCompat.Builder(                 context);          // Set the notification contents         builder.setSmallIcon(R.drawable.ic_notification)                 .setContentTitle(transitionType + ": " + locationName)                 .setContentText(                         context.getString(R.string.geofence_transition_notification_text))                 .setContentIntent(notificationPendingIntent);          // Get an instance of the Notification manager         NotificationManager mNotificationManager = (NotificationManager) context                 .getSystemService(Context.NOTIFICATION_SERVICE);          // Issue the notification         mNotificationManager.notify(0, builder.build());     } } 

Hopefully that helps someone else.

like image 163
b-ryce Avatar answered Oct 03 '22 12:10

b-ryce


Following can be the reasons why the App is not getting Pending Intents according to the official google documentation -
1.The device is rebooted.
2.The app is uninstalled and re-installed.
3.The app's data is cleared.
4.Google Play services data is cleared.
5.The app has received a GEOFENCE_NOT_AVAILABLE alert.(When Android Location Provider gets switched off)

You have to re-register the geofence after these events.

In my case Location provider gets switched off and also device gets rebooted that's why I was not getting the pending intents.

like image 31
Akash Bisariya Avatar answered Oct 03 '22 10:10

Akash Bisariya