Google Play Services includes features to monitor user activity via the ActivityRecognitionClient
. The user activity tracking service is a low-power method of receiving regular updates about what a user is doing. The service periodically monitors local sensor data on the device in short bursts rather than relying on high-power means like web services or GPS.
Using this API, applications will receive updates for one of the following events:
IN_VEHICLE
. The user is likely driving or riding in a vehicle, such as a car, bus, or train.ON_BICYCLE
. The user is likely on a bicycle.ON_FOOT
. The user is likely walking or running.STILL
. The user, or at least the device, is currently sitting still.TILTING
. The device has recently been tilted. This can happen when the device is picked up from rest or an orientation change occurs.UNKNOWN
. There is not enough data to determine with significant confidence what the user is currently doing.When working with ActivityRecognitionClient
, an application initiates periodic updates by calling requestActivityUpdates()
. The parameters this method takes define the frequency of updates to the application and a PendingIntent
that will be used to trigger each event.
Each event includes a list of DetectedActivity
instances, which wrap the activity type (one of the options described previously) and the level of confidence the service has in its prediction. The list is sorted by confidence, so the most probable user activity is first.
The first thing you need to open the build.gradle file, and import Play Services.
compile 'com.google.android.gms:play-services:10.0.1'
Next, create a new class, name it ActivityRecognizedService
, and have it extend Service. When Google Play Services returns the user's activity, it will be sent to this Service
. This will allow you to perform your application logic in the background as the user goes about their day.
public class ActivityRecognizedService extends Service { public ActivityRecognizedService() {} public static String LOCAL_BROADCAST_NAME = "LOCAL_ACT_RECOGNITION"; public static String LOCAL_BROADCAST_EXTRA = "RESULT"; @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not yet implemented"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if(ActivityRecognitionResult.hasResult(intent)) { ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent); handleDetectedActivities( result.getProbableActivities() ); } return super.onStartCommand(intent, flags, startId); } private void handleDetectedActivities(List<DetectedActivity> probableActivities) { StringBuilder str = new StringBuilder(); for(DetectedActivity activity : probableActivities) { switch( activity.getType() ) { case DetectedActivity.IN_VEHICLE: { str.append("In Vehicle: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.ON_BICYCLE: { str.append("On Bicycle: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.ON_FOOT: { str.append("On Foot: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.RUNNING: { str.append("Running: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.STILL: { str.append("Still: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.TILTING: { str.append("Tilting: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.WALKING: { str.append("Walking: " + activity.getConfidence() + "\n"); break; } case DetectedActivity.UNKNOWN: { str.append("Unknown: " + activity.getConfidence() + "\n"); break; } } } Intent intent = new Intent(LOCAL_BROADCAST_NAME); intent.putExtra(LOCAL_BROADCAST_EXTRA, str.toString()); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } }
To finish setting up, open AndroidManifest.xml. You need to declare ActivityRecognizedService
and include the com.google.android.gms.permission.ACTIVITY_RECOGNITION
permission for your application.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="proft.me.activityrecognation"> <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" /> <application android:allowBackup="true" android:name="android.support.multidex.MultiDexApplication" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".ActivityRecognizedService" /> </application> </manifest>
In order to use Google Play Services, you first need to connect to them. Start by opening MainActivity.java and implement the ConnectionCallbacks
and OnConnectionFailedListener
interfaces. You also need to create a member variable of type GoogleApiClient
to keep a reference to the API client.
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener { public GoogleApiClient apiClient; BroadcastReceiver myReceiver; TextView tv; int TIMER = 3000; // 3 sec @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); apiClient = new GoogleApiClient.Builder(this) .addApi(ActivityRecognition.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); apiClient.connect(); myReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String message = intent.getStringExtra(ActivityRecognizedService.LOCAL_BROADCAST_EXTRA); tv.setText(message); } }; // verify Play Services is active and up-to-date checkGooglePlayServicesAvailable(this); } @Override public void onConnected(@Nullable Bundle bundle) { Intent intent = new Intent( this, ActivityRecognizedService.class ); PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(apiClient, TIMER, pendingIntent); } @Override public void onConnectionSuspended(int i) {} @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {} @Override protected void onResume() { super.onResume(); LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter(ActivityRecognizedService.LOCAL_BROADCAST_NAME)); } @Override protected void onPause() { LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver); super.onPause(); } public boolean checkGooglePlayServicesAvailable(Activity activity) { int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance(); int result = googleAPI.isGooglePlayServicesAvailable(activity); if(result != ConnectionResult.SUCCESS) { if(googleAPI.isUserResolvableError(result)) { googleAPI.getErrorDialog(activity, result, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } return false; } return true; } }
After implementing the required interfaces for the GoogleApiClient
, you can initialize the client and connect to Google Play Services in onCreate()
by requesting the ActivityRecognition.API
and associating your listeners with the GoogleApiClient
instance.
Once the GoogleApiClient
instance has connected, onConnected()
is called. When this happens, you need to create a PendingIntent
that goes to the Service
you created earlier, and pass it to the ActivityRecognitionApi
. You also need to set an interval for how often the API should check the user's activity. For this sample application, we use a value of 3000, or three seconds, though in an actual application you may want to check less frequently to conserve power.
At this point, your application should attempt to recognize the user's activity every three seconds and send that data to ActivityRecognizedService
.
In the onStartCommand()
method of ActivityRecognizedService
, the first thing you do is validate that the received Intent
contains activity recognition data. If it does, then you can extract the ActivityRecognitionResult
from the Intent
to see what activities your user might be performing. You can retrieve a list of the possible activities by calling getProbableActivities()
on the ActivityRecognitionResult
object.
For this sample application, you simply build a string with all activities that have been detected and display how confident Google Play Services is that the user is performing that activity by calling getConfidence()
on a DetectedActivity
instance. If a confidence is 75 or higher, then it's safe to assume that the user is performing that activity.
Result