Android LocationServices.GeofencingApi example usage

InquisitorJax picture InquisitorJax · Oct 29, 2014 · Viewed 8.7k times · Source

Does anyone know of an example of using the LocationServices.GeofencingApi? All the android geofencing examples I find are using the deprecated LocationClient class. From what I can see, the LocationServices class is the one to use, but there doesn't seem to be any working examples on how to use it.

The closest I've found is this post highlighting location update requests

UPDATE: The closest answer I've found is this git example project - but it still uses the deprecated LocationClient to get triggered fences.

Answer

L93 picture L93 · Dec 14, 2014

I just migrated my code to the new API. Here is a working example:

A working project on GitHub based on this answer: https://github.com/androidfu/GeofenceExample

This helper class registers the geofences using the API. I use a callback interface to communicate with the calling activity/fragment. You can build a callback that fits your needs.

public class GeofencingRegisterer implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
    private Context mContext;
    private GoogleApiClient mGoogleApiClient;
    private List<Geofence> geofencesToAdd;
    private PendingIntent mGeofencePendingIntent;

    private GeofencingRegistererCallbacks mCallback;

    public final String TAG = this.getClass().getName();

    public GeofencingRegisterer(Context context){
        mContext =context;
    }

    public void setGeofencingCallback(GeofencingRegistererCallbacks callback){
        mCallback = callback;
    }

    public void registerGeofences(List<Geofence> geofences){
        geofencesToAdd = geofences;

        mGoogleApiClient = new GoogleApiClient.Builder(mContext)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
        mGoogleApiClient.connect();
    }


    @Override
    public void onConnected(Bundle bundle) {
        if(mCallback != null){
            mCallback.onApiClientConnected();
        }

        mGeofencePendingIntent = createRequestPendingIntent();
        PendingResult<Status> result = LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, geofencesToAdd, mGeofencePendingIntent);
        result.setResultCallback(new ResultCallback<Status>() {
            @Override
            public void onResult(Status status) {
                if (status.isSuccess()) {
                    // Successfully registered
                    if(mCallback != null){
                        mCallback.onGeofencesRegisteredSuccessful();
                    }
                } else if (status.hasResolution()) {
                    // Google provides a way to fix the issue
                    /*
                    status.startResolutionForResult(
                            mContext,     // your current activity used to receive the result
                            RESULT_CODE); // the result code you'll look for in your
                    // onActivityResult method to retry registering
                    */
                } else {
                    // No recovery. Weep softly or inform the user.
                    Log.e(TAG, "Registering failed: " + status.getStatusMessage());
                }
            }
        });
    }

    @Override
    public void onConnectionSuspended(int i) {
        if(mCallback != null){
            mCallback.onApiClientSuspended();
        }

        Log.e(TAG, "onConnectionSuspended: " + i);
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        if(mCallback != null){
            mCallback.onApiClientConnectionFailed(connectionResult);
        }

        Log.e(TAG, "onConnectionFailed: " + connectionResult.getErrorCode());
    }



    /**
     * Returns the current PendingIntent to the caller.
     *
     * @return The PendingIntent used to create the current set of geofences
     */
    public PendingIntent getRequestPendingIntent() {
        return createRequestPendingIntent();
    }

    /**
     * Get a PendingIntent to send with the request to add Geofences. Location
     * Services issues the Intent inside this PendingIntent whenever a geofence
     * transition occurs for the current list of geofences.
     *
     * @return A PendingIntent for the IntentService that handles geofence
     * transitions.
     */
    private PendingIntent createRequestPendingIntent() {
        if (mGeofencePendingIntent != null) {
            return mGeofencePendingIntent;
        } else {
            Intent intent = new Intent(mContext, GeofencingReceiver.class);
            return PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        }
    }
}

This class is the base class for your geofence transition receiver.

public abstract class ReceiveGeofenceTransitionIntentService extends IntentService {

    /**
     * Sets an identifier for this class' background thread
     */
    public ReceiveGeofenceTransitionIntentService() {
        super("ReceiveGeofenceTransitionIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        GeofencingEvent event = GeofencingEvent.fromIntent(intent);
        if(event != null){

            if(event.hasError()){
                onError(event.getErrorCode());
            } else {
                int transition = event.getGeofenceTransition();
                if(transition == Geofence.GEOFENCE_TRANSITION_ENTER || transition == Geofence.GEOFENCE_TRANSITION_DWELL || transition == Geofence.GEOFENCE_TRANSITION_EXIT){
                    String[] geofenceIds = new String[event.getTriggeringGeofences().size()];
                    for (int index = 0; index < event.getTriggeringGeofences().size(); index++) {
                        geofenceIds[index] = event.getTriggeringGeofences().get(index).getRequestId();
                    }

                    if (transition == Geofence.GEOFENCE_TRANSITION_ENTER || transition == Geofence.GEOFENCE_TRANSITION_DWELL) {
                        onEnteredGeofences(geofenceIds);
                    } else if (transition == Geofence.GEOFENCE_TRANSITION_EXIT) {
                        onExitedGeofences(geofenceIds);
                    }
                }
            }

        }
    }

    protected abstract void onEnteredGeofences(String[] geofenceIds);

    protected abstract void onExitedGeofences(String[] geofenceIds);

    protected abstract void onError(int errorCode);
}

This class implements the abstract class and does all the handling of geofence transitions

public class GeofencingReceiver extends ReceiveGeofenceTransitionIntentService {

    @Override
    protected void onEnteredGeofences(String[] geofenceIds) {
        Log.d(GeofencingReceiver.class.getName(), "onEnter");
    }

    @Override
    protected void onExitedGeofences(String[] geofenceIds) {
        Log.d(GeofencingReceiver.class.getName(), "onExit");
    }

    @Override
    protected void onError(int errorCode) {
        Log.e(GeofencingReceiver.class.getName(), "Error: " + i);
    }
}

And in your manifest add:

<service
        android:name="**xxxxxxx**.GeofencingReceiver"
        android:exported="true"
        android:label="@string/app_name" >
</service>

Callback Interface

public interface GeofencingRegistererCallbacks {
    public void onApiClientConnected();
    public void onApiClientSuspended();
    public void onApiClientConnectionFailed(ConnectionResult connectionResult);

    public void onGeofencesRegisteredSuccessful();
}