Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make changes to allow health connect to work on Android 9 and higher #4790

Merged
merged 10 commits into from
Nov 12, 2024

Conversation

dshokouhi
Copy link
Member

@dshokouhi dshokouhi commented Nov 8, 2024

Summary

Makes requestSensorUpdate and checkPermissions suspend functions to allow health connect to work on Android 9 and higher devices instead of just Android 14+. Some other methods were also converted to make the changes here easier to follow (I hope)

Screenshots

Link to pull request in Documentation repository

Documentation: home-assistant/companion.home-assistant#1135

Any other notes

@dshokouhi dshokouhi marked this pull request as draft November 8, 2024 00:10
@dshokouhi dshokouhi marked this pull request as ready for review November 8, 2024 01:07
@jpelgrom
Copy link
Member

jpelgrom commented Nov 8, 2024

Broadcast receivers are short lived and as I understand it may be killed even earlier if you launch (run work asynchronously) without indicating it to the system. Have you tested/encountered this with the app running in the background? Some nice discussions and a Kotlin extension function for it here: https://stackoverflow.com/questions/22741202/how-to-use-goasync-for-broadcastreceiver

@dshokouhi
Copy link
Member Author

Have you tested/encountered this with the app running in the background?

So have not enabled all sensors but so far working well about 7 hours in

image

image

image

health connect

image

@dshokouhi
Copy link
Member Author

device tracker also updating regularly during this time

image

image

@dshokouhi
Copy link
Member Author

24 hours later all enabled sensors including location tracking still working as expected

Copy link
Member

@jpelgrom jpelgrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're using MainScope().launch { } in a couple of places, but also a regular CoroutineScope in another one or two. Would it be worth it to introduce a helper function for it, or a custom scope like sensorWorkerScope (which is defined in the base class as = MainScope()) so it is easier to track and update later?

@dshokouhi
Copy link
Member Author

You're using MainScope().launch { } in a couple of places, but also a regular CoroutineScope in another one or two.

The reason for that is because we had it split up. Specifically the android auto connection sensors requires the CoroutineScope or it fails to update.

Would it be worth it to introduce a helper function for it, or a custom scope like sensorWorkerScope (which is defined in the base class as = MainScope()) so it is easier to track and update later?

if we were to do this it would need to be teh CoroutineScope

@jpelgrom
Copy link
Member

jpelgrom commented Nov 9, 2024

Specifically the android auto connection sensors requires the CoroutineScope or it fails to update

That's odd because you're still using the main/UI thread, only difference is the supervisor behavior which shouldn't matter.

@dshokouhi
Copy link
Member Author

Specifically the android auto connection sensors requires the CoroutineScope or it fails to update

That's odd because you're still using the main/UI thread, only difference is the supervisor behavior which shouldn't matter.

was failing due to the thread not calling Looper.prepare() dont have teh exact traceback now but that was the root cause

@jpelgrom
Copy link
Member

jpelgrom commented Nov 9, 2024

Testing this on Android 13, requesting Health Connect permissions seems to be broken (immediately denied) and tapping on settings in the snackbar crashes the app:

