diff options
| author | 2016-05-11 17:37:45 +0000 | |
|---|---|---|
| committer | 2016-05-11 17:37:46 +0000 | |
| commit | 965f4bf1ef2e8958ec9a53bab00be919a49bc8c2 (patch) | |
| tree | ed1962524480064828ea500cfdd52ff21eb7cb3d | |
| parent | ae08263ac81277ad25a84cc3a30917f8f78a3153 (diff) | |
| parent | 7cf1e9c4033f6ce230bdaabaa62672e2a1ca50ae (diff) | |
Merge "Deleting pages so redirects work on DevSite. b/28670825" into mnc-mr-docs
| -rw-r--r-- | docs/html/training/location/activity-recognition.jd | 786 | ||||
| -rw-r--r-- | docs/html/training/location/location-testing.jd | 371 |
2 files changed, 0 insertions, 1157 deletions
diff --git a/docs/html/training/location/activity-recognition.jd b/docs/html/training/location/activity-recognition.jd deleted file mode 100644 index d50064b00d6e..000000000000 --- 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 - -<div id="tb-wrapper"> -<div id="tb"> -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#RequestUpdates">Request Activity Recognition Updates</a></li> - <li><a href="#HandleUpdates">Handle Activity Updates</a> - <li><a href="#RemoveUpdates">Stop Activity Recognition Updates</a> -</ol> -<h2>You should also read</h2> -<ul> - <li> - <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> - </li> - <li> - <a href="receive-location-updates.html">Receiving Location Updates</a> - </li> -</ul> -<h2>Try it out</h2> - -<div class="download-box"> - <a href="http://developer.android.com/shareables/training/ActivityRecognition.zip" class="button">Download the sample</a> - <p class="filename">ActivityRecognition.zip</p> -</div> - -</div> -</div> - -<p> - 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. -</p> -<h2 id="RequestUpdates">Request Activity Recognition Updates</h2> -<p> - 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. -</p> -<h3>Request permission to receive updates</h3> -<p> - 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 -<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> - element: -</p> -<pre> -<uses-permission - android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/> -</pre> -<p> - 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}. -</p> -<!-- Check for Google Play services --> -<h3>Check for Google Play Services</h3> -<p> - 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 -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>, - which returns one of the - integer result codes listed in the API reference documentation. If you encounter an error, - call -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code> - 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()} - -</p> -<p class="note"> - <strong>Note:</strong> 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}. -</p> -<p> - 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: -</p> -<pre> -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; - } - } - ... -} -</pre> -<p> - Snippets in the following sections call this method to verify that Google Play services is - available. -</p> -<h3>Send the activity update request</h3> -<p> - 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 -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code>. - 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. -</p> -<p> - This process is described in the following snippets. -</p> -<h4 id="DefineActivity">Define the Activity or Fragment</h4> -<p> - Define an {@link android.support.v4.app.FragmentActivity} or - {@link android.support.v4.app.Fragment} that implements the following interfaces: -</p> -<dl> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code> - </dt> - <dd> - Specifies methods that Location Services calls when the client is connected or - disconnected. - </dd> - <dt> -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code> - </dt> - <dd> - Specifies a method that Location Services calls if an error occurs while attempting to - connect the client. - </dd> -</dl> -<p> - For example: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, OnConnectionFailedListener { - ... -} -</pre> -<p> - 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: -</p> -<pre> -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; - ... -} -</pre> -<p> - In {@link android.app.Activity#onCreate onCreate()}, instantiate the activity recognition - client and the {@link android.app.PendingIntent}: -</p> -<pre> -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); - ... - } - ... -} -</pre> -<h4>Start the request process</h4> -<p> - 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. -</p> -<p> - 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. -</p> -<p> - The following snippet shows how to start a request for updates: -</p> -<pre> -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. - */ - } - } - ... -} -</pre> -<p> - Implement -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code>. - In this method, request activity recognition updates from Location Services. When Location - Services finishes connecting to the client and calls -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code>, - the update request is called immediately: -</p> -<pre> -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(); - } - ... -} -</pre> -<h3>Handle disconnections</h3> -<p> - In some cases, Location Services may disconnect from the activity recognition client before - you call -<code><a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognitionClient.html#disconnect()">disconnect()</a></code>. - To handle this situation, implement <code> -<a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onDisconnected()">onDisconnected()</a></code>. - In this method, set the request flag to indicate that a request is not in progress, and - delete the client: -</p> -<pre> -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; - } - ... -} -</pre> -<!-- Handle connection errors --> -<h3>Handle connection errors</h3> -<p> - 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: -</p> -<pre> -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"); - } - } - ... - } - ... -} -</pre> -<!-- Create Intent Service --> -<h2 id="HandleUpdates">Handle Activity Updates</h2> -<p> - 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 -<code><a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognitionClient.html#requestActivityUpdates(long, android.app.PendingIntent)">requestActivityUpdates()</a></code>. - 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. -</p> -<p> - The following snippets demonstrate how to examine the data in an activity recognition - update. -</p> -<h3>Define an IntentService</h3> -<p> - Start by defining the class and the required method - {@link android.app.IntentService#onHandleIntent onHandleIntent()}: -</p> -<pre> -/** - * 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) { - ... - } - ... -} -</pre> -<p> - 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: -</p> -<pre> -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. - */ - } - ... - } - ... -} -</pre> -<p> - 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: -</p> -<pre> -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"; - } - ... -} -</pre> -<!-- Define IntentService --> -<h3>Specify the IntentService in the manifest</h3> -<p> - To identify the {@link android.app.IntentService} to the system, add a - <code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code> - element to the app manifest. For example: -</p> -<pre> -<service - android:name="com.example.android.location.ActivityRecognitionIntentService" - android:label="@string/app_name" - android:exported="false"> -</service> -</pre> -<p> - 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 <a id="DefineActivity">Define the Activity or Fragment</a>. -</p> -<h2 id="RemoveUpdates">Stop Activity Recognition Updates</h2> -<p> - To stop activity recognition updates, use the same pattern you used to request updates, - but call <code> -<a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognitionClient.html#removeActivityUpdates(android.app.PendingIntent)">removeActivityUpdates()</a></code> - instead of <code><a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognitionClient.html#requestActivityUpdates(long, android.app.PendingIntent)">requestActivityUpdates()</a></code>. -</p> -<p> -<p> - Since removing updates uses some of the methods you use to add updates, start by defining - request types for the two operations: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, OnConnectionFailedListener { - ... - public enum REQUEST_TYPE {START, STOP} - private REQUEST_TYPE mRequestType; - ... -} -</pre> -<p> - Modify the code that starts activity recognition so that it uses the {@code START} - request type: -</p> -<pre> -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; - } - ... - } - ... -} -</pre> -<h3>Start the process</h3> -<p> - 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: -</p> -<pre> -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. - */ - } - ... - } - ... -} -</pre> -<p> - In -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">onConnected()</a></code>, - if the request type is STOP, call -<code><a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognitionClient.html#removeActivityUpdates(android.app.PendingIntent)">removeActivityUpdates()</a></code>. - Pass the {@link android.app.PendingIntent} you used to start updates as the parameter to -<code><a href="{@docRoot}reference/com/google/android/gms/location/ActivityRecognitionClient.html#removeActivityUpdates(android.app.PendingIntent)">removeActivityUpdates()</a></code>: -</p> -<pre> -public class MainActivity extends FragmentActivity implements - ConnectionCallbacks, OnConnectionFailedListener { - ... - public void onConnected(Bundle dataBundle) { - switch (mRequestType) { - ... - case STOP : - mActivityRecognitionClient.removeActivityUpdates( - mActivityRecognitionPendingIntent); - break; - ... - } - ... - } - ... -} -</pre> -<p> - You do not have to modify your implementation of -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html#onDisconnected()">onDisconnected()</a></code> - or -<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html#onConnectionFailed(com.google.android.gms.common.ConnectionResult)">onConnectionFailed()</a></code>, - because these methods do not depend on the request type. -</p> -<p> - 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. -</p> diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd deleted file mode 100644 index 8f73d515db87..000000000000 --- a/docs/html/training/location/location-testing.jd +++ /dev/null @@ -1,371 +0,0 @@ -page.title=Testing Using Mock Locations - -trainingnavtop=true -@jd:body - -<div id="tb-wrapper"> -<div id="tb"> - -<!-- table of contents --> -<h2>This lesson teaches you to</h2> -<ol> - <li><a href="#TurnOnMockMode">Turn On Mock Mode</a></li> - <li><a href="#SendMockLocations">Send Mock Locations</a></li> - <li><a href="#RunProvider">Run the Mock Location Provider App</a></li> - <li><a href="#TestingTips">Testing Tips</a> -</ol> - -<h2>You should also read</h2> -<ul> - <li><a href="receive-location-updates.html">Receiving Location Updates</a></li> - <li><a href="geofencing.html">Creating and Monitoring Geofences</a></li> - <li><a href="{@docRoot}guide/components/services.html">Services</a></li> - <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a> -</ul> - -<h2>Example Test App</h2> - -<div class="download-box"> - <a href="http://developer.android.com/shareables/training/LocationProvider.zip" class="button" - >Download the sample</a> - <p class="filename">LocationProvider.zip</p> -</div> - -</div> -</div> -<p> - 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. -</p> -<p> - Using mock locations has several advantages: -</p> -<ul> - <li> - Mock locations allow you to create specific mock data, instead of trying to approximate - data by moving an actual device. - </li> - <li> - Since mock locations come from Location Services, they test every part of your - location-handling code. In addition, since you can send the mock data from outside your - production app, you don't have to disable or remove test code before you publish. - </li> - <li> - Since you don't have to generate test locations by moving a device, you can test an app - using the emulator. - </li> -</ul> -<p> - 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 <a href="#TestData">Managing test data</a>. -</p> -<p> - 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. -</p> -<p class="note"> - <strong>Note:</strong> Mock locations have no effect on the activity recognition algorithm used - by Location Services. To learn more about activity recognition, see the lesson - <a href="activity-recognition.html">Recognizing the User's Current Activity</a>. -</p> -<!-- - Create a Test App - --> -<h2 id="TurnOnMockMode">Turn On Mock Mode</h2> -<p> - 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 <b>Enable mock locations</b>. To learn how to - enable mock locations on the device, see - <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>. -</p> -<p> - To turn on mock mode in Location Services, start by connecting a location client to Location - Services, as described in the lesson - <a href="retrieve-current.html">Retrieving the Current Location</a>. - Next, call the method -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>. - 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 -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(true)</a></code>: -</p> -<pre> - // 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); -</pre> -<p> - 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 -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#disconnect()">LocationClient.disconnect()</a></code>, - Location Services returns to using its internal location providers. To turn off mock mode while - the location client is connected, call -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockMode(boolean)">LocationClient.setMockMode(false)</a></code>. -</p> -<h2 id="SendMockLocations">Send Mock Locations</h2> -<p> - 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. -</p> -<p> - 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}: -</p> -<pre> - 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); -</pre> -<p> - In mock mode, to send a mock location to Location Services call the method -<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#setMockLocation(android.location.Location)">LocationClient.setMockLocation()</a></code>. - For example: -</p> -<pre> - mLocationClient.setMockLocation(testLocation); -</pre> -<p> - 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. -</p> -<!-- - Run the Mock Location Provider - --> -<h2 id="RunProvider">Run the Mock Location Provider App</h2> -<p> - 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. -</p> -<h3>Overview</h3> -<p> - 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. -</p> -<p> - 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: -</p> -<dl> - <dt> - Pause before test - </dt> - <dd> - 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. - </dd> - <dt> - Send interval - </dt> - <dd> - The number of seconds that the provider app waits before it sends another mock location to - Location Services. See the section <a href="#TestingTips">Testing Tips</a> to learn more - about setting the send interval. - </dd> - <dt> - Run once - </dt> - <dd> - 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}. - </dd> - <dt> - Run continuously - </dt> - <dd> - 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. - </dd> - <dt> - Stop test - </dt> - <dd> - 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. - </dd> -</dl> -<p> - Besides the options, the provider app has two status displays: -</p> -<dl> - <dt> - App status - </dt> - <dd> - Displays messages related to the lifecycle of the provider app. - </dd> - <dt> - Connection status - </dt> - <dd> - Displays messages related to the state of the location client connection. - </dd> -</dl> -<p> - 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. -</p> -<h3>Test using the mock location provider app</h3> -<p> - To test mock location data coming from the mock location provider app: -</p> -<ol> - <li> - Install the mock location provider app on a device that has Google Play services installed. - Location Services is part of Google Play services. - </li> - <li> - On the device, enable mock locations. To learn how to do this, see the topic - <a href="{@docRoot}tools/device.html#setting-up">Setting up a Device for Development</a>. - </li> - <li> - Start the provider app from the Launcher, then choose the options you want from the main - screen. - </li> - <li> - 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. - </li> - <li> - 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. - </li> - <li> - If the provider app is in the midst of a continuous test, you can switch back to real - locations by clicking <b>Stop test</b>. 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. - </li> - -</ol> -<h2 id="TestingTips">Testing Tips</h2> -<p> - The following sections contain tips for creating mock location data and using the data with a - mock location provider app. -</p> -<h3>Choosing a send interval</h3> -<p> - 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. -</p> -<h3>Simulating speed</h3> -<p> - 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. -</p> -<h3>Calculating location data</h3> -<p> - 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: -</p> -<dl> - <dt> - {@link android.location.Location#distanceBetween distanceBetween()} - </dt> - <dd> - A static method that calculates the distance between two points specified by latitude and - longitude. - </dd> - <dt> - {@link android.location.Location#distanceTo distanceTo()} - </dt> - <dd> - For a given {@link android.location.Location}, returns the distance to another - {@link android.location.Location}. - </dd> -</dl> -<h3>Geofence testing</h3> -<p> - 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. -</p> -<h3 id="TestData">Managing test data</h3> -<p> - 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: -</p> -<dl> - <dt> - XML - </dt> - <dd> - 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. - </dd> - <dt> - Server download - </dt> - <dd> - 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. - </dd> - <dt> - Recorded data - </dt> - <dd> - 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. - </dd> -</dl> |