Запуск таймера из события касания плитки в часах 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, но я не уверен и не знаю, как это исправить.

Помощь будет принята с благодарностью, и я приношу извинения за длинный пост.

0 ответов

Другие вопросы по тегам