Blodht
Blodht

Reputation: 1

How to retrieve data from Health Services on Canvas Renderer?

I'm trying to develop my skills in Kotlin and Android development by creating a watch face project. However, I've run into some difficulties with how to obtain heart rate and step data within a watch face.

I'm trying to use the PassiveListenerService to get this information from the smartwatch, but for some reason, I'm unable to retrieve the heart rate data. It seems that the onNewDataPointsReceived() function is never called, so I believe the problem is related to my listener, but I can't seem to identify it.

Here is my code:

AndroidManifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.android.wearable.alpha">

    <uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA" />
    <uses-permission android:name="com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA_PRIVILEGED" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.BODY_SENSORS"/>
    <uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND"/>
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="com.google.android.wearable.healthservices.permission.PASSIVE_DATA_BINDING"/>

    <queries>
        <package android:name="com.google.android.wearable.healthservices" />
    </queries>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/Theme.WatchFace">

        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />

        <service
            android:name=".AnalogWatchFaceService"
            android:directBootAware="true"
            android:exported="true"
            android:label="@string/analog_watch_face_name"
            android:permission="android.permission.BIND_WALLPAPER">
            <intent-filter>
                <action android:name="android.service.wallpaper.WallpaperService" />
                <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
            </intent-filter>

            <meta-data
                android:name="com.google.android.wearable.watchface.preview"
                android:resource="@drawable/watch_preview" />
            <meta-data
                android:name="com.google.android.wearable.watchface.preview_circular"
                android:resource="@drawable/watch_preview" />
            <meta-data
                android:name="android.service.wallpaper"
                android:resource="@xml/watch_face" />
            <meta-data
                android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
                android:value="androidx.wear.watchface.editor.action.WATCH_FACE_EDITOR" />

            <meta-data
                android:name="com.google.android.wearable.watchface.companionBuiltinConfigurationEnabled"
                android:value="true" />
        </service>


        <activity
            android:name=".editor.WatchFaceConfigActivity"
            android:exported="true"
            android:label="@string/title_activity_watch_face_config">

            <intent-filter>
                <action android:name="androidx.wear.watchface.editor.action.WATCH_FACE_EDITOR" />

                <category android:name="com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>


    </application>
</manifest>

CanvasRenderer:

class AnalogWatchCanvasRenderer(
    private val context: Context,
    surfaceHolder: SurfaceHolder,
    watchState: WatchState,
    private val complicationSlotsManager: ComplicationSlotsManager,
    currentUserStyleRepository: CurrentUserStyleRepository,
    canvasType: Int
) : Renderer.CanvasRenderer2<AnalogWatchCanvasRenderer.AnalogSharedAssets>(
    surfaceHolder,
    currentUserStyleRepository,
    watchState,
    canvasType,
    FRAME_PERIOD_MS_DEFAULT,
    clearWithBackgroundTintBeforeRenderingHighlightLayer = false
) {
private val healthClient = HealthServices.getClient(context)
    private val passiveMonitoringClient = healthClient.passiveMonitoringClient
    object HeartRate {
        private var bpm = 0.0f;

        fun setBpm(newBpm: Float) {
            bpm = newBpm
        }
        fun getBpm(): Float {
            return bpm
        }
    }

    class PassiveDataService : PassiveListenerService() { // Listener Service
        init {
            Log.d("HEARTBEAT", "STARTED")
        }
        override fun onNewDataPointsReceived(dataPoints: DataPointContainer) {
            val data = dataPoints.getData(DataType.HEART_RATE_BPM)
            if (data.isNotEmpty()) {
                HeartRate.setBpm(data.last().value.toFloat())
                Log.d("HEARTBEAT", "value updated")
            }
        }
    }
    init {
        scope.launch {
            currentUserStyleRepository.userStyle.collect { userStyle ->
                updateWatchFaceData(userStyle)
            }
        }

        val passiveListenerConfig = PassiveListenerConfig.builder()
            .setDataTypes(setOf(DataType.HEART_RATE_BPM))
            .build()

        passiveMonitoringClient.setPassiveListenerServiceAsync(
            PassiveDataService::class.java,
            passiveListenerConfig
        )
    }

    override fun render(
        canvas: Canvas,
        bounds: Rect,
        zonedDateTime: ZonedDateTime,
        sharedAssets: AnalogSharedAssets
    ) {
              canvas.drawText("Heart: " + HeartRate.getBpm().toString(), bounds.exactCenterX(), bounds.exactCenterY(), clockPaint)
    }

Upvotes: 0

Views: 84

Answers (0)

Related Questions