Geofencing is a location-based service, that sends a notification to a smartphone who enter a defined geographic area.For example, the human resource department to monitor employees working in special locations or child location services can notify parents if a child leaves a designated area.


To use geofencing, your app must request ACCESS_FINE_LOCATION.To request this permission, add the following element as a child element of the <manifest>element in your app manifest

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

2. Google Play Service


Google Play services are used for access the location provider. Download and install the Google Play services component via the SDK Manager and add the library to your project. For details, see the guide to Setting Up Google Play Services

3. Connect to Google Play Services


Create an instance of Google API Client in activity’s onCreate() method. Use GoogleApiClient.Builderclass to add the LocationServices API, as the following code snippet shows.

private GoogleApiClient googleApiClient;
......
googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this).build();

Android 6.0+ (API level 23+), users grant permissions to apps while the app is running, not when they install the app.

 ActivityCompat.requestPermissions(MainActivity.this, new String[]
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 100);

Here is an example activity that implements the callback interfaces that adds  to the Google API Client

implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
...
@Override
public void onConnected(@Nullable Bundle bundle) {
       Log.d(TAG, "Google Api Client Connected");
       ...
}
@Override
public void onConnectionSuspended(int i) {
       Log.d(TAG, "Google Connection Suspended");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Log.e(TAG, "Connection Failed:" + connectionResult.getErrorMessage());
}

To connect, call connect() from the activity’s onStart() method. To disconnect, call disconnect() from the activity’s onStop() method.

@Override
protected void onStart() {
         super.onStart();
         googleApiClient.reconnect();
}
@Override
protected void onStop() {
        super.onStop();
        googleApiClient.disconnect();
}

4. Request Location Updates


Your app must connect to location services and make then a location request. Once a location request is in place you can start the regular updates by calling requestLocationUpdates().

private void startLocationMonitor() {
        Log.d(TAG, "start location monitor");
        LocationRequest locationRequest = LocationRequest.create()
                .setInterval(2000)
                .setFastestInterval(1000)
                .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        try {
            LocationServices.FusedLocationApi.requestLocationUpdates
            (googleApiClient, locationRequest, new LocationListener()
            {
                @Override
                public void onLocationChanged(Location location) {
                  ...
                 Log.d(TAG, "Location Change Lat Lng " +
                 location.getLatitude() + " " + location.getLongitude());
                }
            });
        } catch (SecurityException e) {
            Log.d(TAG, e.getMessage());
        }
    }

Do this in the onConnected() callback provided by Google API Client, which is called when the client is ready.

@Override
public void onConnected(@Nullable Bundle bundle) {
       ...
       startLocationMonitor();
}

Stop Location Updates

whether you want to stop the location updates when the activity is no longer in focus.

@Override
protected void onPause() {
    super.onPause();
    stopLocationUpdates();
}
protected void stopLocationUpdates() {
    LocationServices.FusedLocationApi.removeLocationUpdates(
            googleApiClient, this);
}

5.Create geofence objects


To create geofence object you need Latitude, Longitude, and Radius, Expiration time, Transition type, Geofence ID

public class Constants {
    public static final String GEOFENCE_ID_STAN_UNI = "STAN_UNI";
    public static final float GEOFENCE_RADIUS_IN_METERS = 100;
    /**
     * Map for storing information about stanford university in the Stanford.
     */
    public static final HashMap<String, LatLng> AREA_LANDMARKS = new HashMap<String, LatLng>();
    static {
        // stanford university.
        AREA_LANDMARKS.put(GEOFENCE_ID_STAN_UNI, new LatLng(37.427476, -122.170262));
    }
}

Your app needs to create and add geofences using the location API’s builder class for creating Geofence objects, and the convenience class for adding them.

@NonNull
private Geofence getGeofence() {
    LatLng latLng = Constants.AREA_LANDMARKS.get(Constants.GEOFENCE_ID_STAN_UNI);
    return new Geofence.Builder()
           .setRequestId(Constants.GEOFENCE_ID_STAN_UNI)
           .setExpirationDuration(Geofence.NEVER_EXPIRE)
           .setCircularRegion(latLng.latitude, latLng.longitude, Constants.GEOFENCE_RADIUS_IN_METERS)
           .setNotificationResponsiveness(1000)
           .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
           .build();
}

Specify geofences and initial triggers

The following snippet uses 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();
    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
    builder.addGeofences(getGeofence());
    return builder.build();
}