2024-11-09 22:23:42.768 23522-23522 AndroidRuntime          io....stant.companion.android.debug  E  FATAL EXCEPTION: main
                                                                                                    Process: io.homeassistant.companion.android.debug, PID: 23522
                                                                                                    android.content.ActivityNotFoundException: No Activity found to handle Intent { act=androidx.health.ACTION_REQUEST_PERMISSIONS pkg=io.homeassistant.companion.android.debug (has extras) }
                                                                                                    	at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2200)
                                                                                                    	at android.app.Instrumentation.execStartActivity(Instrumentation.java:1839)
                                                                                                    	at android.app.Activity.startActivityForResult(Activity.java:5507)
                                                                                                    	at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.kt:704)
                                                                                                    	at androidx.core.app.ActivityCompat.startActivityForResult(ActivityCompat.java:244)
                                                                                                    	at androidx.activity.ComponentActivity$activityResultRegistry$1.onLaunch(ComponentActivity.kt:225)
                                                                                                    	at androidx.activity.result.ActivityResultRegistry$register$3.launch(ActivityResultRegistry.kt:199)
                                                                                                    	at androidx.activity.compose.ActivityResultLauncherHolder.launch(ActivityResultRegistry.kt:154)
                                                                                                    	at androidx.activity.compose.ManagedActivityResultLauncher.launch(ActivityResultRegistry.kt:143)
                                                                                                    	at androidx.activity.result.ActivityResultLauncher.launch(ActivityResultLauncher.kt:37)
                                                                                                    	at io.homeassistant.companion.android.settings.sensor.views.SensorDetailViewKt$SensorDetailView$2$1$1.invokeSuspend(SensorDetailView.kt:119)
                                                                                                    	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                    	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:101)
                                                                                                    	at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
                                                                                                    	at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
                                                                                                    	at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run(AndroidUiDispatcher.android.kt:57)
                                                                                                    	at android.os.Handler.handleCallback(Handler.java:942)
                                                                                                    	at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                                                    	at android.os.Looper.loopOnce(Looper.java:201)
                                                                                                    	at android.os.Looper.loop(Looper.java:288)
                                                                                                    	at android.app.ActivityThread.main(ActivityThread.java:7918)
                                                                                                    	at java.lang.reflect.Method.invoke(Native Method)
                                                                                                    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
                                                                                                    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
                                                                                                    	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl@1008cfc, androidx.compose.runtime.BroadcastFrameClock@f18ff85, StandaloneCoroutine{Cancelling}@15d81da, AndroidUiDispatcher@afce60b]

@dshokouhi
Copy link
Member Author

Testing this on Android 13, requesting Health Connect permissions seems to be broken (immediately denied) and tapping on settings in the snackbar crashes the app:

thanks I was able to hunt down an older device will use that for testing and update this PR

@dshokouhi
Copy link
Member Author

Fixed, also the snackbar has been fixed too. Just an FYI these permissions are also subject to not being prompted multiple times if they are continuously denied.

Verified on my old Pixel 3 XL running android 12

@jpelgrom
Copy link
Member

also the snackbar has been fixed too

I'm not completely sure what you mean. For me, if I deny the permission twice tapping Settings on the snackbar will completely stop working (nothing happens/the system auto-denies).

Shouldn't the settings button link to an intent with ACTION_MANAGE_HEALTH_PERMISSIONS? That seems like it would always work.

@dshokouhi
Copy link
Member Author

I'm not completely sure what you mean. For me, if I deny the permission twice tapping Settings on the snackbar will completely stop working (nothing happens/the system auto-denies).

that should behave like the other sensors right?

Shouldn't the settings button link to an intent with ACTION_MANAGE_HEALTH_PERMISSIONS? That seems like it would always work.

thats only for android 14+, we can launch the HC app though

https://developer.android.com/reference/kotlin/androidx/health/connect/client/HealthConnectClient#ACTION_HEALTH_CONNECT_SETTINGS()

@jpelgrom
Copy link
Member

jpelgrom commented Nov 12, 2024

that should behave like the other sensors right?

Currently: no it doesn't, anything normal opens system settings for permissions which always works.

Ideally: yes it should behave like others and always work.

thats only for android 14+, we can launch the HC app though

https://developer.android.com/reference/kotlin/androidx/health/connect/client/HealthConnectClient#ACTION_HEALTH_CONNECT_SETTINGS()

Oops / that seems like a good option :) (need to put it in the SM to avoid the dependency in minimal)

Copy link
Member

@jpelgrom jpelgrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and seems to work as before during testing, but this should be in beta for a while to make sure there is no unexpected impact.

@dshokouhi
Copy link
Member Author

Looks good and seems to work as before during testing, but this should be in beta for a while to make sure there is no unexpected impact.

Agreed this needs beta time

@dshokouhi dshokouhi merged commit 5916092 into home-assistant:master Nov 12, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants