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.Builder
class 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
GEOFENCE_TRANSITION_ENTER
: Triggers when a device enters a geofenceGEOFENCE_TRANSITION_EXIT
: Triggers when a device exits a geofence.INITIAL_TRIGGER_ENTER
: Tells Location services that should be triggered if the device is already inside the geofence.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.
I’ve tried this tutorial, but I have a problem. How to make Button enable when entering geofence and disable when outta geofence on activity ?…