Geofence triggers

  1. GEOFENCE_TRANSITION_ENTER: Triggers when a device enters a geofence
  2. GEOFENCE_TRANSITION_EXIT: Triggers when a device exits a geofence.
  3. INITIAL_TRIGGER_ENTER: Tells Location services that should be triggered if the device is already inside the geofence.
  4. INITIAL_TRIGGER_DWELL: Triggers events only when the user stops for a defined duration within a geofence. This approach can help reduce “alert spam” resulting from large numbers notifications.

6. Handle Geofence Transitions


When Location Services detects that the user has entered or exited a geofence, it sends out the Intent contained in the PendingIntent you included in the request to add geofences. This Intent is received by a Service which obtains the geofencing event from the intent, determines the type of Geofence transition(s), and determines which of the defined geofences was triggered. It then sends a notification as the output. IntentService to listen for geofence transitions, add an element specifying the service name. This element must be a child of the <application> element:

<application
   android:allowBackup="true">
   ...
   <service android:name=".GeofenceRegistrationService"/>
<application/>

The following snippet shows how to define an IntentService that log when a geofence transition occurs. You can define notification. When the user clicks the notification, the app’s main activity appears

protected void onHandleIntent(@Nullable Intent intent) {
    GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    if (geofencingEvent.hasError()) {
       Log.d(TAG, "GeofencingEvent error " + geofencingEvent.getErrorCode());
    }else{
       int transaction = geofencingEvent.getGeofenceTransition();
       List<Geofence> geofences = geofencingEvent.getTriggeringGeofences();
       Geofence geofence = geofences.get(0);
       if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER && geofence.getRequestId().equals(Constants.GEOFENCE_ID_STAN_UNI)) {
          Log.d(TAG, "You are inside Stanford University");
       } else {
          Log.d(TAG, "You are outside Stanford University");
       }
    }
}

Define an Intent for geofence transitions

The Intent sent from Location Services can trigger various actions in your app.IntentService is a good way to handle the intent. An IntentService can post a notification, do long-running background work, send intents to other services, or send a broadcast intent. The following snippet shows how to define a PendingIntent that starts an IntentService:

private PendingIntent pendingIntent;
...
private PendingIntent getGeofencePendingIntent() {
    if (pendingIntent != null) {
       return pendingIntent;
     }
     Intent intent = new Intent(this, GeofenceRegistrationService.class);
     return PendingIntent.getService(this, 0, intent, PendingIntent.
            FLAG_UPDATE_CURRENT);
}

Add geofences

To add geofences, use the GeofencingApi.addGeofences() method. Provide the Google API client, the GeofencingRequest object, and the PendingIntent. The following snippet, which processes the results in onResult(),  implements ResultCallback:

private void startGeofencing() {
     Log.d(TAG, "Start geofencing monitoring call");
     pendingIntent = getGeofencePendingIntent();
     if (!googleApiClient.isConnected()) {
         Log.d(TAG, "Google API client not connected");
     } else {
         try {
             LocationServices.GeofencingApi.addGeofences(
             googleApiClient, getGeofencingRequest(),
             pendingIntent).setResultCallback(new ResultCallback<Status>() {
                    @Override
                    public void onResult(@NonNull Status status) {
                        if (status.isSuccess()) {
                            Log.d(TAG, "Successfully Geofencing Connected");
                        } else {
                            Log.d(TAG, "Failed to add Geofencing " + status.getStatus());
                        }
                    }
                });
            } catch (SecurityException e) {
                Log.d(TAG, e.getMessage());
            }
        }
    }

7. Stop Geofence Monitoring


The following snippet removes geofences by PendingIntent, stopping all further notification when the device enters or exits previously added geofences:

private void stopGeoFencing() {
      pendingIntent = getGeofencePendingIntent();
      LocationServices.GeofencingApi.removeGeofences
      (googleApiClient, pendingIntent)
                .setResultCallback(new ResultCallback<Status>() {
                    @Override
                    public void onResult(@NonNull Status status) {
                        if (status.isSuccess())
                            Log.d(TAG, "Stop geofencing");
                        else
                            Log.d(TAG, "Not stop geofencing");
                    }
           });
}

When geofences required  Re-register?

Registered geofences are kept in the com.google.process.location process owned by the com.google.android.gms package.

  • The device is rebooted.
  • The app is uninstalled and re-installed.
  • The app’s data is cleared.
  • Google Play services data is cleared.
  • The app has received a GEOFENCE_NOT_AVAILABLE alert. This typically happens after NLP (Android’s Network Location Provider) is disabled.

Download this project from GitHub.