diff --git a/docs/html/images/training/geofence.png b/docs/html/images/training/geofence.png new file mode 100644 index 0000000000000..2d5d3aa0b1763 Binary files /dev/null and b/docs/html/images/training/geofence.png differ diff --git a/docs/html/images/training/geofence@2x.png b/docs/html/images/training/geofence@2x.png new file mode 100644 index 0000000000000..2f83105a29d79 Binary files /dev/null and b/docs/html/images/training/geofence@2x.png differ diff --git a/docs/html/training/location/geofencing.jd b/docs/html/training/location/geofencing.jd index 748b6ece8b87a..59fc4c665a53f 100644 --- a/docs/html/training/location/geofencing.jd +++ b/docs/html/training/location/geofencing.jd @@ -9,9 +9,11 @@ trainingnavtop=true

This lesson teaches you to

    -
  1. Request Geofence Monitoring
  2. +
  3. Set up for Geofence Monitoring
  4. +
  5. Create and Add Geofences
  6. Handle Geofence Transitions
  7. Stop Geofence Monitoring
  8. +

You should also read

@@ -23,577 +25,148 @@ trainingnavtop=true

Try it out

-
- Download the sample -

GeofenceDetection.zip

-
+

- Geofencing combines awareness of the user's current location with awareness of nearby - features, defined as the user's proximity to locations that may be of interest. To mark a + Geofencing combines awareness of the user's current location with awareness of the user's + proximity to locations that may be of interest. To mark a location of interest, you specify its latitude and longitude. To adjust the proximity for the - location, you add a radius. The latitude, longitude, and radius define a geofence. - You can have multiple active geofences at one time. + location, you add a radius. The latitude, longitude, and radius define a geofence, creating a + circular area, or fence, around the location of interest.

- Location Services treats a geofences as an area rather than as a points and proximity. This - allows it to detect when the user enters or exits a geofence. For each geofence, you can ask - Location Services to send you entrance events or exit events or both. You can also limit the - duration of a geofence by specifying an expiration duration in milliseconds. After the geofence - expires, Location Services automatically removes it. + You can have multiple active geofences, with a limit of 100 per device user. For each geofence, + you can ask Location Services to send you entrance and exit events, or you can specify a + duration within the geofence area to wait, or dwell, before triggering an event. You + can limit the duration of any geofence by specifying an expiration duration in milliseconds. + After the geofence expires, Location Services automatically removes it.

- -

Request Geofence Monitoring

+ + +

+ This lesson shows you how to add and remove geofences, and then listen for geofence transitions + using an {@link android.app.IntentService}.

+ +

Set up for Geofence Monitoring

