diff --git a/docs/html/training/location/activity-recognition.jd b/docs/html/training/location/activity-recognition.jd deleted file mode 100644 index d50064b00d6eb..0000000000000 --- a/docs/html/training/location/activity-recognition.jd +++ /dev/null @@ -1,786 +0,0 @@ -page.title=Recognizing the User's Current Activity - -trainingnavtop=true -@jd:body - -
-
-

This lesson teaches you to

-
    -
  1. Request Activity Recognition Updates
  2. -
  3. Handle Activity Updates -
  4. Stop Activity Recognition Updates -
-

You should also read

- -

Try it out

- -
- Download the sample -

ActivityRecognition.zip

-
- -
-
- -

- Activity recognition tries to detect the user's current physical activity, such as walking, - driving, or standing still. Requests for updates go through an activity recognition client, - which, while different from the location client used by location or geofencing, follows a - similar pattern. Based on the update interval you choose, Location Services sends out - activity information containing one or more possible activities and the confidence level for - each one. This lesson shows you how to request activity recognition updates from Location - Services. -

-

Request Activity Recognition Updates

-

- Requesting activity recognition updates from Location Services is similar to requesting - periodic location updates. You send the request through a client, and Location Services sends - updates back to your app by means of a {@link android.app.PendingIntent}. However, you need to - request a special permission before you request activity updates, and you use a different type - of client to make requests. The following sections show how to request the permission, - connect the client, and request updates. -

-

Request permission to receive updates

-

- An app that wants to get activity recognition updates must have the permission - {@code com.google.android.gms.permission.ACTIVITY_RECOGNITION}. To request this permission for - your app, add the following XML element to your manifest as a child element of the -<manifest> - element: -

-
-<uses-permission
-    android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
-
-

- Activity recognition does not require the permissions - {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or - {@link android.Manifest.permission#ACCESS_FINE_LOCATION 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: -

-
-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("Activity Recognition",
-                    "Google Play services is available.");
-            // Continue
-            return true;
-        // Google Play services was not available for some reason
-        } else {
-            // Get the error dialog from Google Play services
-            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
-                    resultCode,
-                    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(),
-                        "Activity Recognition");
-            }
-            return false;
-        }
-    }
-    ...
-}
-
-

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

-

Send the activity update request

-

- Send the update request from an {@link android.app.Activity} or - {@link android.support.v4.app.Fragment} that implements the callback methods required by - Location Services. Making the request is an asynchronous process that starts when you request - a connection to an activity recognition client. When the client is connected, Location Services - invokes your implementation of -onConnected(). - In this method, you can send the update request to Location Services; this request is - synchronous. Once you've made the request, you can disconnect the client. -

-

- This process is described in the following snippets. -

-

Define the Activity or Fragment

-

- Define an {@link android.support.v4.app.FragmentActivity} or - {@link android.support.v4.app.Fragment} that implements the following interfaces: -

-
-
-ConnectionCallbacks -
-
- Specifies methods that Location Services calls when the client is connected or - disconnected. -
-
-OnConnectionFailedListener -
-
- Specifies a method that Location Services calls if an error occurs while attempting to - connect the client. -
-
-

- For example: -

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

- Next, define global variables and constants. Define constants for the update interval, - add a variable for the activity recognition client, and another for the - {@link android.app.PendingIntent} that Location Services uses to send updates to your app: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    // Constants that define the activity detection interval
-    public static final int MILLISECONDS_PER_SECOND = 1000;
-    public static final int DETECTION_INTERVAL_SECONDS = 20;
-    public static final int DETECTION_INTERVAL_MILLISECONDS =
-            MILLISECONDS_PER_SECOND * DETECTION_INTERVAL_SECONDS;
-    ...
-    /*
-     * Store the PendingIntent used to send activity recognition events
-     * back to the app
-     */
-    private PendingIntent mActivityRecognitionPendingIntent;
-    // Store the current activity recognition client
-    private ActivityRecognitionClient mActivityRecognitionClient;
-    ...
-}
-
-

