somerandomusername
somerandomusername

Reputation: 2023

Can't figure out why my ActivityTransition example doesn't work with BroadcastReceiver

I have looked at multiple examples and implementations, I have no more ideas to check. I hope for outside perspective to see if I have missed something. Here is complete project on github for full source

It doesn't give me any errors or anything, it even shows that I have registered my request successfully. But I don't get any result in my BroadcastReceiver.

Manifest:

<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>


<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>


    <receiver
        android:exported="true"
        android:enabled="true"
        android:name="com.example.myapplication.ActivityTransitionBroadcastReceiver"
        android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
        <intent-filter>
            <action android:name="com.example.myapplication.ACTION_PROCESS_ACTIVITY_TRANSITIONS"/>
        </intent-filter>
    </receiver>

</application>

Main Activity:

    List<ActivityTransition> transitions = new ArrayList<>();

    transitions.add(
            new ActivityTransition.Builder()
                    .setActivityType(DetectedActivity.STILL)
                    .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                    .build());
    transitions.add(
            new ActivityTransition.Builder()
                    .setActivityType(DetectedActivity.STILL)
                    .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                    .build());
    transitions.add(
            new ActivityTransition.Builder()
                    .setActivityType(DetectedActivity.IN_VEHICLE)
                    .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                    .build());
    transitions.add(
            new ActivityTransition.Builder()
                    .setActivityType(DetectedActivity.IN_VEHICLE)
                    .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                    .build());


    ActivityTransitionRequest request = new ActivityTransitionRequest(transitions);

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


    PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent,
            PendingIntent.FLAG_CANCEL_CURRENT);

    Task<Void> task = ActivityRecognition.getClient(this.getApplicationContext())
            .requestActivityTransitionUpdates(request, pendingIntent);
    task.addOnSuccessListener(aVoid -> Log.i(TAG, "\n\nTransitions API was successfully registered.\n\n"))
            .addOnFailureListener(e -> Log.e(TAG, "Transitions API could not be registered: " + e));

Upvotes: 0

Views: 1960

Answers (4)

Lakpriya Senevirathna
Lakpriya Senevirathna

Reputation: 5109

Make sure you have added these lines in your Manifest:

<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

<receiver
    android:name="com.example.myapplication.activity.ActivityBroadcastReceiver"
    android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
    <intent-filter>
        <action android:name="com.example.myapplication.ACTION_PROCESS_ACTIVITY_TRANSITIONS"/>
    </intent-filter>
</receiver>

Upvotes: 0

Ivan Ardelian
Ivan Ardelian

Reputation: 134

First of all if you using compileSdkVersion 29 you need to request permission "Manifest.permission.ACTIVITY_RECOGNITION", so your MainActivity wiil be like this:

package com.example.myapplication;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.location.ActivityRecognition;
import com.google.android.gms.location.ActivityTransition;
import com.google.android.gms.location.ActivityTransitionRequest;
import com.google.android.gms.location.DetectedActivity;
import com.google.android.gms.tasks.Task;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "TransitionTest";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onResume(){
        super.onResume();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            checkIfAlreadyHavePermission();
        }else{
            requestForUpdates();
        }
    }

    private void checkIfAlreadyHavePermission() {
        int result = ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION);
        if (result == PackageManager.PERMISSION_GRANTED) {
            requestForUpdates();
        } else {
            requestPermissions();
        }
    }

    private void requestPermissions(){
        ActivityCompat.requestPermissions(MainActivity.this,
                new String[]{Manifest.permission.ACTIVITY_RECOGNITION},
                1);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                requestForUpdates();
            } else {
                Toast.makeText(MainActivity.this, "Recognition permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void requestForUpdates(){
        List<ActivityTransition> transitions = new ArrayList<>();

        transitions.add(
                new ActivityTransition.Builder()
                        .setActivityType(DetectedActivity.STILL)
                        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                        .build());
        transitions.add(
                new ActivityTransition.Builder()
                        .setActivityType(DetectedActivity.STILL)
                        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                        .build());
        transitions.add(
                new ActivityTransition.Builder()
                        .setActivityType(DetectedActivity.IN_VEHICLE)
                        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                        .build());
        transitions.add(
                new ActivityTransition.Builder()
                        .setActivityType(DetectedActivity.IN_VEHICLE)
                        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                        .build());
        transitions.add(
                new ActivityTransition.Builder()
                        .setActivityType(DetectedActivity.WALKING)
                        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                        .build());
        transitions.add(
                new ActivityTransition.Builder()
                        .setActivityType(DetectedActivity.ON_FOOT)
                        .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                        .build());

        ActivityTransitionRequest request = new ActivityTransitionRequest(transitions);

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


        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent,
                PendingIntent.FLAG_CANCEL_CURRENT);

        Task<Void> task = ActivityRecognition.getClient(getApplicationContext())
                .requestActivityTransitionUpdates(request, pendingIntent);
        task.addOnSuccessListener(aVoid -> Log.i(TAG, "\n\nTransitions API was successfully registered.\n\n"))
                .addOnFailureListener(e -> Log.e(TAG, "Transitions API could not be registered: " + e));
    }
    
}

