pxbn
pxbn

Reputation: 21

ActivityTransitions API not calling BroadcastReceiver on Samsung Deivce

I implemented the Activity Transitions API with a PendingIntent and a BroadcastReceiver as seen below. The code works perfectly fine on a Pixel 3a. However, on a Samsung A32 and Samsung S22 Pro, the Broadcast receiver is never reached, eventhough the ActivityRecognition.getClient(mainActivity).requestActivityTransitionUpdates() succeeds and enters the onSuccessListener().

After a lot of time spent reading through the internet, I wasn't able to find any further information. Neither concerning the Activity Transitions API, nor concerning such problems on Samsung devices (e.g. not raching BroadcastReceiver). Some people hint to disabling battery saving features from Samsung, but the App runs currently only in foreground in the MainActivty thread, therefore I don't think my problem is related to that. Other point out that, for example Huawai devices, need a diffferent permission than the in the android docs specified one for the Activity Transition API. So currently I'm specifing those three permissions (and check them run-time with ContextCompat.checkSelfPermission()):

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

Code

Main class with

class ActivityTransitionController() {
companion object {
internal val TRANSITION_RECEIVER_ACTION: String =
"MyMachineLearningStalkingProtection.TRANSITIONS_RECEIVER_ACTION"
}

    private var activityTrackingOn: Boolean = false
    
    private lateinit var activityTransitionList: List<ActivityTransition>
    private lateinit var mActivityTransitionPendingIntent: PendingIntent
    
    internal fun initController(mainActivity: MainActivity) {
        activityTrackingOn = false    
        activityTransitionList = buildTransitionList()
    
        val intent = Intent(TRANSITION_RECEIVER_ACTION)
        mActivityTransitionPendingIntent =
            PendingIntent.getBroadcast(mainActivity, 0, intent, PendingIntent.FLAG_MUTABLE)
    
        Utils.makeSnackBar("Activity Recognition initialized!", mainActivity)
    }
    
    internal fun onClickEnableOrDisableActivityRecognition(mainActivity: MainActivity) {
        if (activityTrackingOn) {
            disableActivityTransitions(mainActivity)
        } else {
            enableActivityTransitions(mainActivity)
        }
    }
    
    
    private fun buildTransitionList(): ArrayList<ActivityTransition> {
        val list = ArrayList<ActivityTransition>()
        list.add(
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.WALKING)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                .build()
        )
        list.add(
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.WALKING)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                .build()
        )
        list.add(
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.STILL)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER)
                .build()
        )
        list.add(
            ActivityTransition.Builder()
                .setActivityType(DetectedActivity.STILL)
                .setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT)
                .build()
        )
        return list
    }
    
    @SuppressLint("MissingPermission")
    internal fun disableActivityTransitions(mainActivity: MainActivity) {
        Log.d(Utils.MY_LOG_TAG, "disableActivityTransitions()")
        ActivityRecognition.getClient(mainActivity)
            .removeActivityTransitionUpdates(mActivityTransitionPendingIntent)
            .addOnSuccessListener {
                activityTrackingOn = false
                Utils.makeSnackBar("Transitions successfully unregistered.", mainActivity)
            }.addOnFailureListener {
                Utils.makeSnackBar("Transitions could NOT be unregistered.", mainActivity)
                Log.e(Utils.MY_LOG_TAG, "Transitions could not be unregistered $it")
            }
    }
    
    @SuppressLint("MissingPermission")
    internal fun enableActivityTransitions(mainActivity: MainActivity) {
        Log.d(Utils.MY_LOG_TAG, "enableActivityTransitions()")
    
        val request = ActivityTransitionRequest(activityTransitionList)
        ActivityRecognition.getClient(mainActivity)
            .requestActivityTransitionUpdates(request, mActivityTransitionPendingIntent)
            .addOnSuccessListener {
                Utils.makeSnackBar("Transitions Api was successfully registered", mainActivity)
                activityTrackingOn = true
            }
            .addOnFailureListener {
                Utils.makeSnackBar("Transitions Api could NOT be registered", mainActivity)
                Log.e(Utils.MY_LOG_TAG, "Transitions Api could NOT be registered. $it")
            }
    }

}

Boradcast receiver


class ActivityTransitionReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        val mainActivity = context as MainActivity
        val findViewById = mainActivity.findViewById<TextView>(R.id.txt_activity)
        val now = Calendar.getInstance().time.toString()
        val currentText = findViewById.text
        if (currentText.isEmpty()) {
            findViewById.text = "1##$now"
        } else {
            val split = currentText.split("##")
            val num = split[0].toInt() + 1
            findViewById.text = "$num##$now"
        }

        if (ActivityRecognitionResult.hasResult(intent)) {
            Log.d(Utils.MY_LOG_TAG, "RECOGNITION  called")
        }

        if (ActivityTransitionResult.hasResult(intent)) {
            Log.d(Utils.MY_LOG_TAG, "TRANSITION  called")
            val result = ActivityTransitionResult.extractResult(intent!!)
            for (event in result!!.transitionEvents) {
                val activityType = event.activityType
                val transitionType = event.transitionType
                val elapsedRealTimeNanos = event.elapsedRealTimeNanos
                val findViewById1 = mainActivity.findViewById<TextView>(R.id.txt_confidence)
                findViewById1.text ="${findViewById1.text} + $activityType + $transitionType"
            }
        }
    }
}

With this code, the Pixel 3a is able to detect my activities as soon as I call the onClickEnableOrDisableActivityRecognition() entrypoint. On the Samsung devices however, nothing happens, the requestActivityTransitionUpdates() succeeds, though the broadcast receiver ActivityTransitionReceiver is never reached. Do you guys have any idea why I expereience this behaviour? Maybe you experienced similar behaviour with a BroadcastReceiver and were able to fix it?

On a short side note: I also tested if the ActivityRecognition API is available on the Samsung devices using code which is equivalent as described in the docs https://developers.google.com/android/guides/api-client#check-api-availability which succeeded.

If something is unclear, do not hesitate to ask for clarification. Thanks in advance!

Upvotes: 2

Views: 236

Answers (0)

Related Questions