The first step in requesting geofence monitoring is to request the necessary permission. To use geofencing, your app must request {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. To request this permission, add the following element as a child element of the <manifest> - element: + element in your app manifest:

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

Check for Google Play Services

-

- Location Services is part of the Google Play services APK. Since it's hard to anticipate the - state of the user's device, you should always check that the APK is installed before you attempt - to connect to Location Services. To check that the APK is installed, call -GooglePlayServicesUtil.isGooglePlayServicesAvailable(), - which returns one of the - integer result codes listed in the API reference documentation. If you encounter an error, - call -GooglePlayServicesUtil.getErrorDialog() - to retrieve localized dialog that prompts users to take the correct action, then display - the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the - user to correct the problem, in which case Google Play services may send a result back to your - activity. To handle this result, override the method - {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} -

-

- Note: To make your app compatible with - platform version 1.6 and later, the activity that displays the - {@link android.support.v4.app.DialogFragment} must subclass - {@link android.support.v4.app.FragmentActivity} instead of {@link android.app.Activity}. Using - {@link android.support.v4.app.FragmentActivity} also allows you to call - {@link android.support.v4.app.FragmentActivity#getSupportFragmentManager - getSupportFragmentManager()} to display the {@link android.support.v4.app.DialogFragment}. -

- Since you usually need to check for Google Play services in more than one place in your code, - define a method that encapsulates the check, then call the method before each connection - attempt. The following snippet contains all of the code required to check for Google - Play services: + If you want to use an {@link android.app.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=".GeofenceTransitionsIntentService"/>
+<application/>
+
+ +

To access the location APIs, you need to create an instance of the + Google Play services API client. To learn how to connect your client, see + Connect + to Google Play Services.

+ +

Create and Add Geofences

+ +

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. Also, to handle the + intents sent from Location Services when geofence transitions occur, you can define a + {@link android.app.PendingIntent} as shown in this section. +

+ +

Create geofence objects

+ +

+ First, use Geofence.Builder to create a geofence, setting the desired radius, duration, and + transition types for the geofence. For example, to populate a list object named + {@code mGeofenceList}: +

+ +
+mGeofenceList.add(new Geofence.Builder()
+    // Set the request ID of the geofence. This is a string to identify this
+    // geofence.
+    .setRequestId(entry.getKey())
+
+    .setCircularRegion(
+            entry.getValue().latitude,
+            entry.getValue().longitude,
+            Constants.GEOFENCE_RADIUS_IN_METERS
+    )
+    .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
+    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
+            Geofence.GEOFENCE_TRANSITION_EXIT)
+    .build());
+
+ +

This example pulls data from a constants file. In actual practice, apps might + dynamically create geofences based on the user's location.

+ +

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:

-public class MainActivity extends FragmentActivity {
-    ...
-    // Global constants
-    /*
-     * Define a request code to send to Google Play services
-     * This code is returned in Activity.onActivityResult
-     */
-    private final static int
-            CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
-    ...
-    // Define a DialogFragment that displays the error dialog
-    public static class ErrorDialogFragment extends DialogFragment {
-        // Global field to contain the error dialog
-        private Dialog mDialog;
-        ...
-        // Default constructor. Sets the dialog field to null
-        public ErrorDialogFragment() {
-            super();
-            mDialog = null;
-        }
-        ...
-        // Set the dialog to display
-        public void setDialog(Dialog dialog) {
-            mDialog = dialog;
-        }
-        ...
-        // Return a Dialog to the DialogFragment.
-        @Override
-        public Dialog onCreateDialog(Bundle savedInstanceState) {
-            return mDialog;
-        }
-        ...
-    }
-    ...
-    /*
-     * Handle results returned to the FragmentActivity
-     * by Google Play services
-     */
-     @Override
-    protected void onActivityResult(
-            int requestCode, int resultCode, Intent data) {
-        // Decide what to do based on the original request code
-        switch (requestCode) {
-            ...
-            case CONNECTION_FAILURE_RESOLUTION_REQUEST :
-            /*
-             * If the result code is Activity.RESULT_OK, try
-             * to connect again
-             */
-                switch (resultCode) {
-                    ...
-                    case Activity.RESULT_OK :
-                    /*
-                     * Try the request again
-                     */
-                    ...
-                    break;
-                }
-            ...
-        }
-        ...
-    }
-    ...
-    private boolean servicesConnected() {
-        // Check that Google Play services is available
-        int resultCode =
-                GooglePlayServicesUtil.
-                        isGooglePlayServicesAvailable(this);
-        // If Google Play services is available
-        if (ConnectionResult.SUCCESS == resultCode) {
-            // In debug mode, log the status
-            Log.d("Geofence Detection",
-                    "Google Play services is available.");
-            // Continue
-            return true;
-        // Google Play services was not available for some reason
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    this,
-                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
-
-            // If Google Play services can provide an error dialog
-            if (errorDialog != null) {
-                // Create a new DialogFragment for the error dialog
-                ErrorDialogFragment errorFragment =
-                        new ErrorDialogFragment();
-                // Set the dialog in the DialogFragment
-                errorFragment.setDialog(errorDialog);
-                // Show the error dialog in the DialogFragment
-                errorFragment.show(
-                        getSupportFragmentManager(),
-                        "Geofence Detection");
-            }
-        }
-    }
-    ...
+private GeofencingRequest getGeofencingRequest() {
+    GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
+    builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
+    builder.addGeofences(mGeofenceList);
+    return builder.build();
 }
 
-

- Snippets in the following sections call this method to verify that Google Play services is - available. -

-

- To use geofencing, start by defining the geofences you want to monitor. Although you usually - store geofence data in a local database or download it from the network, you need to send - a geofence to Location Services as an instance of -Geofence, - which you create with -Geofence.Builder. - Each -Geofence - object contains the following information: -

-
-
Latitude, longitude, and radius
-
- Define a circular area for the geofence. Use the latitude and longitude to mark a location - of interest, and then use the radius to adjust how close the user needs to approach the - location before the geofence is detected. The larger the radius, the more likely the - user will trigger a geofence transition alert by approaching the geofence. For example, - providing a large radius for a geofencing app that turns on lights in the user's house as - the user returns home might cause the lights to go on even if the user is simply passing by. -
-
Expiration time
-
- How long the geofence should remain active. Once the expiration time is reached, Location - Services deletes the geofence. Most of the time, you should specify an expiration time, but - you may want to keep permanent geofences for the user's home or place of work. -
-
Transition type
-
- Location Services can detect when the user steps within the radius of the geofence ("entry") - and when the user steps outside the radius of the geofence ("exit"), or both. -
-
Geofence ID
-
- A string that is stored with the geofence. You should make this unique, so that you can - use it to remove a geofence from Location Services tracking. -
-
-

Define geofence storage

-

- A geofencing app needs to read and write geofence data to persistent storage. You shouldn't use -Geofence - objects to do this; instead, use storage techniques such as databases that can store groups of - related data. -

-

- As an example of storing geofence data, the following snippet defines two classes that use - the app's {@link android.content.SharedPreferences} instance for persistent storage. The class - {@code SimpleGeofence}, analogous to a database record, stores the - data for a single -Geofence - object in a "flattened" form. The class {@code SimpleGeofenceStore}, analogous to a database, - reads and writes {@code SimpleGeofence} data to the - {@link android.content.SharedPreferences} instance. -

-
-public class MainActivity extends FragmentActivity {
-    ...
-    /**
-     * A single Geofence object, defined by its center and radius.
-     */
-    public class SimpleGeofence {
-            // Instance variables
-            private final String mId;
-            private final double mLatitude;
-            private final double mLongitude;
-            private final float mRadius;
-            private long mExpirationDuration;
-            private int mTransitionType;
 
-        /**
-         * @param geofenceId The Geofence's request ID
-         * @param latitude Latitude of the Geofence's center.
-         * @param longitude Longitude of the Geofence's center.
-         * @param radius Radius of the geofence circle.
-         * @param expiration Geofence expiration duration
-         * @param transition Type of Geofence transition.
-         */
-        public SimpleGeofence(
-                String geofenceId,
-                double latitude,
-                double longitude,
-                float radius,
-                long expiration,
-                int transition) {
-            // Set the instance fields from the constructor
-            this.mId = geofenceId;
-            this.mLatitude = latitude;
-            this.mLongitude = longitude;
-            this.mRadius = radius;
-            this.mExpirationDuration = expiration;
-            this.mTransitionType = transition;
-        }
-        // Instance field getters
-        public String getId() {
-            return mId;
-        }
-        public double getLatitude() {
-            return mLatitude;
-        }
-        public double getLongitude() {
-            return mLongitude;
-        }
-        public float getRadius() {
-            return mRadius;
-        }
-        public long getExpirationDuration() {
-            return mExpirationDuration;
-        }
-        public int getTransitionType() {
-            return mTransitionType;
-        }
-        /**
-         * Creates a Location Services Geofence object from a
-         * SimpleGeofence.
-         *
-         * @return A Geofence object
-         */
-        public Geofence toGeofence() {
-            // Build a new Geofence object
-            return new Geofence.Builder()
-                    .setRequestId(getId())
-                    .setTransitionTypes(mTransitionType)
-                    .setCircularRegion(
-                            getLatitude(), getLongitude(), getRadius())
-                    .setExpirationDuration(mExpirationDuration)
-                    .build();
-        }
-    }
-    ...
-    /**
-     * Storage for geofence values, implemented in SharedPreferences.
-     */
-    public class SimpleGeofenceStore {
-        // Keys for flattened geofences stored in SharedPreferences
-        public static final String KEY_LATITUDE =
-                "com.example.android.geofence.KEY_LATITUDE";
-        public static final String KEY_LONGITUDE =
-                "com.example.android.geofence.KEY_LONGITUDE";
-        public static final String KEY_RADIUS =
-                "com.example.android.geofence.KEY_RADIUS";
-        public static final String KEY_EXPIRATION_DURATION =
-                "com.example.android.geofence.KEY_EXPIRATION_DURATION";
-        public static final String KEY_TRANSITION_TYPE =
-                "com.example.android.geofence.KEY_TRANSITION_TYPE";
-        // The prefix for flattened geofence keys
-        public static final String KEY_PREFIX =
-                "com.example.android.geofence.KEY";
-        /*
-         * Invalid values, used to test geofence storage when
-         * retrieving geofences
-         */
-        public static final long INVALID_LONG_VALUE = -999l;
-        public static final float INVALID_FLOAT_VALUE = -999.0f;
-        public static final int INVALID_INT_VALUE = -999;
-        // The SharedPreferences object in which geofences are stored
-        private final SharedPreferences mPrefs;
-        // The name of the SharedPreferences
-        private static final String SHARED_PREFERENCES =
-                "SharedPreferences";
-        // Create the SharedPreferences storage with private access only
-        public SimpleGeofenceStore(Context context) {
-            mPrefs =
-                    context.getSharedPreferences(
-                            SHARED_PREFERENCES,
-                            Context.MODE_PRIVATE);
-        }
-        /**
-         * Returns a stored geofence by its id, or returns {@code null}
-         * if it's not found.
-         *
-         * @param id The ID of a stored geofence
-         * @return A geofence defined by its center and radius. See
-         */
-        public SimpleGeofence getGeofence(String id) {
-            /*
-             * Get the latitude for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            double lat = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_LATITUDE),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the longitude for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            double lng = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_LONGITUDE),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the radius for the geofence identified by id, or
-             * INVALID_FLOAT_VALUE if it doesn't exist
-             */
-            float radius = mPrefs.getFloat(
-                    getGeofenceFieldKey(id, KEY_RADIUS),
-                    INVALID_FLOAT_VALUE);
-            /*
-             * Get the expiration duration for the geofence identified
-             * by id, or INVALID_LONG_VALUE if it doesn't exist
-             */
-            long expirationDuration = mPrefs.getLong(
-                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),
-                    INVALID_LONG_VALUE);
-            /*
-             * Get the transition type for the geofence identified by
-             * id, or INVALID_INT_VALUE if it doesn't exist
-             */
-            int transitionType = mPrefs.getInt(
-                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),
-                    INVALID_INT_VALUE);
-            // If none of the values is incorrect, return the object
-            if (
-                lat != GeofenceUtils.INVALID_FLOAT_VALUE &&
-                lng != GeofenceUtils.INVALID_FLOAT_VALUE &&
-                radius != GeofenceUtils.INVALID_FLOAT_VALUE &&
-                expirationDuration !=
-                        GeofenceUtils.INVALID_LONG_VALUE &&
-                transitionType != GeofenceUtils.INVALID_INT_VALUE) {
-
-                // Return a true Geofence object
-                return new SimpleGeofence(
-                        id, lat, lng, radius, expirationDuration,
-                        transitionType);
-            // Otherwise, return null.
-            } else {
-                return null;
-            }
-        }
-        /**
-         * Save a geofence.
-         * @param geofence The SimpleGeofence containing the
-         * values you want to save in SharedPreferences
-         */
-        public void setGeofence(String id, SimpleGeofence geofence) {
-            /*
-             * Get a SharedPreferences editor instance. Among other
-             * things, SharedPreferences ensures that updates are atomic
-             * and non-concurrent
-             */
-            Editor editor = mPrefs.edit();
-            // Write the Geofence values to SharedPreferences
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_LATITUDE),
-                    (float) geofence.getLatitude());
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_LONGITUDE),
-                    (float) geofence.getLongitude());
-            editor.putFloat(
-                    getGeofenceFieldKey(id, KEY_RADIUS),
-                    geofence.getRadius());
-            editor.putLong(
-                    getGeofenceFieldKey(id, KEY_EXPIRATION_DURATION),
-                    geofence.getExpirationDuration());
-            editor.putInt(
-                    getGeofenceFieldKey(id, KEY_TRANSITION_TYPE),
-                    geofence.getTransitionType());
-            // Commit the changes
-            editor.commit();
-        }
-        public void clearGeofence(String id) {
-            /*
-             * Remove a flattened geofence object from storage by
-             * removing all of its keys
-             */
-            Editor editor = mPrefs.edit();
-            editor.remove(getGeofenceFieldKey(id, KEY_LATITUDE));
-            editor.remove(getGeofenceFieldKey(id, KEY_LONGITUDE));
-            editor.remove(getGeofenceFieldKey(id, KEY_RADIUS));
-            editor.remove(getGeofenceFieldKey(id,
-                    KEY_EXPIRATION_DURATION));
-            editor.remove(getGeofenceFieldKey(id, KEY_TRANSITION_TYPE));
-            editor.commit();
-        }
-        /**
-         * Given a Geofence object's ID and the name of a field
-         * (for example, KEY_LATITUDE), return the key name of the
-         * object's values in SharedPreferences.
-         *
-         * @param id The ID of a Geofence object
-         * @param fieldName The field represented by the key
-         * @return The full key name of a value in SharedPreferences
-         */
-        private String getGeofenceFieldKey(String id,
-                String fieldName) {
-            return KEY_PREFIX + "_" + id + "_" + fieldName;
-        }
-    }
-    ...
-}
-
-