in Manifest also try to add

<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

<receiver
    android:name="com.example.myapplication.ActivityBroadcastReceiver"
    android:permission="com.google.android.gms.permission.ACTIVITY_RECOGNITION">
    <intent-filter>
        <action android:name="com.example.myapplication.ACTION_PROCESS_ACTIVITY_TRANSITIONS"/>
    </intent-filter>
</receiver>

And for convenience create NotificationHelper class:

class NotificationHelper {

    static void sendNotification(Context context, String textContent) {

        Intent notificationIntent;
        PendingIntent pendingIntent;

        notificationIntent = new Intent(context, MainActivity.class);
        notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NO_HISTORY);
        pendingIntent = PendingIntent.getActivity(context, new Random().nextInt(100) + 1,
                notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context,"notif_ch_myapplication")
                .setContentTitle(context.getResources().getString(R.string.app_name))
                .setContentText(textContent)
                .setChannelId("notif_ch_myapplication")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
                .setContentIntent(pendingIntent);

        if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            mBuilder.setSmallIcon(R.mipmap.ic_launcher);
            mBuilder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher_background));
        } else {
            mBuilder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher_background));
            mBuilder.setSmallIcon(R.mipmap.ic_launcher);
        }

        android.app.NotificationManager notificationManager = (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            NotificationChannel channel = new NotificationChannel("notif_ch_myapplication",
                    context.getResources().getString(R.string.app_name),
                    android.app.NotificationManager.IMPORTANCE_DEFAULT);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
            }
        }
        if (notificationManager != null) {
            notificationManager.notify(new Random().nextInt(100) + 1, mBuilder.build());
        }
    }
}

and use it in ActivityTransitionBroadcastReceiver:

    public  class ActivityTransitionBroadcastReceiver extends BroadcastReceiver {

    public static final String INTENT_ACTION = "com.example.myapplication.ACTION_PROCESS_ACTIVITY_TRANSITIONS";

    @Override
    public  void onReceive(Context context, Intent intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            ActivityTransitionResult result = ActivityTransitionResult.extractResult(intent);
            for (ActivityTransitionEvent event : Objects.requireNonNull(result).getTransitionEvents()) {
                NotificationHelper.sendNotification(context, "Activity type:" + event.getActivityType()
                        + " Transition type: " + event.getTransitionType());
            }
        }
    }
}

In such way you will be able to check in without android studio.

And one more important thing: when you will install application - go outside for at least 10 minutes or you can shake the phone at least a minute. In my case I have received new activity transition event only in ~5-7 minutes.

Upvotes: 3

Pavlo Ostasha
Pavlo Ostasha

Reputation: 16699

Have you tried to register BroadcastReceiver in the Activity's onCreate or `onStart' method

class CustomBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //do some stuff here
        Log.d("Broadcast", "Success");
    }
}

CustomBroadcast broadcast = new CustomBroadcast();

LocalBroadcastManager.getInstance(this).registerReceiver(broadcast,
                    new IntentFilter("com.example.myapplication.ACTION_PROCESS_ACTIVITY_TRANSITIONS"));

Then in onStop unsubscribe:

LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcast);

I do it like that since after 26 it is quite problematic to use manifest declared ones.

Hope it helps.

Upvotes: 0

Ivan Ardelian
Ivan Ardelian

Reputation: 134

1) It can be caused by "apps that target the API level 26 or higher can no longer register broadcast receivers for implicit broadcasts in their manifest.". Please try to use IntentService but not BroadcastReceiver.

In manifest:

<service
            android:name=".DetectedActivitiesIntentService"
            android:exported="false" />

Service class:

public class DetectedActivityIntentService extends IntentService {

    protected static final String LOG_TAG = DetectedActivityIntentService.class.getSimpleName();

    public DetectedActivityIntentService() {
        super(LOG_TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (ActivityTransitionResult.hasResult(intent)) {
            ActivityTransitionResult result = ActivityTransitionResult.extractResult(intent);
        }
    }
}

Pending intent:

 private PendingIntent getActivityDetectionPendingIntent() {
        Intent intent = new Intent(App.getInstance().getApplicationContext(), DetectedActivityIntentService.class);
        return PendingIntent.getService(App.getInstance().getApplicationContext(), 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

And starting listen method:

 public void startListenMoveUpdates(List<ActivityTransition> transitions) {

        ActivityTransitionRequest request = new ActivityTransitionRequest(transitions);
        Task<Void> task = mActivityRecognitionClient.requestActivityTransitionUpdates(request, getActivityDetectionPendingIntent());

        task.addOnSuccessListener(
                result -> LogManager.saveMsg("Start listen move actions")
        );
        task.addOnFailureListener(
                e -> {
                    e.printStackTrace();
                    LogManager.saveMsg("Start listen move actions error");
                }
        );
    }

2) I would also recommend avoiding testing in buildings where the gps signal strength is poor.

Upvotes: 0

Related Questions