- In {@link android.app.Activity#onCreate onCreate()}, instantiate the activity recognition - client and the {@link android.app.PendingIntent}: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    @Override
-    onCreate(Bundle savedInstanceState) {
-        ...
-        /*
-         * Instantiate a new activity recognition client. Since the
-         * parent Activity implements the connection listener and
-         * connection failure listener, the constructor uses "this"
-         * to specify the values of those parameters.
-         */
-        mActivityRecognitionClient =
-                new ActivityRecognitionClient(mContext, this, this);
-        /*
-         * Create the PendingIntent that Location Services uses
-         * to send activity recognition updates back to this app.
-         */
-        Intent intent = new Intent(
-                mContext, ActivityRecognitionIntentService.class);
-        /*
-         * Return a PendingIntent that starts the IntentService.
-         */
-        mActivityRecognitionPendingIntent =
-                PendingIntent.getService(mContext, 0, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        ...
-    }
-    ...
-}
-
-

Start the request process

-

- Define a method that requests activity recognition updates. In the method, request a - connection to Location Services. You can call this method from anywhere in your activity; its - purpose is to start the chain of method calls for requesting updates. -

-

- 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. Set the flag to {@code true} when you start a request, and then set it to - {@code false} when the request completes. -

-

- The following snippet shows how to start a request for updates: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    // Global constants
-    ...
-    // Flag that indicates if a request is underway.
-    private boolean mInProgress;
-    ...
-    @Override
-    onCreate(Bundle savedInstanceState) {
-        ...
-        // Start with the request flag set to false
-        mInProgress = false;
-        ...
-    }
-    ...
-    /**
-     * Request activity recognition updates based on the current
-     * detection interval.
-     *
-     */
-     public void startUpdates() {
-        // Check for Google Play services
-
-        if (!servicesConnected()) {
-            return;
-        }
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is in progress
-            mInProgress = true;
-            // Request a connection to Location Services
-            mActivityRecognitionClient.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.
-             */
-        }
-    }
-    ...
-}
-
-

- Implement -onConnected(). - In this method, request activity recognition updates from Location Services. When Location - Services finishes connecting to the client and calls -onConnected(), - the update request is called immediately: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    /*
-     * Called by Location Services once the location client is connected.
-     *
-     * Continue by requesting activity updates.
-     */
-    @Override
-    public void onConnected(Bundle dataBundle) {
-        /*
-         * Request activity recognition updates using the preset
-         * detection interval and PendingIntent. This call is
-         * synchronous.
-         */
-        mActivityRecognitionClient.requestActivityUpdates(
-                DETECTION_INTERVAL_MILLISECONDS,
-                mActivityRecognitionPendingIntent);
-        /*
-         * Since the preceding call is synchronous, turn off the
-         * in progress flag and disconnect the client
-         */
-        mInProgress = false;
-        mActivityRecognitionClient.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 {
-    ...
-    /*
-     * Called by Location Services once the activity recognition
-     * client is disconnected.
-     */
-    @Override
-    public void onDisconnected() {
-        // Turn off the request flag
-        mInProgress = false;
-        // Delete the client
-        mActivityRecognitionClient = 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 {
-    ...
-    // 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(),
-                        "Activity Recognition");
-            }
-        }
-        ...
-    }
-    ...
-}
-
- -

Handle Activity Updates

-

