Запуск таймера из события касания плитки в часах Android
У меня есть приложение для часов Android, созданное с помощью Jetpack Compose. Один из экранов приложения представляет собой таймер. Когда пользователь нажимает кнопку, запускается таймер. Все работает нормально. Я добавил плитку для приложения, которая должна запустить приложение, переключиться на страницу таймера и автоматически запустить таймер. Все происходит как надо, приложение запускается на нужную страницу, все события происходят, но таймер не запускается, и я не знаю почему. Мне действительно не помешала бы рука...
Код Tile... упрощенный...
@OptIn(ExperimentalHorologistApi::class)
class TimerRileRenderer(context: Context) : SingleTileLayoutRendrer<TimerTileState, Boolean(context) {
override fun renderTile(state: TimerTileState, deviceParameters: DeviceParameters): LayoutElement {
return timerTileLayout(
context,
deviceParameters,
state,
launchActivityClickable("start_button", startTimer())
)
}
}
private fun timerTileLayout(
context: Context,
deviceParameters: DeviceParameters,
state: TimerTileState,
buttonClickable: Clickable
) = PrimaryLayout.Builder(deviceParameters)
.setContent(
Column.Builder()
.setHorizontalAlignment(HORIZONTAL_ALIGNMENT_CENTER)
.addContent(
Chip.Builder(context, buttonClickable, deviceParameters)
.setIconContent(TimerTileRenderer.START_ICON)
.setPrimaryLabelContent("START")
.build()
)
.build()
)
.build()
Тогда мой кликабельный код...
fun launchActivityClickable(
clickableID: String,
androidActivity: ActionBuilders.AndroidActivity
) = ModifiersBuilders.Clickable.Builder()
.setId(clickableID)
.setOnClick(
ActionBuilder.LaunchAction.Builder()
.setAndroidActivity(androidActivity)
.build()
)
.build()
fun startTimer() = ActionBuilders.AndroidActivity.Builder()
.setActivity()
.addKeyToExtraMapping(
NotificationUtil.ACTION_START,
ActionBuilders.booleanExtra(true)
)
.addKeyToExtraMapping(
NotificationUtil.ACTION_OPEN_PAGE,
ActionBuilders.stringExtra(NotificationUtil.PAGE_EXTRA_TIMER)
)
.build()
internal fun ActionBuilders.AndroidActivity.Builder.setActivity(): ActionBuilders.AndroidActivity.Builder {
return setPackageName("mypackagenamehere")
.setClassName("mypackagenamehere.MainActivity")
}
Затем в моей MainActivity...
var openedPage: Int = 0
class MainActivity: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//... lots of other code...
val page = intent.extras?.getString(NotificationUtil.ACTION_OPEN_PAGE)
if(page != null) {
openedPage = when(page) {
NotificationUtil.PAGE_TIMER_EXTRA -> 1
NotificationUtil.PAGE_STATS_EXTRA -> 2
else -> 0
}
}
val startTimer = intent.extras?.getBoolean(NotificationUtil.ACTION_START) ?: false
if(startTimer) {
openedPage = 1
val intent = Intent(NotificationUtil.ACTION_START)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
setContent {
WearApp(timeViewModel) //that was defined earlier, but ommitted
}
}
}
@Composable
fun WearApp(model: TimeViewModel) {
//lots of code for things here...
WearAppTheme {
Scaffold(...) {
val maxPages = 5
val currentPage = remember {
derivedStateOf {
openedPage
}
}
val pagerState = rememberPagerState(initialPage = currentPage.value)
//code for other display things...
HorizontalPager(state = pagerState, count = maxPages) { page ->
openedPage = pagerState.currentPage
when(page) {
0 -> ProgressView(model)
1 -> TimerView(model)
//... all the other pages.
}
}
}
}
}
И, наконец, мой TimerView...
@Composable
fun TimerView(model: TimeViewModel) {
var currentTime by rememberSaveable {
mutableStateOf(0L)
}
var timerIsRunning by rememberSaveable {
mutableStateOf(false)
}
var timerStartedAt by rememberSaveable {
mutableStateOf(0L)
}
LaunchedEffect(key1 = currentTime, key2 = timerIsRunning) {
if(timerIsRunning) {
delay(1000L)
currentTime = SystemClock.elapsedRealtime() - timerStartedAt
}
}
val startReceiver = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(TAG, "Receive for start timer")
context?.let {
Log.d(TAG, "Context is set")
if(!timerIsRunning) {
Log.d(TAG, "Timer is NOT running")
timerStartedAt = SystemClock.elapsedRealtime()
timerIsRunning = true
}
}
}
}
LocalBroadcastManager.getInstance(LocalContext.current).registerReceiver(
startReceiver, IntentFilter(NotificationUtil.ACTION_START)
)
Column(...) {
Text(
getAttributedString((currentTime / 1000L).toInt())
)
//... lots of other code.
}
}
Теперь, когда я нажимаю на чип на плитке, мое приложение запускает страницу таймера, и я вижу в журналах...
Получить для запуска таймера
Контекст установлен
Таймер НЕ работает
Это означает, что приемник вещания получает трансляцию и устанавливает для переменной значение true. Позже в коде дисплея у меня есть кнопка, которая делает то же самое, и когда я нажимаю кнопку, таймер запускается правильно. Я могу это сказать, потому что этот текстовый элемент показывает время работы таймера. Я не уверен, почему таймер на самом деле не запускается при запуске с приемника вещания. Я думаю, что это как-то связано с LaunchedEffect, но я не уверен и не знаю, как это исправить.
Помощь будет принята с благодарностью, и я приношу извинения за длинный пост.