| 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> |