Reputation: 21
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" />
Main class with
initController()
called in the form of
mActivityTransitionController = ActivityTransitionController().also { it.initController(this@MainActivity) }
onClickEnableOrDisableActivityRecognition()
: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
MainActivity
's onStart()
MainActivity
's onStop()
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