Create Geofence objects

- The following snippet uses the {@code SimpleGeofence} and {@code SimpleGeofenceStore} classes - gets geofence data from the UI, stores it in {@code SimpleGeofence} objects, stores these - objects in a {@code SimpleGeofenceStore} object, and then creates -Geofence - objects: + This example shows the use of two geofence triggers. The + GEOFENCE_TRANSITION_ENTER + transition triggers when a device enters a geofence, and the + GEOFENCE_TRANSITION_EXIT + transition triggers when a device exits a geofence. Specifying + + INITIAL_TRIGGER_ENTER tells Location services that + + GEOFENCE_TRANSITION_ENTER + should be triggered if the the device is already inside the geofence.

-
-public class MainActivity extends FragmentActivity {
-    ...
-    /*
-     * Use to set an expiration time for a geofence. After this amount
-     * of time Location Services will stop tracking the geofence.
-     */
-    private static final long SECONDS_PER_HOUR = 60;
-    private static final long MILLISECONDS_PER_SECOND = 1000;
-    private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
-    private static final long GEOFENCE_EXPIRATION_TIME =
-            GEOFENCE_EXPIRATION_IN_HOURS *
-            SECONDS_PER_HOUR *
-            MILLISECONDS_PER_SECOND;
-    ...
-    /*
-     * Handles to UI views containing geofence data
-     */
-    // Handle to geofence 1 latitude in the UI
-    private EditText mLatitude1;
-    // Handle to geofence 1 longitude in the UI
-    private EditText mLongitude1;
-    // Handle to geofence 1 radius in the UI
-    private EditText mRadius1;
-    // Handle to geofence 2 latitude in the UI
-    private EditText mLatitude2;
-    // Handle to geofence 2 longitude in the UI
-    private EditText mLongitude2;
-    // Handle to geofence 2 radius in the UI
-    private EditText mRadius2;
-    /*
-     * Internal geofence objects for geofence 1 and 2
-     */
-    private SimpleGeofence mUIGeofence1;
-    private SimpleGeofence mUIGeofence2;
-    ...
-    // Internal List of Geofence objects
-    List<Geofence> mGeofenceList;
-    // Persistent storage for geofences
-    private SimpleGeofenceStore mGeofenceStorage;
-    ...
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        ...
-        // Instantiate a new geofence storage area
-        mGeofenceStorage = new SimpleGeofenceStore(this);
 
-        // Instantiate the current List of geofences
-        mCurrentGeofences = new ArrayList<Geofence>();
-    }
-    ...
-    /**
-     * Get the geofence parameters for each geofence from the UI
-     * and add them to a List.
-     */
-    public void createGeofences() {
-        /*
-         * Create an internal object to store the data. Set its
-         * ID to "1". This is a "flattened" object that contains
-         * a set of strings
-         */
-        mUIGeofence1 = new SimpleGeofence(
-                "1",
-                Double.valueOf(mLatitude1.getText().toString()),
-                Double.valueOf(mLongitude1.getText().toString()),
-                Float.valueOf(mRadius1.getText().toString()),
-                GEOFENCE_EXPIRATION_TIME,
-                // This geofence records only entry transitions
-                Geofence.GEOFENCE_TRANSITION_ENTER);
-        // Store this flat version
-        mGeofenceStorage.setGeofence("1", mUIGeofence1);
-        // Create another internal object. Set its ID to "2"
-        mUIGeofence2 = new SimpleGeofence(
-                "2",
-                Double.valueOf(mLatitude2.getText().toString()),
-                Double.valueOf(mLongitude2.getText().toString()),
-                Float.valueOf(mRadius2.getText().toString()),
-                GEOFENCE_EXPIRATION_TIME,
-                // This geofence records both entry and exit transitions
-                Geofence.GEOFENCE_TRANSITION_ENTER |
-                Geofence.GEOFENCE_TRANSITION_EXIT);
-        // Store this flat version
-        mGeofenceStorage.setGeofence(2, mUIGeofence2);
-        mGeofenceList.add(mUIGeofence1.toGeofence());
-        mGeofenceList.add(mUIGeofence2.toGeofence());
-    }
-    ...
-}
-
-

