Search code examples
androidandroid-intentandroid-serviceandroid-locationandroid-geofence

onHandleWork never receives intent from pending intent Geofencing


I am working on a Geofencing application. The JobIntentService subclass that handles the GeofenceTransitions never receives the intent. I am receiving location updates at one minute interval then creating a new geofence list then adding the geofences based on a user's current location.

Here's my AndroidManifest.xml

 ........

 <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.WAKE_LOCK" />

<service
            android:name=".GeofenceTransitionsService"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE">

        </service>

        <receiver
            android:name=".GeofenceBroadcastReceiver"
            android:enabled="true"
            android:exported="true" />
.............

My GeofenceBroadcastReceiver.java

public class GeofenceBroadcastReceiver extends BroadcastReceiver {

    /**
     * Receives incoming intents.
     *
     * @param context the application context.
     * @param intent  sent by Location Services. This Intent is provided to Location
     *                Services (inside a PendingIntent) when addGeofences() is called.
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        // Enqueues a JobIntentService passing the context and intent as parameters
        GeofenceTransitionsService.enqueueWork(context, intent);
    }
}

My GeofenceTransitionsService.java that handles the triggered geofences

public class GeofenceTransitionsService extends JobIntentService {
   ..........

    /**
     * Convenience method for enqueuing work in to this service
     * Enqueue new work to be dispatched to onHandleWork
     */
    public static void enqueueWork(Context context, Intent intent) {
        Log.d(TAG, "Received intent: " + intent);
        enqueueWork(context, GeofenceTransitionsService.class, JOB_ID, intent);
    }

@Override
    protected void onHandleWork(Intent intent){
        // We have received work to do.  The system or framework is already
        // holding a wake lock for us at this point, so we can just go.
        Log.d(TAG, "Received intent: " + intent);
    }
}

Here's part of my code in PointOfInterestMapFragment.java that creates a geofencing request, creates the pending intent and adds the geofences

     /* Use the GeofencingRequest class and its nested GeofencingRequestBuilder
         * class to specify the geofences to monitor and to set how related geofence events are
         * triggered
         */
        private GeofencingRequest getGeofencingRequest(){
            GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
            //tell Location services that GEOFENCE_TRANSITION_DWELL should be triggered if the
            //device is already inside the geofence
            builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
            builder.addGeofences(mGeofenceList);
            return builder.build();
        }//end method getGeofencingRequest

        /*Pending intent that starts the IntentService*/
        private PendingIntent getGeofencePendingIntent(){
            Log.d(TAG, "getPendingIntent()");
            //Reuse the pending intent if we already have it
            if(mGeofencePendingIntent != null) {
                return mGeofencePendingIntent;
            }

            Intent intent = new Intent(getActivity(), GeofenceBroadcastReceiver.class);

            // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
            // calling addGeofences() and removeGeofences().
            mGeofencePendingIntent = PendingIntent.getBroadcast(getActivity()
                    , 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            return mGeofencePendingIntent;
        }//end method PendingIntent

        /*Add geofences*/
        @SuppressWarnings("MissingPermission")
        private void addGeofence(){
            if(checkPermissions()){
                mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
                        .addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {

                                Log.d(TAG, "Geofence added");
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.d(TAG, "Failed to add geofence: " + e.getMessage());
                            }
                        })
                        .addOnCompleteListener(new OnCompleteListener<Void>() {
                            @Override
                            public void onComplete(@NonNull Task<Void> task) {
                                //drawGeofence();

                            }
                        });


            }else{
                requestPermissions();
            }
        }//end method addGeofence

Here's the part of code in PointOfInterestMapFragment.java where I am receiving the location updates, populating the GeofenceList then adding geofences

/**
     * Creates a callback for receiving location events.
     */
    private void createLocationCallback() {
        mLocationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                super.onLocationResult(locationResult);

                mCurrentLocation = locationResult.getLastLocation();
                mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());

                //populateGeofenceList to reflect the new current location bounds
                populateGeofenceList();
                addGeofence();

            }
        };
    }

When the app executes, the I get the message in log cat from the line of code Log.d(TAG, "getPendingIntent()"); in getGeofencePendingIntent() but never get the message supposed to be displayed in onHandleWork() method


Solution

  • I had a similar 'problem'. The code is fine. In my case, I thought the code was not working because I had not understood properly how a geofence works. I thought to add the geofences, in your case a call to addGeofence() is the trigger, so I was waiting to see the notifications at that particular point in time. However a call to the method only adds the geofences for monitoring, then an intent is only delivered to the service when any of the filters are satisified (Geofence.GEOFENCE_TRANSITION_DWELL, Geofence.GEOFENCE_TRANSITION_EXIT OR Geofence.GEOFENCE_TRANSITION_ENTER) on an added geofence. You can read more from the documentation here

    So, you might receive a Geofence added message in your log cat, but that's what it literally means, the geofences have been added not triggered. Wait for some time after the geofence have been added and if any of the filters are satisfied for a geofence that was added, then the intent is sent. So the solution that worked for me was to wait and I received the intent and notifications after some period of time.

    If waiting does not work, you might want to extend the GEOFENCE_RADIUS, say to 3000 metres the check to see whether there is any change. Also, set the expiration duration to a higher value or to Geofence.NEVER_EXPIRE