Mr. WTG
Mr. WTG

Reputation: 21

How do I control my own programmed kotlin wear os stopwatch app with the bluetooth headset buttons skip forward and skip backward?

I programmed a wear OS app in Kotlin (and Jetpack Compose). The app is a stopwatch app and therefore has a start function and a stop function. Previously, these functions were triggered using a touch button on the watch display (Samsung Galaxy Watch 4). Everything was going great until then!

Then I decided that the watch should be controlled with an external bluetooth device. For this I use a normal bluetooth headset (https://www.amazon.de/Kopfhörer-Bluetooth-magnetische-hengkexin-4-1-Sport-Kopfhörer-Rot/dp/B07F9TGVHH/ref=sr_1_90?crid=CJCJK5QU54BQ&dib=eyJ2IjoiMSJ9.1h3L28wCLsrovxp0ukTeFuRNooe6-FPTVR27vNrdiBKWES0oRBpTupcr7zXCbzmzJ-eR50Px6KDl60oWku7ykBCIkvONVyUHXYoocikgPLsPqjmqg7RA67lt8xKkmnuEni4CMoebqUzJigqWmv4MqZfKlEkxNMm-50_Z6lCVZls.iODpqxNOtLt8FbcNXg_-gewCpkhTdNyT1sUJqTrddjc&dib_tag=se&keywords=bluetooth+kopfhörer&qid=1721215831&sprefix=blu%2Caps%2C125&sr=8-90).

Unfortunately, my app doesn't respond when I press the bluetooth buttons, even though the watch connects to the headset. It doesn't work in the emulator either, although my MAC also connects to the headset. I've read through many similar questions about this and I've been trying to solve the problem for weeks, but unfortunately without success.

In the emulator I can control the clock using the MAC keyboard. But I can't get any further. Now I'm completely confused.

Here my code:

MainActivity.kt

package com.example.wearosstopwatch.presentation

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusTarget
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.wear.compose.material.Button
import androidx.wear.compose.material.ButtonDefaults
import androidx.wear.compose.material.Text
import com.example.wearosstopwatch.R

class MainActivity : ComponentActivity() {

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

        setContent {
            .
            .   
            .
val viewModel_1 = viewModel<StopWatchViewModel_A2>()
val timerState_1 by viewModel_1.timerState_1.collectAsStateWithLifecycle()
val stopWatchText_1 by viewModel_1.stopWatchText_1.collectAsStateWithLifecycle()


            Stopwatch_1(
                state = timerState_1,
                text = stopWatchText_1,
                onToggleRunning_1 = viewModel_1::toggleIsRunning_1,
                onReset_1 = viewModel_1::resteTimer_1,
                modifier = Modifier.padding(top = 10.dp)
            )
            Test(
                start = viewModel_1::start,
                stop = viewModel_1::stop
            )

        }


    }

}
@Composable
fun Test(start: ()-> Unit,
         stop: ()-> Unit) {
        .
        .
        .
        Box(
        Modifier
            .size(0.dp)
            .focusRequester(focusRequester)
            .focusTarget()
            .onKeyEvent {
                if (it.type == KeyEventType.KeyDown &&
it.key ==Key.MediaSkipBackward) {
                    start()
                }
                if (it.type == KeyEventType.KeyDown &&
it.key == Key.MediaSkipForward) {
                    stop()
                }
                                true
            }) {  }

    LaunchedEffect(Unit) {
        focusRequester.requestFocus()
    }
}
@Composable
private fun Stopwatch_1(
    state: TimerState_1,
    text: String,
    onToggleRunning_1: ()-> Unit,
    onReset_1: ()-> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = Modifier
            .padding(top = 10.dp)
            .padding(start = 80.dp)
    ){
        Text(
            text = text,
            fontSize = 10.sp,//Textgröße
            fontWeight = FontWeight.SemiBold,
            textAlign = TextAlign.Center
        )

    }
}

The start function and the stop function are defined in the file StopWatchViewModel_A2.kt.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-feature android:name="android.hardware.type.watch" />
    <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />


    <application

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

        <uses-library
            android:name="com.google.android.wearable"
            android:required="true"
            />

        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />
        
        <receiver android:name="android.support.v4.media.session.MediaButtonReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
        </receiver>
        
        <activity
            android:name=".presentation.MainActivity"
            android:exported="true"

            android:taskAffinity="">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"
                    />

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>

        </activity>

    </application>

</manifest>

My questions:

Why doesn't my app respond to the headset buttons even though the smartwatch (or MAC) connects to the headset?

Do I have to connect the headset again using a code?

My app should be controlled via headset buttons. So I tried to access the media button via code. But unfortunately without success. The app doesn't respond to the headset at all.

Upvotes: 2

Views: 85

Answers (0)

Related Questions