- In addition to the {@link java.util.List} of -Geofence - objects you want to monitor, you need to provide Location Services with the - {@link android.content.Intent} that it sends to your app when it detects geofence - transitions. -

Define a Intent for geofence transitions

+

In many cases, it may be preferable to use instead + INITIAL_TRIGGER_DWELL, + which 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 when a + device briefly enters and exits geofences. Another strategy for getting best results from your + geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy + of typical WiFi networks, and also helps reduce device power consumption. +

+ +

Define an Intent for geofence transitions

The {@link android.content.Intent} sent from Location Services can trigger various actions in your app, but you should not have it start an activity or fragment, because components @@ -601,807 +174,133 @@ public class MainActivity extends FragmentActivity { {@link android.app.IntentService} is a good way to handle the intent. An {@link android.app.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 - how to define a {@link android.app.PendingIntent} that starts an - {@link android.app.IntentService}: + to define a {@link android.app.PendingIntent} that starts an {@link android.app.IntentService}:

 public class MainActivity extends FragmentActivity {
     ...
-    /*
-     * Create a PendingIntent that triggers an IntentService in your
-     * app when a geofence transition occurs.
-     */
-    private PendingIntent getTransitionPendingIntent() {
-        // Create an explicit Intent
-        Intent intent = new Intent(this,
-                ReceiveTransitionsIntentService.class);
-        /*
-         * Return the PendingIntent
-         */
-        return PendingIntent.getService(
-                this,
-                0,
-                intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-    }
-    ...
-}
-
-

- Now you have all the code you need to send a request to monitor geofences to Location - Services. -

- -

Send the monitoring request

-

- Sending the monitoring request requires two asynchronous operations. The first operation gets a - location client for the request, and the second makes the request using the client. In both - cases, Location Services invokes a callback method when it finishes the operation. The best way - to handle these operations is to chain together the method calls. The following snippets - demonstrate how to set up an activity, define the methods, and call them in the proper order. -

-

- First, modify the activity's class definition to implement the necessary callback interfaces. - Add the following interfaces: -

-
-
-ConnectionCallbacks -
-
- Specifies methods that Location Services calls when a location client is connected or - disconnected. -
-
-OnConnectionFailedListener -
-
- Specifies a method that Location Services calls if an error occurs while attempting to - connect the location client. -
-
-OnAddGeofencesResultListener -
-
- Specifies a method that Location Services calls once it has added the geofences. -
-
-

- For example: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-}
-
-

Start the request process

-

- Next, define a method that starts the request process by connecting to Location Services. - Mark this as a request to add a geofence by setting a global variable. This allows you to - use the callback -ConnectionCallbacks.onConnected() - to add geofences and to remove them, as described in succeeding sections. -

-

-

- To guard against race conditions that might arise if your app tries to start another request - before the first one finishes, define a boolean flag that tracks the state of the current - request: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Holds the location client
-    private LocationClient mLocationClient;
-    // Stores the PendingIntent used to request geofence monitoring
-    private PendingIntent mGeofenceRequestIntent;
-    // Defines the allowable request types.
-    public enum REQUEST_TYPE = {ADD}
-    private REQUEST_TYPE mRequestType;
-    // Flag that indicates if a request is underway.
-    private boolean mInProgress;
-    ...
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        ...
-        // Start with the request flag set to false
-        mInProgress = false;
-        ...
-    }
-    ...
-    /**
-     * Start a request for geofence monitoring by calling
-     * LocationClient.connect().
-     */
-    public void addGeofences() {
-        // Start a request to add geofences
-        mRequestType = ADD;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the proper request
-         * can be restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this)
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
+    private PendingIntent getGeofencePendingIntent() {
+        // Reuse the PendingIntent if we already have it.
+        if (mGeofencePendingIntent != null) {
+            return mGeofencePendingIntent;
         }
+        Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
+        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
+        // calling addGeofences() and removeGeofences().
+        return PendingIntent.getService(this, 0, intent, PendingIntent.
+                FLAG_UPDATE_CURRENT);
     }
-    ...
-}
 
