Anyone have trouble with the Activity Recognition API in the recent Google Play Services update?
I have it implemented in an app. It was working perfectly fine before the 5.0 update. Now it returns IN_VEHICLE
when the user is walking or sitting still. :/
And doesn't return WALKING
, RUNNING
or ON_FOOT
at all.
Were there any changes to the Activity Recognition API I should be aware of?
Let me know if you need any more details.
The Activity Recognition API automatically detects activities by periodically reading short bursts of sensor data and processing them using machine learning models.
Google's 'Activity Recognition' Android permission can reveal to company the kind of physical activity that user is doing and the apps they're using on their Android device. The permission is embedded into the 'Other' category of app's permissions page, and there's no way to disable it.
Human activity recognition (HAR) can be referred to as the art of identifying and naming activities using Artificial Intelligence (AI) from the gathered activity raw data by utilizing various sources (so-called devices). Examples of such devices include wearable sensors (Pham et al.
The WALKING
and RUNNING
activities come in as secondary activities in a list (ActivityRecognitionResult.getProbableActivities()
), and you'll need to parse them out.
// Get the update
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
// Get the most probable activity from the list of activities in the update
DetectedActivity mostProbableActivity = result.getMostProbableActivity();
// Get the type of activity
int activityType = mostProbableActivity.getType();
if (activityType == DetectedActivity.ON_FOOT) {
DetectedActivity betterActivity = walkingOrRunning(result.getProbableActivities());
if (null != betterActivity)
mostProbableActivity = betterActivity;
}
private DetectedActivity walkingOrRunning(List<DetectedActivity> probableActivities) {
DetectedActivity myActivity = null;
int confidence = 0;
for (DetectedActivity activity : probableActivities) {
if (activity.getType() != DetectedActivity.RUNNING && activity.getType() != DetectedActivity.WALKING)
continue;
if (activity.getConfidence() > confidence)
myActivity = activity;
}
return myActivity;
}
I tested the above code this evening, both walking and running and it seemed to do fairly well. If you don't explicitly filter on only RUNNING
or WALKING
, you will likely get erroneous results.
Below is a full method for handling new activity results. I pulled this straight out of the sample app, and have been testing it for a couple of days with good results.
/**
* Called when a new activity detection update is available.
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent");
// Get a handle to the repository
mPrefs = getApplicationContext().getSharedPreferences(
Constants.SHARED_PREFERENCES, Context.MODE_PRIVATE);
// Get a date formatter, and catch errors in the returned timestamp
try {
mDateFormat = (SimpleDateFormat) DateFormat.getDateTimeInstance();
} catch (Exception e) {
Log.e(TAG, getString(R.string.date_format_error));
}
// Format the timestamp according to the pattern, then localize the pattern
mDateFormat.applyPattern(DATE_FORMAT_PATTERN);
mDateFormat.applyLocalizedPattern(mDateFormat.toLocalizedPattern());
// If the intent contains an update
if (ActivityRecognitionResult.hasResult(intent)) {
// Get the update
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
// Log the update
logActivityRecognitionResult(result);
// Get the most probable activity from the list of activities in the update
DetectedActivity mostProbableActivity = result.getMostProbableActivity();
// Get the confidence percentage for the most probable activity
int confidence = mostProbableActivity.getConfidence();
// Get the type of activity
int activityType = mostProbableActivity.getType();
mostProbableActivity.getVersionCode();
Log.d(TAG, "acitivty: " + getNameFromType(activityType));
if (confidence >= 50) {
String mode = getNameFromType(activityType);
if (activityType == DetectedActivity.ON_FOOT) {
DetectedActivity betterActivity = walkingOrRunning(result.getProbableActivities());
if (null != betterActivity)
mode = getNameFromType(betterActivity.getType());
}
sendNotification(mode);
}
}
}
private DetectedActivity walkingOrRunning(List<DetectedActivity> probableActivities) {
DetectedActivity myActivity = null;
int confidence = 0;
for (DetectedActivity activity : probableActivities) {
if (activity.getType() != DetectedActivity.RUNNING && activity.getType() != DetectedActivity.WALKING)
continue;
if (activity.getConfidence() > confidence)
myActivity = activity;
}
return myActivity;
}
/**
* 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 RIDE;
case DetectedActivity.RUNNING:
return RUN;
case DetectedActivity.WALKING:
return "walking";
case DetectedActivity.ON_FOOT:
return "on_foot";
case DetectedActivity.STILL:
return "still";
case DetectedActivity.TILTING:
return "tilting";
default:
return "unknown";
}
}
The main change is that ON_FOOT now returns a list of Detected Activities. Use getMostProbableActivities() instead now.
this solution gets walking or running when ON_foot get a list of Detected activities like this:
//Get the list from the result
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
ArrayList<DetectedActivity> activityList = new ArrayList<DetectedActivity>(result.getProbableActivities());
//Get the most probable activity
getMostProbableActivity(activityList);
Now pass your list to find the most probable activity like this:
private DetectedActivity getMostProbableActivity(List<DetectedActivity> detectedActivityList)
{
DetectedActivity result = null;
//Find the most probably activity in the list
for(DetectedActivity detectedActivity : detectedActivityList)
{
if(detectedActivity.getType() != DetectedActivity.ON_FOOT)
{
if(result == null)
{
result = detectedActivity;
}
else
{
if(result.getConfidence() < detectedActivity.getConfidence())
{
result = detectedActivity;
}
}
}
}
return result;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With