Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt +10 −11 Original line number Diff line number Diff line Loading @@ -21,9 +21,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.parameterizeSceneContainerFlag import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataManager import com.android.systemui.media.controls.shared.model.MediaData Loading @@ -47,7 +48,8 @@ import platform.test.runner.parameterized.Parameters class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val mediaControlChipInteractor by lazy { kosmos.mediaControlChipInteractor } private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipViewModel } private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipViewModelFactory.create() } @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener> companion object { Loading @@ -62,6 +64,7 @@ class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCas fun setUp() { MockitoAnnotations.initMocks(this) mediaControlChipInteractor.initialize() kosmos.underTest.activateIn(kosmos.testScope) } init { Loading @@ -71,7 +74,7 @@ class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCas @Test fun chip_noActiveMedia_IsHidden() = kosmos.runTest { val chip by collectLastValue(underTest.chip) val chip = underTest.chip assertThat(chip).isInstanceOf(PopupChipModel.Hidden::class.java) } Loading @@ -79,30 +82,26 @@ class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCas @Test fun chip_activeMedia_IsShown() = kosmos.runTest { val chip by collectLastValue(underTest.chip) val userMedia = MediaData(active = true, song = "test") updateMedia(userMedia) assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java) assertThat(underTest.chip).isInstanceOf(PopupChipModel.Shown::class.java) } @Test fun chip_songNameChanges_chipTextUpdated() = kosmos.runTest { val chip by collectLastValue(underTest.chip) val initialSongName = "Initial Song" val newSongName = "New Song" val userMedia = MediaData(active = true, song = initialSongName) updateMedia(userMedia) assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java) assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName) assertThat(underTest.chip).isInstanceOf(PopupChipModel.Shown::class.java) assertThat((underTest.chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName) val updatedUserMedia = userMedia.copy(song = newSongName) updateMedia(updatedUserMedia) assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName) assertThat((underTest.chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName) } private fun updateMedia(mediaData: MediaData) { Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.featurepods.media.ui.viewmodel import android.platform.test.annotations.EnableFlags import androidx.compose.runtime.snapshots.Snapshot import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @EnableFlags(StatusBarPopupChips.FLAG_NAME) @RunWith(AndroidJUnit4::class) class StatusBarPopupChipsViewModelTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val underTest = kosmos.statusBarPopupChipsViewModelFactory.create() @Before fun setUp() { underTest.activateIn(kosmos.testScope) } @Test fun shownPopupChips_allHidden_empty() = kosmos.runTest { val shownPopupChips = underTest.shownPopupChips assertThat(shownPopupChips).isEmpty() } @Test fun shownPopupChips_activeMedia_restHidden_mediaControlChipShown() = kosmos.runTest { val shownPopupChips = underTest.shownPopupChips val userMedia = MediaData(active = true, song = "test") val instanceId = userMedia.instanceId mediaFilterRepository.addSelectedUserMediaEntry(userMedia) mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) Snapshot.takeSnapshot { assertThat(shownPopupChips).hasSize(1) assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl) } } @Test fun shownPopupChips_mediaChipToggled_popupShown() = kosmos.runTest { val shownPopupChips = underTest.shownPopupChips val userMedia = MediaData(active = true, song = "test") val instanceId = userMedia.instanceId mediaFilterRepository.addSelectedUserMediaEntry(userMedia) mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) Snapshot.takeSnapshot { assertThat(shownPopupChips).hasSize(1) val mediaChip = shownPopupChips.first() assertThat(mediaChip.isPopupShown).isFalse() mediaChip.showPopup.invoke() assertThat(shownPopupChips.first().isPopupShown).isTrue() } } } packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt +28 −23 Original line number Diff line number Diff line Loading @@ -17,52 +17,52 @@ package com.android.systemui.statusbar.featurepods.media.ui.viewmodel import android.content.Context import androidx.compose.runtime.getValue import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.statusbar.featurepods.media.domain.interactor.MediaControlChipInteractor import com.android.systemui.statusbar.featurepods.media.shared.model.MediaControlChipModel import com.android.systemui.statusbar.featurepods.popups.shared.model.HoverBehavior import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipViewModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** * [StatusBarPopupChipViewModel] for a media control chip in the status bar. This view model is * responsible for converting the [MediaControlChipModel] to a [PopupChipModel] that can be used to * display a media control chip. */ @SysUISingleton class MediaControlChipViewModel @Inject @AssistedInject constructor( @Background private val backgroundScope: CoroutineScope, @Application private val applicationContext: Context, mediaControlChipInteractor: MediaControlChipInteractor, ) : StatusBarPopupChipViewModel { ) : StatusBarPopupChipViewModel, ExclusiveActivatable() { private val hydrator: Hydrator = Hydrator("MediaControlChipViewModel.hydrator") /** * A [StateFlow] of the current [PopupChipModel]. This flow emits a new [PopupChipModel] * A snapshot [State] of the current [PopupChipModel]. This emits a new [PopupChipModel] * whenever the underlying [MediaControlChipModel] changes. */ override val chip: StateFlow<PopupChipModel> = mediaControlChipInteractor.mediaControlChipModel .map { mediaControlChipModel -> toPopupChipModel(mediaControlChipModel) } .stateIn( backgroundScope, SharingStarted.WhileSubscribed(), PopupChipModel.Hidden(PopupChipId.MediaControl), override val chip: PopupChipModel by hydrator.hydratedStateOf( traceName = "chip", initialValue = PopupChipModel.Hidden(PopupChipId.MediaControl), source = mediaControlChipInteractor.mediaControlChipModel.map { model -> toPopupChipModel(model) }, ) override suspend fun onActivated(): Nothing { hydrator.activate() } private fun toPopupChipModel(model: MediaControlChipModel?): PopupChipModel { if (model == null || model.songName.isNullOrEmpty()) { return PopupChipModel.Hidden(PopupChipId.MediaControl) Loading Loading @@ -96,7 +96,12 @@ constructor( return HoverBehavior.Button( icon = Icon.Loaded(drawable = icon, contentDescription = contentDescription), onIconPressed = { backgroundScope.launch { action.run() } }, onIconPressed = { action.run() }, ) } @AssistedFactory interface Factory { fun create(): MediaControlChipViewModel } } packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt +4 −4 Original line number Diff line number Diff line Loading @@ -16,14 +16,14 @@ package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel import com.android.systemui.lifecycle.Activatable import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel import kotlinx.coroutines.flow.StateFlow /** * Interface for a view model that knows the display requirements for a single type of status bar * popup chip. */ interface StatusBarPopupChipViewModel { /** A flow modeling the popup chip that should be shown (or not shown). */ val chip: StateFlow<PopupChipModel> interface StatusBarPopupChipViewModel : Activatable { /** A snapshot [State] modeling the popup chip that should be shown (or not shown). */ val chip: PopupChipModel } packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt +8 −10 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId Loading @@ -36,18 +35,17 @@ import kotlinx.coroutines.flow.map */ class StatusBarPopupChipsViewModel @AssistedInject constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() { private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator") constructor(mediaControlChipFactory: MediaControlChipViewModel.Factory) : ExclusiveActivatable() { private val mediaControlChip by lazy { mediaControlChipFactory.create() } /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */ private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null) private val incomingPopupChipBundle: PopupChipBundle by hydrator.hydratedStateOf( traceName = "incomingPopupChipBundle", initialValue = PopupChipBundle(), source = mediaControlChip.chip.map { chip -> PopupChipBundle(media = chip) }, ) private val incomingPopupChipBundle: PopupChipBundle by derivedStateOf { val mediaChip = mediaControlChip.chip PopupChipBundle(media = mediaChip) } val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf { if (StatusBarPopupChips.isEnabled) { Loading @@ -66,7 +64,7 @@ constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable( } override suspend fun onActivated(): Nothing { hydrator.activate() mediaControlChip.activate() } private data class PopupChipBundle( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt +10 −11 Original line number Diff line number Diff line Loading @@ -21,9 +21,10 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.parameterizeSceneContainerFlag import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataManager import com.android.systemui.media.controls.shared.model.MediaData Loading @@ -47,7 +48,8 @@ import platform.test.runner.parameterized.Parameters class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val mediaControlChipInteractor by lazy { kosmos.mediaControlChipInteractor } private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipViewModel } private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipViewModelFactory.create() } @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener> companion object { Loading @@ -62,6 +64,7 @@ class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCas fun setUp() { MockitoAnnotations.initMocks(this) mediaControlChipInteractor.initialize() kosmos.underTest.activateIn(kosmos.testScope) } init { Loading @@ -71,7 +74,7 @@ class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCas @Test fun chip_noActiveMedia_IsHidden() = kosmos.runTest { val chip by collectLastValue(underTest.chip) val chip = underTest.chip assertThat(chip).isInstanceOf(PopupChipModel.Hidden::class.java) } Loading @@ -79,30 +82,26 @@ class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCas @Test fun chip_activeMedia_IsShown() = kosmos.runTest { val chip by collectLastValue(underTest.chip) val userMedia = MediaData(active = true, song = "test") updateMedia(userMedia) assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java) assertThat(underTest.chip).isInstanceOf(PopupChipModel.Shown::class.java) } @Test fun chip_songNameChanges_chipTextUpdated() = kosmos.runTest { val chip by collectLastValue(underTest.chip) val initialSongName = "Initial Song" val newSongName = "New Song" val userMedia = MediaData(active = true, song = initialSongName) updateMedia(userMedia) assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java) assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName) assertThat(underTest.chip).isInstanceOf(PopupChipModel.Shown::class.java) assertThat((underTest.chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName) val updatedUserMedia = userMedia.copy(song = newSongName) updateMedia(updatedUserMedia) assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName) assertThat((underTest.chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName) } private fun updateMedia(mediaData: MediaData) { Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.statusbar.featurepods.media.ui.viewmodel import android.platform.test.annotations.EnableFlags import androidx.compose.runtime.snapshots.Snapshot import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @SmallTest @EnableFlags(StatusBarPopupChips.FLAG_NAME) @RunWith(AndroidJUnit4::class) class StatusBarPopupChipsViewModelTest : SysuiTestCase() { private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val underTest = kosmos.statusBarPopupChipsViewModelFactory.create() @Before fun setUp() { underTest.activateIn(kosmos.testScope) } @Test fun shownPopupChips_allHidden_empty() = kosmos.runTest { val shownPopupChips = underTest.shownPopupChips assertThat(shownPopupChips).isEmpty() } @Test fun shownPopupChips_activeMedia_restHidden_mediaControlChipShown() = kosmos.runTest { val shownPopupChips = underTest.shownPopupChips val userMedia = MediaData(active = true, song = "test") val instanceId = userMedia.instanceId mediaFilterRepository.addSelectedUserMediaEntry(userMedia) mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) Snapshot.takeSnapshot { assertThat(shownPopupChips).hasSize(1) assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl) } } @Test fun shownPopupChips_mediaChipToggled_popupShown() = kosmos.runTest { val shownPopupChips = underTest.shownPopupChips val userMedia = MediaData(active = true, song = "test") val instanceId = userMedia.instanceId mediaFilterRepository.addSelectedUserMediaEntry(userMedia) mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) Snapshot.takeSnapshot { assertThat(shownPopupChips).hasSize(1) val mediaChip = shownPopupChips.first() assertThat(mediaChip.isPopupShown).isFalse() mediaChip.showPopup.invoke() assertThat(shownPopupChips.first().isPopupShown).isTrue() } } }
packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt +28 −23 Original line number Diff line number Diff line Loading @@ -17,52 +17,52 @@ package com.android.systemui.statusbar.featurepods.media.ui.viewmodel import android.content.Context import androidx.compose.runtime.getValue import com.android.systemui.common.shared.model.ContentDescription import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.statusbar.featurepods.media.domain.interactor.MediaControlChipInteractor import com.android.systemui.statusbar.featurepods.media.shared.model.MediaControlChipModel import com.android.systemui.statusbar.featurepods.popups.shared.model.HoverBehavior import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipViewModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** * [StatusBarPopupChipViewModel] for a media control chip in the status bar. This view model is * responsible for converting the [MediaControlChipModel] to a [PopupChipModel] that can be used to * display a media control chip. */ @SysUISingleton class MediaControlChipViewModel @Inject @AssistedInject constructor( @Background private val backgroundScope: CoroutineScope, @Application private val applicationContext: Context, mediaControlChipInteractor: MediaControlChipInteractor, ) : StatusBarPopupChipViewModel { ) : StatusBarPopupChipViewModel, ExclusiveActivatable() { private val hydrator: Hydrator = Hydrator("MediaControlChipViewModel.hydrator") /** * A [StateFlow] of the current [PopupChipModel]. This flow emits a new [PopupChipModel] * A snapshot [State] of the current [PopupChipModel]. This emits a new [PopupChipModel] * whenever the underlying [MediaControlChipModel] changes. */ override val chip: StateFlow<PopupChipModel> = mediaControlChipInteractor.mediaControlChipModel .map { mediaControlChipModel -> toPopupChipModel(mediaControlChipModel) } .stateIn( backgroundScope, SharingStarted.WhileSubscribed(), PopupChipModel.Hidden(PopupChipId.MediaControl), override val chip: PopupChipModel by hydrator.hydratedStateOf( traceName = "chip", initialValue = PopupChipModel.Hidden(PopupChipId.MediaControl), source = mediaControlChipInteractor.mediaControlChipModel.map { model -> toPopupChipModel(model) }, ) override suspend fun onActivated(): Nothing { hydrator.activate() } private fun toPopupChipModel(model: MediaControlChipModel?): PopupChipModel { if (model == null || model.songName.isNullOrEmpty()) { return PopupChipModel.Hidden(PopupChipId.MediaControl) Loading Loading @@ -96,7 +96,12 @@ constructor( return HoverBehavior.Button( icon = Icon.Loaded(drawable = icon, contentDescription = contentDescription), onIconPressed = { backgroundScope.launch { action.run() } }, onIconPressed = { action.run() }, ) } @AssistedFactory interface Factory { fun create(): MediaControlChipViewModel } }
packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt +4 −4 Original line number Diff line number Diff line Loading @@ -16,14 +16,14 @@ package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel import com.android.systemui.lifecycle.Activatable import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel import kotlinx.coroutines.flow.StateFlow /** * Interface for a view model that knows the display requirements for a single type of status bar * popup chip. */ interface StatusBarPopupChipViewModel { /** A flow modeling the popup chip that should be shown (or not shown). */ val chip: StateFlow<PopupChipModel> interface StatusBarPopupChipViewModel : Activatable { /** A snapshot [State] modeling the popup chip that should be shown (or not shown). */ val chip: PopupChipModel }
packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt +8 −10 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId Loading @@ -36,18 +35,17 @@ import kotlinx.coroutines.flow.map */ class StatusBarPopupChipsViewModel @AssistedInject constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() { private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator") constructor(mediaControlChipFactory: MediaControlChipViewModel.Factory) : ExclusiveActivatable() { private val mediaControlChip by lazy { mediaControlChipFactory.create() } /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */ private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null) private val incomingPopupChipBundle: PopupChipBundle by hydrator.hydratedStateOf( traceName = "incomingPopupChipBundle", initialValue = PopupChipBundle(), source = mediaControlChip.chip.map { chip -> PopupChipBundle(media = chip) }, ) private val incomingPopupChipBundle: PopupChipBundle by derivedStateOf { val mediaChip = mediaControlChip.chip PopupChipBundle(media = mediaChip) } val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf { if (StatusBarPopupChips.isEnabled) { Loading @@ -66,7 +64,7 @@ constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable( } override suspend fun onActivated(): Nothing { hydrator.activate() mediaControlChip.activate() } private data class PopupChipBundle( Loading