-

Send a request to add the geofences

+ +

Add geofences

+

- In your implementation of -ConnectionCallbacks.onConnected(), - call -LocationClient.addGeofences(). - Notice that if the connection fails, -onConnected() - isn't called, and the request stops. + To add geofences, use the {@code GeoencingApi.addGeofences()} method. + Provide the Google API client, the + GeofencingRequest object, and the {@link android.app.PendingIntent}. + The following snippet, which processes the results in + onResult(), assumes that the main activity implements + ResultCallback:

-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
+public class MainActivity extends FragmentActivity {
     ...
-    /*
-     * Provide the implementation of ConnectionCallbacks.onConnected()
-     * Once the connection is available, send a request to add the
-     * Geofences
-     */
-    @Override
-    private void onConnected(Bundle dataBundle) {
-        ...
-        switch (mRequestType) {
-            case ADD :
-                // Get the PendingIntent for the request
-                mTransitionPendingIntent =
-                        getTransitionPendingIntent();
-                // Send a request to add the current geofences
-                mLocationClient.addGeofences(
-                        mCurrentGeofences, pendingIntent, this);
-            ...
-        }
-    }
-    ...
-}
+    LocationServices.GeofencingApi.addGeofences(
+                mGoogleApiClient,
+                getGeofencingRequest(),
+                getGeofencePendingIntent()
+        ).setResultCallback(this);
 
-

- Notice that -addGeofences() - returns immediately, but the status of the request is indeterminate until Location Services - calls -onAddGeofencesResult() - Once this method is called, you can determine if the request was successful or not. -

-

Check the result returned by Location Services

-