- To handle the {@link android.content.Intent} that Location Services sends for each update - interval, define an {@link android.app.IntentService} and its required method - {@link android.app.IntentService#onHandleIntent onHandleIntent()}. Location Services - sends out activity recognition updates as {@link android.content.Intent} objects, using the - the {@link android.app.PendingIntent} you provided when you called -requestActivityUpdates(). - Since you provided an explicit intent for the {@link android.app.PendingIntent}, the only - component that receives the intent is the {@link android.app.IntentService} you're defining. -

-

- The following snippets demonstrate how to examine the data in an activity recognition - update. -

-

Define an IntentService

-

- Start by defining the class and the required method - {@link android.app.IntentService#onHandleIntent onHandleIntent()}: -

-
-/**
- * Service that receives ActivityRecognition updates. It receives
- * updates in the background, even if the main Activity is not visible.
- */
-public class ActivityRecognitionIntentService extends IntentService {
-    ...
-    /**
-     * Called when a new activity detection update is available.
-     */
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        ...
-    }
-    ...
-}
-
-

- Next, examine the data in the intent. From the update, you can get a list of possible activities - and the probability of each one. The following snippet shows how to get the most probable - activity, the confidence level for the activity (the probability that this is the actual - activity), and its type: -

-
-public class ActivityRecognitionIntentService extends IntentService {
-    ...
-    @Override
-    protected void onHandleIntent(Intent intent) {
-        ...
-        // If the incoming intent contains an update
-        if (ActivityRecognitionResult.hasResult(intent)) {
-            // Get the update
-            ActivityRecognitionResult result =
-                    ActivityRecognitionResult.extractResult(intent);
-            // Get the most probable activity
-            DetectedActivity mostProbableActivity =
-                    result.getMostProbableActivity();
-            /*
-             * Get the probability that this activity is the
-             * the user's actual activity
-             */
-            int confidence = mostProbableActivity.getConfidence();
-            /*
-             * Get an integer describing the type of activity
-             */
-            int activityType = mostProbableActivity.getType();
-            String activityName = getNameFromType(activityType);
-            /*
-             * At this point, you have retrieved all the information
-             * for the current update. You can display this
-             * information to the user in a notification, or
-             * send it to an Activity or Service in a broadcast
-             * Intent.
-             */
-            ...
-        } else {
-            /*
-             * This implementation ignores intents that don't contain
-             * an activity update. If you wish, you can report them as
-             * errors.
-             */
-        }
-        ...
-    }
-    ...
-}
-
-

- The method {@code getNameFromType()} converts activity types into descriptive - strings. In a production app, you should retrieve the strings from resources instead of - using fixed values: -

-
-public class ActivityRecognitionIntentService extends IntentService {
-    ...
-    /**
-     * Map detected activity types to strings
-     *@param activityType The detected activity type
-     *@return A user-readable name for the type
-     */
-    private String getNameFromType(int activityType) {
-        switch(activityType) {
-            case DetectedActivity.IN_VEHICLE:
-                return "in_vehicle";
-            case DetectedActivity.ON_BICYCLE:
-                return "on_bicycle";
-            case DetectedActivity.ON_FOOT:
-                return "on_foot";
-            case DetectedActivity.STILL:
-                return "still";
-            case DetectedActivity.UNKNOWN:
-                return "unknown";
-            case DetectedActivity.TILTING:
-                return "tilting";
-        }
-        return "unknown";
-    }
-    ...
-}
-
- -

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.ActivityRecognitionIntentService"
-    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 activity update intents are created is described in the - section Define the Activity or Fragment. -

-

Stop Activity Recognition Updates

-

- To stop activity recognition updates, use the same pattern you used to request updates, - but call -removeActivityUpdates() - instead of requestActivityUpdates(). -

-

-

- Since removing updates uses some of the methods you use to add updates, start by defining - request types for the two operations: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    public enum REQUEST_TYPE {START, STOP}
-    private REQUEST_TYPE mRequestType;
-    ...
-}
-
-

- Modify the code that starts activity recognition so that it uses the {@code START} - request type: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    public void startUpdates() {
-        // Set the request type to START
-        mRequestType = REQUEST_TYPE.START;
-        /*
-         * Test for Google Play services after setting the request type.
-         * If Google Play services isn't present, the proper request type
-         * can be restarted.
-         */
-        if (!servicesConnected()) {
-            return;
-        }
-        ...
-    }
-    ...
-    public void onConnected(Bundle dataBundle) {
-        switch (mRequestType) {
-            case START :
-                /*
-                 * Request activity recognition updates using the
-                 * preset detection interval and PendingIntent.
-                 * This call is synchronous.
-                 */
-                mActivityRecognitionClient.requestActivityUpdates(
-                        DETECTION_INTERVAL_MILLISECONDS,
-                        mActivityRecognitionPendingIntent);
-                break;
-                ...
-                /*
-                 * An enum was added to the definition of REQUEST_TYPE,
-                 * but it doesn't match a known case. Throw an exception.
-                 */
-                default :
-                throw new Exception("Unknown request type in onConnected().");
-                break;
-        }
-        ...
-    }
-    ...
-}
-
-

