1

I'm trying to write a fitness companion watch app that would collect heart rate, and calories via HealthServices API, and send them to the device, where we display a workout. I've been following suggested examples: https://github.com/android/wear-os-samples/tree/main/AlwaysOnKotlin, https://github.com/android/health-samples/tree/2220ea6611770b56350d26502faefc28791f3cbd/health-services/ExerciseSample, and https://github.com/googlecodelabs/ongoing-activity .

I'm trying to achieve the following workflow:

  • Launch app on Wear device when X happens on the phone
  • Start exercise client on Wear
  • Send heart rate/calories update on a regular basis back to phone
  • Show summary screen, and stop exercise client when Y happens on the phone.

All of these work somewhat well until the watch goes into ambient mode. Then I run into the following problems:

  • When watch is in ambient mode, the capabilities client on the phone cannot locate watch, and tell it to start exercise. Nor can it tell it to stop exercise. What is a suggested workaround for this?

I use message client on phone to send message to the wearable. But nothing happens here, since the current node is empty.

currentNode?.also { nodeId ->
            val sendTask: Task<*>? =
                messageClient
                    ?.sendMessage(nodeId, WORKOUT_STATUS_MESSAGE_PATH, "START.toByteArray())
  • When trying to simulate ambient mode by pressing 'hand' on the watch simulator, the ambient mode listener does not actually trigger to tell me the right thing. The screen gets "stuck" instead of updating to what I want it to.

Code for the ambient mode in MainActivity (I'm still learning Compose, so right now Main activity is where it's at, to eliminate other Compose specific errors):

In Manifest:

<uses-permission android:name="android.permission.WAKE_LOCK" />

In Main Activity:

class MainActivity : FragmentActivity(), AmbientModeSupport.AmbientCallbackProvider {

...

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    ambientController = AmbientModeSupport.attach(this)

    setContent {
        val ambientEvent by mainViewModel.ambientEventFlow.collectAsState()
        StatsScreen(ambientEvent)
    }
        ...
}

override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback = AmbientModeCallback()

inner class AmbientModeCallback : AmbientModeSupport.AmbientCallback() {
    override fun onEnterAmbient(ambientDetails: Bundle) {
        Timber.e("ambient event: enter: $ambientDetails")
        mainViewModel.sendAmbientEvent(AmbientEvent.Enter(ambientDetails))
    }

    override fun onExitAmbient() {
        Timber.e("ambient event: exit")
        mainViewModel.sendAmbientEvent(AmbientEvent.Exit)
    }

    override fun onUpdateAmbient() {
        Timber.e("ambient event: update")
        mainViewModel.sendAmbientEvent(AmbientEvent.Update)
    }
}

I don't see anything printed in this callback, and then consequently, by StateScreen doesn't really do anything when the device enters in the ambient mode.

Ana
  • 67
  • 5
  • To follow up. If I navigate to Display - Always on, and turn that on, and then just imitate the ambient mode with Palm and Tilt in the simulator, the ambient works great. I'm using Wear OS Small API 30 emulator in Android studio. Not sure, if this is a problem on real devices as well. – Ana Feb 15 '23 at 18:06
  • I tried this on Pixel Watch, and if the user has Display -> Always on option turned off, the Wear OS goes black, and the ambient mode never triggers. – Ana Feb 22 '23 at 18:52

0 Answers0