- When Location Services invokes your implementation of the callback method -onAddGeofencesResult(), - indicating that the request is complete, examine the incoming status code. If the request - was successful, the geofences you requested are active. If the request was unsuccessful, - the geofences aren't active, and you need to re-try the request or report an error. For example: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-        ...
-    /*
-     * Provide the implementation of
-     * OnAddGeofencesResultListener.onAddGeofencesResult.
-     * Handle the result of adding the geofences
-     *
-     */
-    @Override
-    public void onAddGeofencesResult(
-            int statusCode, String[] geofenceRequestIds) {
-        // If adding the geofences was successful
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            /*
-             * Handle successful addition of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If adding the geofences failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        // Turn off the in progress flag and disconnect the client
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
-    ...
-}
-
- -

Handle disconnections

-

- In some cases, Location Services may disconnect from the activity recognition client before - you call -disconnect(). - To handle this situation, implement -onDisconnected(). - In this method, set the request flag to indicate that a request is not in progress, and - delete the client: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /*
-     * Implement ConnectionCallbacks.onDisconnected()
-     * Called by Location Services once the location client is
-     * disconnected.
-     */
-    @Override
-    public void onDisconnected() {
-        // Turn off the request flag
-        mInProgress = false;
-        // Destroy the current location client
-        mLocationClient = null;
-    }
-    ...
-}
-
- -

Handle connection errors

-

- Besides handling the normal callbacks from Location Services, you have to provide a callback - method that Location Services calls if a connection error occurs. This callback method - can re-use the {@link android.support.v4.app.DialogFragment} class that you defined to - handle the check for Google Play services. It can also re-use the override you defined - for {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()} that - receives any Google Play services results that occur when the user interacts with the - error dialog. The following snippet shows you a sample implementation of the callback method: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Implementation of OnConnectionFailedListener.onConnectionFailed
-    @Override
-    public void onConnectionFailed(ConnectionResult connectionResult) {
-        // Turn off the request flag
-        mInProgress = false;
-        /*
-         * If the error has a resolution, start a Google Play services
-         * activity to resolve it.
-         */
-        if (connectionResult.hasResolution()) {
-            try {
-                connectionResult.startResolutionForResult(
-                        this,
-                        CONNECTION_FAILURE_RESOLUTION_REQUEST);
-            } catch (SendIntentException e) {
-                // Log the error
-                e.printStackTrace();
-            }
-        // If no resolution is available, display an error dialog
-        } else {
-            // Get the error code
-            int errorCode = connectionResult.getErrorCode();
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    errorCode,
-                    this,
-                    CONNECTION_FAILURE_RESOLUTION_REQUEST);
-            // If Google Play services can provide an error dialog
-            if (errorDialog != null) {
-                // Create a new DialogFragment for the error dialog
-                ErrorDialogFragment errorFragment =
-                        new ErrorDialogFragment();
-                // Set the dialog in the DialogFragment
-                errorFragment.setDialog(errorDialog);
-                // Show the error dialog in the DialogFragment
-                errorFragment.show(
-                        getSupportFragmentManager(),
-                        "Geofence Detection");
-            }
-        }
-    }
-    ...
-}
-
- + +

Handle Geofence Transitions

When Location Services detects that the user has entered or exited a geofence, it sends out the {@link android.content.Intent} contained in the {@link android.app.PendingIntent} - you included in the request to add geofences. This {@link android.content.Intent} is + you included in the request to add geofences. This {@link android.content.Intent} is received + by a service like GeofenceTransitionsIntentService, + 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.

-

Define an IntentService

The following snippet shows how to define an {@link android.app.IntentService} that posts a notification when a geofence transition occurs. When the user clicks the notification, the app's main activity appears:

-public class ReceiveTransitionsIntentService extends IntentService {
-    ...
-    /**
-     * Sets an identifier for the service
-     */
-    public ReceiveTransitionsIntentService() {
-        super("ReceiveTransitionsIntentService");
-    }
-    /**
-     * Handles incoming intents
-     *@param intent The Intent sent by Location Services. This
-     * Intent is provided
-     * to Location Services (inside a PendingIntent) when you call
-     * addGeofences()
-     */
-    @Override
+public class GeofenceTransitionsIntentService extends IntentService {
+   ...
     protected void onHandleIntent(Intent intent) {
-        // First check for errors
-        if (LocationClient.hasError(intent)) {
-            // Get the error code with a static method
-            int errorCode = LocationClient.getErrorCode(intent);
-            // Log the error
-            Log.e("ReceiveTransitionsIntentService",
-                    "Location Services error: " +
-                    Integer.toString(errorCode));
-            /*
-             * You can also send the error code to an Activity or
-             * Fragment with a broadcast Intent
-             */
-        /*
-         * If there's no error, get the transition type and the IDs
-         * of the geofence or geofences that triggered the transition
-         */
-        } else {
-            // Get the type of transition (entry or exit)
-            int transitionType =
-                    LocationClient.getGeofenceTransition(intent);
-            // Test that a valid transition was reported
-            if (
-                (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER)
-                 ||
-                (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT)
-               ) {
-                List <Geofence> triggerList =
-                        getTriggeringGeofences(intent);
+        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
+        if (geofencingEvent.hasError()) {
+            String errorMessage = GeofenceErrorMessages.getErrorString(this,
+                    geofencingEvent.getErrorCode());
+            Log.e(TAG, errorMessage);
+            return;
+        }
 
-                String[] triggerIds = new String[geofenceList.size()];
+        // Get the transition type.
+        int geofenceTransition = geofencingEvent.getGeofenceTransition();
 
-                for (int i = 0; i < triggerIds.length; i++) {
-                    // Store the Id of each geofence
-                    triggerIds[i] = triggerList.get(i).getRequestId();
-                }
-                /*
-                 * At this point, you can store the IDs for further use
-                 * display them, or display the details associated with
-                 * them.
-                 */
-            }
-        // An invalid transition was reported
+        // Test that the reported transition was of interest.
+        if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
+                geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
+
+            // Get the geofences that were triggered. A single event can trigger
+            // multiple geofences.
+            List triggeringGeofences = geofencingEvent.getTriggeringGeofences();
+
+            // Get the transition details as a String.
+            String geofenceTransitionDetails = getGeofenceTransitionDetails(
+                    this,
+                    geofenceTransition,
+                    triggeringGeofences
+            );
+
+            // Send notification and log the transition details.
+            sendNotification(geofenceTransitionDetails);
+            Log.i(TAG, geofenceTransitionDetails);
         } else {
-            Log.e("ReceiveTransitionsIntentService",
-                    "Geofence transition error: " +
-                    Integer.toString()transitionType));
+            // Log the error.
+            Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
+                    geofenceTransition));
         }
     }
-    ...
-}
 
- -

Specify the IntentService in the manifest

-

- To identify the {@link android.app.IntentService} to the system, add a - <service> - element to the app manifest. For example: -

-
-<service
-    android:name="com.example.android.location.ReceiveTransitionsIntentService"
-    android:label="@string/app_name"
-    android:exported="false">
-</service>
-
-

- Notice that you don't have to specify intent filters for the service, because it only receives - explicit intents. How the incoming geofence transition intents are created is described in the - section Send the monitoring request. -

+ +

After detecting the transition event via the {@link android.app.PendingIntent}, + this {@link android.app.IntentService} gets the geofence transition type and tests whether + it is one of the events the app uses to trigger notifications -- either + GEOFENCE_TRANSITION_ENTER + or GEOFENCE_TRANSITION_EXIT + in this case. The service then sends a notification and logs the transition details.

Stop Geofence Monitoring

-

- To stop geofence monitoring, you remove the geofences themselves. You can remove a specific - set of geofences or all the geofences associated with a {@link android.app.PendingIntent}. The - procedure is similar to adding geofences. The first operation gets a location - client for the removal request, and the second makes the request using the client. + +

Stopping geofence monitoring when it is no longer needed or desired can help save battery + power and CPU cycles on the device. You can stop geofence monitoring + in the main activity used to add and remove geofences; removing a geofence stops it + immediately. The API provides methods to + remove geofences either by request IDs, or by removing geofences associated with a given + {@link android.app.PendingIntent}.

- The callback methods that Location Services invokes when it has finished removing geofences - are defined in the interface -LocationClient.OnRemoveGeofencesResultListener. Declare - this interface as part of your class definition, and then add definitions for its two methods: -

-
-
-onRemoveGeofencesByPendingIntentResult() -
-
- Callback invoked when Location Services finishes a request to remove all geofences made - by the method -removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener). -
-
-onRemoveGeofencesByRequestIdsResult(List<String>, LocationClient.OnRemoveGeofencesResultListener) -
-
- Callback invoked when Location Services finished a request to remove a set of geofences, - specified by their geofence IDs, by the method -removeGeofences(List<String>, LocationClient.OnRemoveGeofencesResultListener). -
-
-

- Examples of implementing these methods are shown in the next snippets. -

-

Remove all geofences

-

- Since removing geofences uses some of the methods you use to add geofences, start by defining - another request type: + The following snippet removes geofences by {@link android.app.PendingIntent}, stopping all + further notification when the device enters or exits previously added geofences:

-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    // Enum type for controlling the type of removal requested
-    public enum REQUEST_TYPE = {ADD, REMOVE_INTENT}
-    ...
+LocationServices.GeofencingApi.removeGeofences(
+            mGoogleApiClient,
+            // This is the same pending intent that was used in addGeofences().
+            getGeofencePendingIntent()
+    ).setResultCallback(this); // Result processed in onResult().
 }
 
+

- Start the removal request by getting a connection to Location Services. If the connection fails, -onConnected() isn't called, - and the request stops. The following snippet shows how to start the request: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Start a request to remove geofences by calling
-     * LocationClient.connect()
-     */
-    public void removeGeofences(PendingIntent requestIntent) {
-        // Record the type of removal request
-        mRequestType = REMOVE_INTENT;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the request can be
-         * restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        // Store the PendingIntent
-        mGeofenceRequestIntent = requestIntent;
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
-    }
-    ...
-}
-
-

- When Location Services invokes the callback method indicating that the connection is open, - make the request to remove all geofences. Disconnect the client after making the request. - For example: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Once the connection is available, send a request to remove the
-     * Geofences. The method signature used depends on which type of
-     * remove request was originally received.
-     */
-    private void onConnected(Bundle dataBundle) {
-        /*
-         * Choose what to do based on the request type set in
-         * removeGeofences
-         */
-        switch (mRequestType) {
-            ...
-            case REMOVE_INTENT :
-                mLocationClient.removeGeofences(
-                        mGeofenceRequestIntent, this);
-                break;
-            ...
-        }
-    }
-    ...
-}
-
-