Start the process

-

- Define a method that requests a stop to activity recognition updates. In the method, - set the request type and then request a connection to Location Services. You can call this - method from anywhere in your activity; its purpose is to start the chain of method calls that - stop activity updates: -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    /**
-     * Turn off activity recognition updates
-     *
-     */
-    public void stopUpdates() {
-        // Set the request type to STOP
-        mRequestType = REQUEST_TYPE.STOP;
-        /*
-         * 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;
-        }
-        // If a request is not already underway
-        if (!mInProgress) {
-            // Indicate that a request is in progress
-            mInProgress = true;
-            // Request a connection to Location Services
-            mActivityRecognitionClient.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.
-             */
-        }
-        ...
-    }
-    ...
-}
-
-

- In -onConnected(), - if the request type is STOP, call -removeActivityUpdates(). - Pass the {@link android.app.PendingIntent} you used to start updates as the parameter to -removeActivityUpdates(): -

-
-public class MainActivity extends FragmentActivity implements
-        ConnectionCallbacks, OnConnectionFailedListener {
-    ...
-    public void onConnected(Bundle dataBundle) {
-        switch (mRequestType) {
-            ...
-            case STOP :
-            mActivityRecognitionClient.removeActivityUpdates(
-                    mActivityRecognitionPendingIntent);
-            break;
-            ...
-        }
-        ...
-    }
-    ...
-}
-
-

- You do not have to modify your implementation of -onDisconnected() - or -onConnectionFailed(), - because these methods do not depend on the request type. -

-

- You now have the basic structure of an app that implements activity recognition. You can combine - activity recognition with other location-aware features, such as periodic location updates or - geofencing, which are described in other lessons in this class. -

diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd deleted file mode 100644 index 8f73d515db878..0000000000000 --- a/docs/html/training/location/location-testing.jd +++ /dev/null @@ -1,371 +0,0 @@ -page.title=Testing Using Mock Locations - -trainingnavtop=true -@jd:body - -
-
- - -

This lesson teaches you to

-
    -
  1. Turn On Mock Mode
  2. -
  3. Send Mock Locations
  4. -
  5. Run the Mock Location Provider App
  6. -
  7. Testing Tips -
- -

You should also read

- - -

Example Test App

- -
- Download the sample -

LocationProvider.zip

-
- -
-
-

- To test a location-aware app that uses Location Services, you don't need to move your device - from place to place to generate location data. Instead, you can put Location Services into mock - mode. In this mode, you can send mock {@link android.location.Location} objects to - Location Services, which then sends them to location clients. In mock mode, Location Services - also uses mock {@link android.location.Location} objects to trigger geofences. -

-

- Using mock locations has several advantages: -

- -

- The best way to use mock locations is to send them from a separate mock location provider app. - This lesson includes a provider app that you can download and use to test your own software. - Modify the provider app as necessary to suit your own needs. Some ideas for providing test data - to the app are listed in the section Managing test data. -

-

- The remainder of this lesson shows you how to turn on mock mode and use a location client to - send mock locations to Location Services. -

-

- Note: Mock locations have no effect on the activity recognition algorithm used - by Location Services. To learn more about activity recognition, see the lesson - Recognizing the User's Current Activity. -

- -

Turn On Mock Mode

-

- To send mock locations to Location Services in mock mode, a test app must request the permission - android.Manifest.permission#ACCESS_MOCK_LOCATION. In addition, you must enable mock - locations on the test device using the option Enable mock locations. To learn how to - enable mock locations on the device, see - Setting up a Device for Development. -

-

