Parth Anjaria
Parth Anjaria

Reputation: 3971

Activity Transition API not working

I wish to use the new Activity transition API and after following the tutorial here I am not able to get the desired result.

This is the code I have for setting the activity transition I wish to detect :

public void setActivityTransitions() {
    transitionList = new ArrayList<>();
    ArrayList<Integer> activities = new ArrayList<>(Arrays.asList(
            DetectedActivity.STILL,
            DetectedActivity.WALKING,
            DetectedActivity.ON_FOOT,
            DetectedActivity.RUNNING,
            DetectedActivity.ON_BICYCLE,
            DetectedActivity.IN_VEHICLE));
    for (int activity :
            activities) {
        transitionList.add(new ActivityTransition.Builder()
                .setActivityType(activity)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER).build());

        transitionList.add(new ActivityTransition.Builder()
                .setActivityType(activity)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT).build());

    }

}

And then requesting the activity transition updates :

 ActivityTransitionRequest activityTransitionRequest = new ActivityTransitionRequest(transitionList);
        Intent intent = new Intent(context, ActivityDetectorTransitionService.class);
        intent.setAction("com.test.activityrecognition.START_ACTIVITY_TRANSITION_DETECTION_ALARM");
        PendingIntent pendingIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        Task<Void> task = ActivityRecognition.getClient(context).requestActivityTransitionUpdates(activityTransitionRequest, pendingIntent);
        task.addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void result) {
                System.out.println("onSuccess");
            }
        });
        task.addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                e.printStackTrace();
                System.out.println("onFailure");
            }
        });

And this is the broadcastreceiver :

    public class ActivityDetectorTransitionService extends BroadcastReceiver {
    private static final String TAG = "ActivityDetectorTransitionService";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            ActivityTransitionResult activityTransitionResult = ActivityTransitionResult.extractResult(intent);
            ActivityDetectorTransitionAPI.getInstance().handleActivityRecognitionResult(activityTransitionResult);
        }
    }
}

(The name has service in it cause initially I had kept it service but still not working.)

and in manifest :

<receiver
    android:name=".tracking.activityrecognition.ActivityDetectorTransitionService">
    <intent-filter>
        <action android:name="com.test.activityrecognition.START_ACTIVITY_TRANSITION_DETECTION_ALARM"/>
    </intent-filter>
</receiver>

Upvotes: 5

Views: 6110

Answers (5)

Sean Barbeau
Sean Barbeau

Reputation: 11756

At some point it seems that the following intent for an explicit class stopped working (or maybe never worked?):

Intent intent = new Intent(context, ActivityDetectorTransitionService.class);

Instead, I created the intent by passing in the action in the intent constructor, as follows:

Intent intent = new Intent("com.test.activityrecognition.START_ACTIVITY_TRANSITION_DETECTION_ALARM");

...and then I started to get callbacks successfully from the Activity Transition API.

Note that this approach is used in the latest codelab as well: https://github.com/googlecodelabs/activity_transitionapi-codelab/blob/master/complete/src/main/java/com/google/example/android/basicactivityrecognitiontransitionsample/MainActivity.java#L134

Upvotes: 0

solamour
solamour

Reputation: 3194

I also tried the aforementioned Codelab tutorial, as well as a few other examples, but none of them worked; BroadcastReceiver.onReceive() was never called, no matter how I set it up.

What did work was to use requestActivityUpdates() instead of requestActivityTransitionUpdates(). According to the document, requestActivityTransitionUpdates() is a better choice, because it improves accuracy and consumes less power, but it's not better choice for me if it doesn't do what it's supposed to do. Here is the summary on what I did.

[AndroidManifest.xml]
<receiver
    android:name=".TransitionUpdatesBroadcastReceiver"
    android:enabled="true"
    android:exported="false">
    <intent-filter>
        <action android:name="TRANSITION_UPDATES" />
    </intent-filter>
</receiver>

// This is in your Activity/Fragment.
private val pendingIntent: PendingIntent by lazy {
    val intent = Intent(context, TransitionUpdatesBroadcastReceiver::class.java)
    intent.action = TRANSITION_UPDATES
    PendingIntent.getBroadcast(context, 0, intent,
        PendingIntent.FLAG_UPDATE_CURRENT)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ActivityRecognition.getClient(context)
        .requestActivityUpdates(1_000, pendingIntent)    <-- Here.
}

override fun onDestroy() {
    super.onDestroy()
    ActivityRecognition.getClient(context)
        .removeActivityUpdates(pendingIntent)
}

class TransitionUpdatesBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // Do what you need to do with intent.
    }
}

Upvotes: 2

Mauro Banze
Mauro Banze

Reputation: 2248

This is an old post, but this answer might help someone.

Keep in mind that latency might actually be the problem, as it was in my case. I thought my implementation wasn't working, but in reality it was. The Activity Transitions API just has a huge delay of about 1 minute to notify you of transitions. So try walking around or driving for a few minutes to start receiving notifications.

Upvotes: 5

Mr. Vonkey
Mr. Vonkey

Reputation: 101

You are using PendingIntent.getService() in combination with a BroadcastReceiver.

To receive pending intents with a BroadcastReceiver you have to retrieve the PendingIntent instance using PendingIntent.getBroadcast(). The corresponding developer guide concerning intents and intent filters can be found here.

Since Android 8 there are several background service limitations. Using an IntentService only works when the app is in foreground. To receive activity transition updates after the app was closed you even have to use a BroadcastReceiver. For this purpose the BroadcastReceiver has to be registered in the application manifest with the corresponding permission, as Jan Maděra already mentioned.

   <receiver android:name="com.mypackage.ActivityTransitionBroadcastReceiver"
       android:exported="false"
       android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
       <intent-filter>
           <action android:name="com.mypackage.ACTION_PROCESS_ACTIVITY_TRANSITIONS" />
       </intent-filter>
   </receiver>

Furthermore onReceive() should only respond to your specific action, since intent filters are not guaranteed to be exclusive.

public class ActivityTransitionBroadcastReceiver extends BroadcastReceiver {

    public static final String INTENT_ACTION = "com.mypackage" +
                    ".ACTION_PROCESS_ACTIVITY_TRANSITIONS";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && INTENT_ACTION.equals(intent.getAction())) {
            if (ActivityTransitionResult.hasResult(intent)) {
                ActivityTransitionResult intentResult = ActivityTransitionResult
                        .extractResult(intent);
                // handle activity transition result ...
            }
        }
    }
}

Requesting activity transition updates using PendingIntent.getBroadcast():

ActivityTransitionRequest request = new ActivityTransitionRequest(transitionList);

Intent intent = new Intent(context, ActivityTransitionBroadcastReceiver.class);
intent.setAction(ActivityTransitionBroadcastReceiver.INTENT_ACTION);

PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
        PendingIntent.FLAG_UPDATE_CURRENT);

Task<Void> task = ActivityRecognition.getClient(context)
        .requestActivityTransitionUpdates(request, pendingIntent);

Be aware that activity transition updates can be received delayed. This depends on the device and can also be affected by power management restrictions.

Upvotes: 10

Jan Maděra
Jan Maděra

Reputation: 61

I faced similar issue but helped me add receiver to the manifest

    <receiver
    android:name=".service.ActivityTransitionReceiver"
    android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION"
    android:exported="false" />

Upvotes: 3

Related Questions