- Although the call to -removeGeofences(PendingIntent, LocationClient.OnRemoveGeofencesResultListener) Services calls - returns immediately, the result of the removal request is indeterminate until Location Services - calls -onRemoveGeofencesByPendingIntentResult(). - The following snippet shows how to define this method: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * When the request to remove geofences by PendingIntent returns,
-     * handle the result.
-     *
-     *@param statusCode the code returned by Location Services
-     *@param requestIntent The Intent used to request the removal.
-     */
-    @Override
-    public void onRemoveGeofencesByPendingIntentResult(int statusCode,
-            PendingIntent requestIntent) {
-        // If removing the geofences was successful
-        if (statusCode == LocationStatusCodes.SUCCESS) {
-            /*
-             * Handle successful removal of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If adding the geocodes failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        /*
-         * Disconnect the location client regardless of the
-         * request status, and indicate that a request is no
-         * longer in progress
-         */
-        mInProgress = false;
-        mLocationClient.disconnect();
-    }
-    ...
-}
-
-

Remove individual geofences

-

- The procedure for removing an individual geofence or set of geofences is similar to the - removal of all geofences. To specify the geofences you want remove, add their geofence ID - values to a {@link java.util.List} of String objects. Pass this {@link java.util.List} to a - different definition of {@code removeGeofences} with the appropriate signature. This method - then starts the removal process. -

-

- Start by adding a request type for removing geofences by a list, and also add a global variable - for storing the list of geofences: -

-
-    ...
-    // Enum type for controlling the type of removal requested
-    public enum REQUEST_TYPE = {ADD, REMOVE_INTENT, REMOVE_LIST}
-    // Store the list of geofence Ids to remove
-    String<List> mGeofencesToRemove;
-
-

- Next, define a list of geofences you want to remove. For example, this snippet removes the -Geofence - defined by the geofence ID "1": -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-        List<String> listOfGeofences =
-                Collections.singletonList("1");
-        removeGeofences(listOfGeofences);
-    ...
-}
-
-

- The following snippet defines the {@code removeGeofences()} method: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * Start a request to remove monitoring by
-     * calling LocationClient.connect()
-     *
-     */
-    public void removeGeofences(List<String> geofenceIds) {
-        // If Google Play services is unavailable, exit
-        // Record the type of removal request
-        mRequestType = REMOVE_LIST;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the request can be
-         * restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        // Store the list of geofences to remove
-        mGeofencesToRemove = geofenceIds;
-        /*
-         * Create a new location client object. Since the current
-         * activity class implements ConnectionCallbacks and
-         * OnConnectionFailedListener, pass the current activity object
-         * as the listener for both parameters
-         */
-        mLocationClient = new LocationClient(this, this, this);
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is underway
-            mInProgress = true;
-            // Request a connection from the client to Location Services
-            mLocationClient.connect();
-        } else {
-            /*
-             * A request is already underway. You can handle
-             * this situation by disconnecting the client,
-             * re-setting the flag, and then re-trying the
-             * request.
-             */
-        }
-    }
-    ...
-}
-
-

- When Location Services invokes the callback method indicating that the connection is open, - make the request to remove the list of geofences. Disconnect the client after making the request. - For example: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    private void onConnected(Bundle dataBundle) {
-        ...
-        switch (mRequestType) {
-        ...
-        // If removeGeofencesById was called
-            case REMOVE_LIST :
-                mLocationClient.removeGeofences(
-                        mGeofencesToRemove, this);
-                break;
-        ...
-        }
-        ...
-    }
-    ...
-}
-
-

- Define an implementation of -onRemoveGeofencesByRequestIdsResult(). - Location Services invokes this callback method to indicate that the request to remove a list of - geofences is complete. In this method, examine the incoming status code and take the - appropriate action: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks,
-        OnConnectionFailedListener,
-        OnAddGeofencesResultListener {
-    ...
-    /**
-     * When the request to remove geofences by IDs returns, handle the
-     * result.
-     *
-     * @param statusCode The code returned by Location Services
-     * @param geofenceRequestIds The IDs removed
-     */
-    @Override
-    public void onRemoveGeofencesByRequestIdsResult(
-            int statusCode, String[] geofenceRequestIds) {
-        // If removing the geocodes was successful
-        if (LocationStatusCodes.SUCCESS == statusCode) {
-            /*
-             * Handle successful removal of geofences here.
-             * You can send out a broadcast intent or update the UI.
-             * geofences into the Intent's extended data.
-             */
-        } else {
-        // If removing the geofences failed
-            /*
-             * Report errors here.
-             * You can log the error using Log.e() or update
-             * the UI.
-             */
-        }
-        // Indicate that a request is no longer in progress
-        mInProgress = false;
-        // Disconnect the location client
-        mLocationClient.disconnect();
-    }
-    ...
-}
-
-

- You can combine geofencing with other location-aware features, such as periodic location updates - or activity recognition, which are described in other lessons in this class. -

-

- The next lesson, - Recognizing the User's Current Activity, shows you how - to request and receive activity updates. At regular intervals, Location Services can send you - information about the user's current physical activity. Based on this information, you can - change your app's behavior; for example, you can switch to a longer update interval if you - detect that the user is walking instead of driving. + You can combine geofencing with other location-aware features, such as periodic location updates. + For more information, see the other lessons in this class.

diff --git a/docs/html/training/location/index.jd b/docs/html/training/location/index.jd index 35e177f923b06..c4dec9928d822 100644 --- a/docs/html/training/location/index.jd +++ b/docs/html/training/location/index.jd @@ -81,4 +81,10 @@ startpage=true Learn how to convert a location's latitude and longitude into an address (reverse geocoding). +
+ Creating and Monitoring Geofences +
+ Learn how to define one or more geographic areas as locations of interest, + called geofences, and detect when the user is close to or inside a geofence. +
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 89e72f1706b91..11ae1a6f2d670 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -736,6 +736,10 @@ include the action bar on devices running Android 2.1 or higher." Displaying a Location Address +
  • + Creating and Monitoring Geofences + +