- To turn on mock mode in Location Services, start by connecting a location client to Location - Services, as described in the lesson - Retrieving the Current Location. - Next, call the method -LocationClient.setMockMode(true). - Once you call this method, Location Services turns off its internal location providers and only - sends out the mock locations you provide it. The following snippet shows you how to call -LocationClient.setMockMode(true): -

-
-    // Define a LocationClient object
-    public LocationClient mLocationClient;
-    ...
-    // Connect to Location Services
-    mLocationClient.connect();
-    ...
-    // When the location client is connected, set mock mode
-    mLocationClinet.setMockMode(true);
-
-

- Once you have connected the location client to Location Services, you must keep it connected - until you finish sending out mock locations. Once you call -LocationClient.disconnect(), - Location Services returns to using its internal location providers. To turn off mock mode while - the location client is connected, call -LocationClient.setMockMode(false). -

-

Send Mock Locations

-

- Once you have set mock mode, you can create mock {@link android.location.Location} objects and - send them to Location Services. In turn, Location Services sends these mock - {@link android.location.Location} objects to connected location clients. Location Services also - uses the mock {@link android.location.Location} objects to control geofence triggering. -

-

- To create a new mock {@link android.location.Location}, create a new - {@link android.location.Location} object using your test data. Always set the provider - value to {@code flp}, which is the code that Location Services puts into the - {@link android.location.Location} objects it sends out. The following snippet shows you how - to create a new mock {@link android.location.Location}: -

-
-    private static final String PROVIDER = "flp";
-    private static final double LAT = 37.377166;
-    private static final double LNG = -122.086966;
-    private static final float ACCURACY = 3.0f;
-    ...
-    /*
-     * From input arguments, create a single Location with provider set to
-     * "flp"
-     */
-    public Location createLocation(double lat, double lng, float accuracy) {
-        // Create a new Location
-        Location newLocation = new Location(PROVIDER);
-        newLocation.setLatitude(lat);
-        newLocation.setLongitude(lng);
-        newLocation.setAccuracy(accuracy);
-        return newLocation;
-    }
-    ...
-    // Example of creating a new Location from test data
-    Location testLocation = createLocation(LAT, LNG, ACCURACY);
-
-

- In mock mode, to send a mock location to Location Services call the method -LocationClient.setMockLocation(). - For example: -

-
-    mLocationClient.setMockLocation(testLocation);
-
-

- Location Services sets this mock location as the current location, and this location is sent - out as the next location update. If this new mock location moves across a geofence boundary, - Location Services triggers the geofence. -

- -

Run the Mock Location Provider App

-

- This section contains a brief overview of the mock location provider sample app - (available for download above) and gives you directions for testing an app using the sample app. -

-

Overview

-

- The mock location provider app included with this lesson sends mock - {@link android.location.Location} objects to Location Services from a background thread running - in a started {@link android.app.Service}. By using a started service, the provider app is able - to keep running even if the app's main {@link android.app.Activity} is destroyed because of - a configuration change or other system event. By using a background thread, the service is able - to perform a long-running test without blocking the UI thread. -

-

- The {@link android.app.Activity} that starts when you run the provider app allows you to - send test parameters to the {@link android.app.Service} and control the type of test you want. - You have the following options: -

-
-
- Pause before test -
-
- The number of seconds to wait before the provider app starts sending test data to Location - Services. This interval allows you to switch from the provider app to the app under test - before the testing actually starts. -
-
- Send interval -
-
- The number of seconds that the provider app waits before it sends another mock location to - Location Services. See the section Testing Tips to learn more - about setting the send interval. -
-
- Run once -
-
- Switch from normal mode to mock mode, run through the test data once, switch back to - normal mode, and then kill the {@link android.app.Service}. -
-
- Run continuously -
-
- Switch from normal mode to mock mode, then run through the test data indefinitely. The - background thread and the started {@link android.app.Service} continue to run, even if the - main {@link android.app.Activity} is destroyed. -
-
- Stop test -
-
- If a continuous test is in progress, stop it; otherwise, return a warning message. The - started {@link android.app.Service} switches from mock mode to normal mode and then - stops itself. This also stops the background thread. -
-
-

