Android LocationServices.GeofencingApi example usage
Asked Answered
D

1

14

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.

Deirdra answered 29/10, 2014 at 15:3 Comment(2)
did you tried at the source: d.android.com at training section acronym of article title is CaMGChristcross
The specific link is here developer.android.com/training/location/geofencing.html which uses the deprecated LocationClient class - seems they haven't updated the documentation yetDeirdra
P
27

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();
}
Panoply answered 14/12, 2014 at 15:0 Comment(7)
could you provide your callback too? I am new to android development, would be nice if you could share your code :) thxProffer
According to the docs, the method LocationServices.GeofencingApi.addGeofences(GoogleApiClient, List<Geofence>, PendingIntent); is deprecated, too. Use LocationServices.GeofencingApi.addGeofences(GoogleApiClient, GeofencingRequest, PendingIntent); instead, by creating a GeofencingRequest first: GeofencingRequest geofenceRequest = new GeofencingRequest.Builder().addGeofences(mGeofencesToAdd).build();Melioration
Nice, they changed the docs again.. last week it was not deprecatedPanoply
Why is GeofencingReceiver service exported?Rhizogenic
I can't explain this, I found this in an other documentation of the geofencing API. Maybe it is because the service is called by google play services framework.Panoply
But IntentService cannot run after it is finished! What if I want a service to run indefinitely in the background?Delouse
Why would you want this? The IntentService is called everytime Google Play Services acknowledges a geofence transitionPanoply

© 2022 - 2024 — McMap. All rights reserved.