diff options
8 files changed, 225 insertions, 40 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt index 6e364d180ebf..3cbcb2cb4a0b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt @@ -33,12 +33,16 @@ import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.utils.GlobalWindowManager import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch @@ -60,6 +64,7 @@ constructor( @Application private val applicationScope: CoroutineScope, @Background private val bgDispatcher: CoroutineDispatcher, private val featureFlags: FeatureFlags, + private val sceneInteractor: SceneInteractor, ) : CoreStartable, WakefulnessLifecycle.Observer { override fun start() { @@ -85,9 +90,15 @@ constructor( applicationScope.launch(bgDispatcher) { // We drop 1 to avoid triggering on initial collect(). - keyguardTransitionInteractor.transition(Edge.create(to = GONE)).collect { transition -> - if (transition.transitionState == TransitionState.FINISHED) { - onKeyguardGone() + if (SceneContainerFlag.isEnabled) { + sceneInteractor.transitionState + .filter { it.isIdle(Scenes.Gone) } + .collect { onKeyguardGone() } + } else { + keyguardTransitionInteractor.transition(Edge.create(to = GONE)).collect { + if (it.transitionState == TransitionState.FINISHED) { + onKeyguardGone() + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt index 08d29d4fc0a6..1aac1c5940b3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractor.kt @@ -25,6 +25,9 @@ import com.android.systemui.keyguard.shared.model.KeyguardDone import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -48,6 +51,7 @@ constructor( transitionInteractor: KeyguardTransitionInteractor, val dismissInteractor: KeyguardDismissInteractor, @Application private val applicationScope: CoroutineScope, + sceneInteractor: SceneInteractor, ) { val dismissAction: Flow<DismissAction> = repository.dismissAction @@ -72,7 +76,12 @@ constructor( ) private val finishedTransitionToGone: Flow<Unit> = - transitionInteractor.finishedKeyguardState.filter { it == GONE }.map {} // map to Unit + if (SceneContainerFlag.isEnabled) { + sceneInteractor.transitionState.filter { it.isIdle(Scenes.Gone) }.map {} + } else { + transitionInteractor.finishedKeyguardState.filter { it == GONE }.map {} + } + val executeDismissAction: Flow<() -> KeyguardDone> = merge( finishedTransitionToGone, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index 188516cc7e36..229e592a6a0c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt @@ -74,6 +74,9 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.PageIndicator import com.android.systemui.res.R +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shared.system.SysUiStatsLog import com.android.systemui.shared.system.SysUiStatsLog.SMARTSPACE_CARD_REPORTED import com.android.systemui.shared.system.SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD @@ -143,6 +146,7 @@ constructor( private val secureSettings: SecureSettings, private val mediaCarouselViewModel: MediaCarouselViewModel, private val mediaViewControllerFactory: Provider<MediaViewController>, + private val sceneInteractor: SceneInteractor, ) : Dumpable { /** The current width of the carousel */ var currentCarouselWidth: Int = 0 @@ -641,9 +645,13 @@ constructor( @VisibleForTesting internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job { return scope.launch { - keyguardTransitionInteractor - .transition(Edge.create(to = GONE)) - .filter { it.transitionState == TransitionState.FINISHED } + if (SceneContainerFlag.isEnabled) { + sceneInteractor.transitionState.filter { it.isIdle(Scenes.Gone) } + } else { + keyguardTransitionInteractor.transition(Edge.create(to = GONE)).filter { + it.transitionState == TransitionState.FINISHED + } + } .collect { showMediaCarousel() updateHostVisibility() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt index 7afed9db8604..977116e812ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt @@ -8,6 +8,8 @@ import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -19,7 +21,10 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.scene.data.repository.Idle +import com.android.systemui.scene.data.repository.setSceneTransition import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.utils.GlobalWindowManager @@ -70,12 +75,13 @@ class ResourceTrimmerTest : SysuiTestCase() { resourceTrimmer = ResourceTrimmer( keyguardInteractor, - powerInteractor, - kosmos.keyguardTransitionInteractor, - globalWindowManager, - testScope.backgroundScope, - kosmos.testDispatcher, - featureFlags, + powerInteractor = powerInteractor, + keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor, + globalWindowManager = globalWindowManager, + applicationScope = testScope.backgroundScope, + bgDispatcher = kosmos.testDispatcher, + featureFlags = featureFlags, + sceneInteractor = kosmos.sceneInteractor, ) resourceTrimmer.start() } @@ -204,6 +210,7 @@ class ResourceTrimmerTest : SysuiTestCase() { @Test @EnableFlags(com.android.systemui.Flags.FLAG_TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK) + @DisableSceneContainer fun keyguardTransitionsToGone_trimsFontCache() = testScope.runTest { keyguardTransitionRepository.sendTransitionSteps( @@ -219,6 +226,20 @@ class ResourceTrimmerTest : SysuiTestCase() { @Test @EnableFlags(com.android.systemui.Flags.FLAG_TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK) + @EnableSceneContainer + fun keyguardTransitionsToGone_trimsFontCache_scene_container() = + testScope.runTest { + kosmos.setSceneTransition(Idle(Scenes.Gone)) + + verify(globalWindowManager, times(1)) + .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) + verify(globalWindowManager, times(1)).trimCaches(HardwareRenderer.CACHE_TRIM_FONT) + verifyNoMoreInteractions(globalWindowManager) + } + + @Test + @EnableFlags(com.android.systemui.Flags.FLAG_TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK) + @DisableSceneContainer fun keyguardTransitionsToGone_flagDisabled_doesNotTrimFontCache() = testScope.runTest { featureFlags.set(Flags.TRIM_FONT_CACHES_AT_UNLOCK, false) @@ -232,4 +253,18 @@ class ResourceTrimmerTest : SysuiTestCase() { .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) verify(globalWindowManager, times(0)).trimCaches(any()) } + + @Test + @EnableFlags(com.android.systemui.Flags.FLAG_TRIM_RESOURCES_WITH_BACKGROUND_TRIM_AT_LOCK) + @EnableSceneContainer + fun keyguardTransitionsToGone_flagDisabled_doesNotTrimFontCache_scene_container() = + testScope.runTest { + featureFlags.set(Flags.TRIM_FONT_CACHES_AT_UNLOCK, false) + kosmos.setSceneTransition(Idle(Scenes.Gone)) + + // Memory hidden should still be called. + verify(globalWindowManager, times(1)) + .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) + verify(globalWindowManager, times(0)).trimCaches(any()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt index 62855d79c052..974e3bb133d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorTest.kt @@ -21,12 +21,18 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.DismissAction import com.android.systemui.keyguard.shared.model.KeyguardDone import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.data.repository.Idle +import com.android.systemui.scene.data.repository.setSceneTransition +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -65,10 +71,11 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { underTest = KeyguardDismissActionInteractor( - keyguardRepository, - kosmos.keyguardTransitionInteractor, - dismissInteractorWithDependencies.interactor, - testScope.backgroundScope, + repository = keyguardRepository, + transitionInteractor = kosmos.keyguardTransitionInteractor, + dismissInteractor = dismissInteractorWithDependencies.interactor, + applicationScope = testScope.backgroundScope, + sceneInteractor = kosmos.sceneInteractor, ) } @@ -153,6 +160,7 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun executeDismissAction_dismissKeyguardRequestWithoutImmediateDismissAction() = testScope.runTest { val executeDismissAction by collectLastValue(underTest.executeDismissAction) @@ -179,6 +187,29 @@ class KeyguardDismissActionInteractorTest : SysuiTestCase() { } @Test + @EnableSceneContainer + fun executeDismissAction_dismissKeyguardRequestWithoutImmediateDismissAction_scene_container() = + testScope.runTest { + val executeDismissAction by collectLastValue(underTest.executeDismissAction) + + // WHEN a keyguard action will run after the keyguard is gone + val onDismissAction = {} + keyguardRepository.setDismissAction( + DismissAction.RunAfterKeyguardGone( + dismissAction = onDismissAction, + onCancelAction = {}, + message = "message", + willAnimateOnLockscreen = true, + ) + ) + assertThat(executeDismissAction).isNull() + + kosmos.setSceneTransition(Idle(Scenes.Gone)) + + assertThat(executeDismissAction).isNotNull() + } + + @Test fun resetDismissAction() = testScope.runTest { val resetDismissAction by collectLastValue(underTest.resetDismissAction) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt index d3952f047215..85cfacc0f87b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt @@ -33,6 +33,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository @@ -54,7 +56,10 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.PageIndicator import com.android.systemui.res.R +import com.android.systemui.scene.data.repository.Idle +import com.android.systemui.scene.data.repository.setSceneTransition import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider import com.android.systemui.statusbar.policy.ConfigurationController @@ -153,29 +158,30 @@ class MediaCarouselControllerTest : SysuiTestCase() { testDispatcher = UnconfinedTestDispatcher() mediaCarouselController = MediaCarouselController( - context, - mediaControlPanelFactory, - visualStabilityProvider, - mediaHostStatesManager, - activityStarter, - clock, - kosmos.testDispatcher, - executor, - bgExecutor, - testDispatcher, - mediaDataManager, - configurationController, - falsingManager, - dumpManager, - logger, - debugLogger, - mediaFlags, - keyguardUpdateMonitor, - kosmos.keyguardTransitionInteractor, - globalSettings, - secureSettings, - kosmos.mediaCarouselViewModel, - mediaViewControllerFactory, + context = context, + mediaControlPanelFactory = mediaControlPanelFactory, + visualStabilityProvider = visualStabilityProvider, + mediaHostStatesManager = mediaHostStatesManager, + activityStarter = activityStarter, + systemClock = clock, + mainDispatcher = kosmos.testDispatcher, + executor = executor, + bgExecutor = bgExecutor, + backgroundDispatcher = testDispatcher, + mediaManager = mediaDataManager, + configurationController = configurationController, + falsingManager = falsingManager, + dumpManager = dumpManager, + logger = logger, + debugLogger = debugLogger, + mediaFlags = mediaFlags, + keyguardUpdateMonitor = keyguardUpdateMonitor, + keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor, + globalSettings = globalSettings, + secureSettings = secureSettings, + mediaCarouselViewModel = kosmos.mediaCarouselViewModel, + mediaViewControllerFactory = mediaViewControllerFactory, + sceneInteractor = kosmos.sceneInteractor, ) verify(configurationController).addCallback(capture(configListener)) verify(mediaDataManager).addListener(capture(listener)) @@ -835,6 +841,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(mediaCarousel).visibility = View.VISIBLE } + @DisableSceneContainer @ExperimentalCoroutinesApi @Test fun testKeyguardGone_showMediaCarousel() = @@ -858,6 +865,25 @@ class MediaCarouselControllerTest : SysuiTestCase() { job.cancel() } + @EnableSceneContainer + @ExperimentalCoroutinesApi + @Test + fun testKeyguardGone_showMediaCarousel_scene_container() = + kosmos.testScope.runTest { + kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) + var updatedVisibility = false + mediaCarouselController.updateHostVisibility = { updatedVisibility = true } + mediaCarouselController.mediaCarousel = mediaCarousel + + val job = mediaCarouselController.listenForAnyStateToGoneKeyguardTransition(this) + kosmos.setSceneTransition(Idle(Scenes.Gone)) + + verify(mediaCarousel).visibility = View.VISIBLE + assertEquals(true, updatedVisibility) + + job.cancel() + } + @ExperimentalCoroutinesApi @Test fun keyguardShowing_notAllowedOnLockscreen_updateVisibility() { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt index 2c6d44f10152..03e5a90c9f7d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.sceneInteractor import kotlinx.coroutines.ExperimentalCoroutinesApi @ExperimentalCoroutinesApi @@ -29,5 +30,6 @@ val Kosmos.keyguardDismissActionInteractor by transitionInteractor = keyguardTransitionInteractor, dismissInteractor = keyguardDismissInteractor, applicationScope = testScope.backgroundScope, + sceneInteractor = sceneInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryUtil.kt new file mode 100644 index 000000000000..641a75716ea0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryUtil.kt @@ -0,0 +1,63 @@ +/* + * 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.scene.data.repository + +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.shared.model.Scenes +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent + +private val mutableTransitionState = + MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(Scenes.Lockscreen)) + +fun Kosmos.setSceneTransition( + transition: ObservableTransitionState, + scope: TestScope = testScope, + repository: SceneContainerRepository = sceneContainerRepository +) { + repository.setTransitionState(mutableTransitionState) + mutableTransitionState.value = transition + scope.runCurrent() +} + +fun Transition( + from: SceneKey, + to: SceneKey, + currentScene: Flow<SceneKey> = flowOf(to), + progress: Flow<Float> = flowOf(0f), + isInitiatedByUserInput: Boolean = false, + isUserInputOngoing: Flow<Boolean> = flowOf(false), +): ObservableTransitionState.Transition { + return ObservableTransitionState.Transition( + fromScene = from, + toScene = to, + currentScene = currentScene, + progress = progress, + isInitiatedByUserInput = isInitiatedByUserInput, + isUserInputOngoing = isUserInputOngoing + ) +} + +fun Idle(currentScene: SceneKey): ObservableTransitionState.Idle { + return ObservableTransitionState.Idle(currentScene) +} |