- Besides the options, the provider app has two status displays: -

-
-
- App status -
-
- Displays messages related to the lifecycle of the provider app. -
-
- Connection status -
-
- Displays messages related to the state of the location client connection. -
-
-

- While the started {@link android.app.Service} is running, it also posts notifications with the - testing status. These notifications allow you to see status updates even if the app is not in - the foreground. When you click on a notification, the main {@link android.app.Activity} of the - provider app returns to the foreground. -

-

Test using the mock location provider app

-

- To test mock location data coming from the mock location provider app: -

-
    -
  1. - Install the mock location provider app on a device that has Google Play services installed. - Location Services is part of Google Play services. -
  2. -
  3. - On the device, enable mock locations. To learn how to do this, see the topic - Setting up a Device for Development. -
  4. -
  5. - Start the provider app from the Launcher, then choose the options you want from the main - screen. -
  6. -
  7. - Unless you've removed the pause interval feature, the mock location provider app - pauses for a few seconds, and then starts sending mock location data to Location - Services. -
  8. -
  9. - Run the app you want to test. While the mock location provider app is running, the app - you're testing receives mock locations instead of real locations. -
  10. -
  11. - If the provider app is in the midst of a continuous test, you can switch back to real - locations by clicking Stop test. This forces the started {@link android.app.Service} - to turn off mock mode and then stop itself. When the service stops itself, the background - thread is also destroyed. -
  12. - -
-

Testing Tips

-

- The following sections contain tips for creating mock location data and using the data with a - mock location provider app. -

-

Choosing a send interval

-

- Each location provider that contributes to the fused location sent out by Location Services has - its own minimum update cycle. For example, the GPS provider can't send a new location more often - than once per second, and the Wi-Fi provider can't send a new location more often than once - every five seconds. These cycle times are handled automatically for real locations, but you - should account for them when you send mock locations. For example, you shouldn't send a new mock - location more than once per second. If you're testing indoor locations, which rely heavily on - the Wi-Fi provider, then you should consider using a send interval of five seconds. -

-

Simulating speed

-

- To simulate the speed of an actual device, shorten or lengthen the distance between two - successive locations. For example, changing the location by 88 feet every second simulates - car travel, because this change works out to 60 miles an hour. In comparison, changing the - location by 1.5 feet every second simulates brisk walking, because this change works out to - 3 miles per hour. -

-

Calculating location data

-

- By searching the web, you can find a variety of small programs that calculate a new set of - latitude and longitude coordinates from a starting location and a distance, as well as - references to formulas for calculating the distance between two points based on their latitude - and longitude. In addition, the {@link android.location.Location} class offers two methods for - calculating the distance between points: -

-
-
- {@link android.location.Location#distanceBetween distanceBetween()} -
-
- A static method that calculates the distance between two points specified by latitude and - longitude. -
-
- {@link android.location.Location#distanceTo distanceTo()} -
-
- For a given {@link android.location.Location}, returns the distance to another - {@link android.location.Location}. -
-
-

Geofence testing

-

- When you test an app that uses geofence detection, use test data that reflects different modes - of travel, including walking, cycling, driving, and traveling by train. For a slow mode of - travel, make small changes in position between points. Conversely, for a fast mode of travel, - make a large change in position between points. -

-

Managing test data

-

- The mock location provider app included with this lesson contains test latitude, longitude, - and accuracy values in the form of constants. You may want to consider other ways of organizing - data as well: -

-
-
- XML -
-
- Store location data in XML files that are including in the provider app. By separating the - data from the code, you facilitate changes to the data. -
-
- Server download -
-
- Store location data on a server and then have the provider app download it. Since the data - is completely separate from the app, you can change the data without having to rebuild the - app. You can also change the data on the server and have the changes reflected immediately - in the mock locations you're testing. -
-
- Recorded data -
-
- Instead of making up test data, write a utility app that records location data as you move - the device. Use the recorded data as your test data, or use the data to guide you in - developing test data. For example, record locations as you walk with a device, and then - create mock locations that have an appropriate change in latitude and longitude over - time. -
-