Loading packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +94 −38 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.systemui.statusbar package com.android.systemui.statusbar import android.animation.ObjectAnimator import android.animation.ObjectAnimator import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.FlagsParameterization import android.testing.TestableLooper import android.testing.TestableLooper import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest Loading Loading @@ -47,8 +49,10 @@ import com.android.systemui.scene.data.repository.setTransition import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos import com.android.systemui.testKosmos import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.util.kotlin.JavaAdapter Loading Loading @@ -79,6 +83,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest private val kosmos = testKosmos() private val kosmos = testKosmos() private val testScope = kosmos.testScope private val testScope = kosmos.testScope private val sceneInteractor = kosmos.sceneInteractor private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val mockDarkAnimator = mock<ObjectAnimator>() private val mockDarkAnimator = mock<ObjectAnimator>() Loading Loading @@ -229,14 +234,15 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest @Test @Test fun testSetDreamState_getterReturnsCurrentState() { fun testSetDreamState_getterReturnsCurrentState() { underTest.setIsDreaming(true) underTest.setIsDreaming(true) assertTrue(underTest.isDreaming()) assertTrue(underTest.isDreaming) underTest.setIsDreaming(false) underTest.setIsDreaming(false) assertFalse(underTest.isDreaming()) assertFalse(underTest.isDreaming) } } @Test @Test @EnableSceneContainer @EnableSceneContainer @DisableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_whileLocked() = fun start_hydratesStatusBarState_whileLocked() = testScope.runTest { testScope.runTest { var statusBarState = underTest.state var statusBarState = underTest.state Loading @@ -248,7 +254,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } } underTest.addCallback(listener) underTest.addCallback(listener) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) val deviceUnlockStatus by val deviceUnlockStatus by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) Loading @@ -258,45 +264,107 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest runCurrent() runCurrent() assertThat(deviceUnlockStatus!!.isUnlocked).isFalse() assertThat(deviceUnlockStatus!!.isUnlocked).isFalse() kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason") toScene = Scenes.Lockscreen, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) // Call start to begin hydrating based on the scene framework: // Call start to begin hydrating based on the scene framework: underTest.start() underTest.start() kosmos.sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Bouncer) assertThat(currentScene).isEqualTo(Scenes.Bouncer) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason") toScene = Scenes.QuickSettings, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) kosmos.sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Communal) assertThat(currentScene).isEqualTo(Scenes.Communal) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason") toScene = Scenes.Lockscreen, runCurrent() loggingReason = "reason" assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) } @Test @EnableSceneContainer @EnableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_dualShade_whileLocked() = testScope.runTest { var statusBarState = underTest.state val listener = object : StatusBarStateController.StateListener { override fun onStateChanged(newState: Int) { statusBarState = newState } } underTest.addCallback(listener) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) val deviceUnlockStatus by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) runCurrent() assertThat(deviceUnlockStatus!!.isUnlocked).isFalse() sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) // Call start to begin hydrating based on the scene framework: underTest.start() sceneInteractor.changeScene(Scenes.Bouncer, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Bouncer) assertThat(currentOverlays).isEmpty() assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason") runCurrent() sceneInteractor.showOverlay(Overlays.NotificationsShade, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) sceneInteractor.replaceOverlay( from = Overlays.NotificationsShade, to = Overlays.QuickSettingsShade, loggingReason = "reason", ) ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) sceneInteractor.hideOverlay(Overlays.QuickSettingsShade, loggingReason = "reason") sceneInteractor.changeScene(Scenes.Communal, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Communal) assertThat(currentOverlays).isEmpty() assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) } } Loading @@ -313,7 +381,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } } underTest.addCallback(listener) underTest.addCallback(listener) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) val deviceUnlockStatus by val deviceUnlockStatus by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( kosmos.fakeAuthenticationRepository.setAuthenticationMethod( Loading @@ -326,10 +394,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest assertThat(deviceUnlockStatus!!.isUnlocked).isTrue() assertThat(deviceUnlockStatus!!.isUnlocked).isTrue() kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason") toScene = Scenes.Lockscreen, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) Loading @@ -339,20 +404,17 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) kosmos.sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Gone) assertThat(currentScene).isEqualTo(Scenes.Gone) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason") toScene = Scenes.QuickSettings, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) Loading @@ -371,7 +433,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } } underTest.addCallback(listener) underTest.addCallback(listener) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) val isOccluded by val isOccluded by collectLastValue(kosmos.sceneContainerOcclusionInteractor.invisibleDueToOcclusion) collectLastValue(kosmos.sceneContainerOcclusionInteractor.invisibleDueToOcclusion) Loading @@ -385,15 +447,12 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest // Call start to begin hydrating based on the scene framework: // Call start to begin hydrating based on the scene framework: underTest.start() underTest.start() kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason") toScene = Scenes.QuickSettings, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) Loading @@ -415,10 +474,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest kosmos.setTransition( kosmos.setTransition( sceneTransition = Idle(Scenes.Gone), sceneTransition = Idle(Scenes.Gone), stateTransition = stateTransition = TransitionStep( TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE), from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, ) ) ) assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(false) assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(false) Loading packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +14 −4 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.view.animation.Interpolator; import androidx.annotation.NonNull; import androidx.annotation.NonNull; import com.android.app.animation.Interpolators; import com.android.app.animation.Interpolators; import com.android.compose.animation.scene.OverlayKey; import com.android.compose.animation.scene.SceneKey; import com.android.compose.animation.scene.SceneKey; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; Loading @@ -60,6 +61,7 @@ import com.android.systemui.scene.domain.interactor.SceneBackInteractor; import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.model.Overlays; import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; Loading @@ -75,6 +77,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.ArrayList; import java.util.Comparator; import java.util.Comparator; import java.util.Map; import java.util.Map; import java.util.Set; import javax.inject.Inject; import javax.inject.Inject; Loading Loading @@ -230,6 +233,7 @@ public class StatusBarStateControllerImpl implements combineFlows( combineFlows( mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(), mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(), mSceneInteractorLazy.get().getCurrentScene(), mSceneInteractorLazy.get().getCurrentScene(), mSceneInteractorLazy.get().getCurrentOverlays(), mSceneBackInteractorLazy.get().getBackStack(), mSceneBackInteractorLazy.get().getBackStack(), mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(), mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(), this::calculateStateFromSceneFramework), this::calculateStateFromSceneFramework), Loading Loading @@ -690,19 +694,25 @@ public class StatusBarStateControllerImpl implements private int calculateStateFromSceneFramework( private int calculateStateFromSceneFramework( DeviceUnlockStatus deviceUnlockStatus, DeviceUnlockStatus deviceUnlockStatus, SceneKey currentScene, SceneKey currentScene, Set<OverlayKey> currentOverlays, SceneStack backStack, SceneStack backStack, boolean isOccluded) { boolean isOccluded) { SceneContainerFlag.isUnexpectedlyInLegacyMode(); SceneContainerFlag.isUnexpectedlyInLegacyMode(); if (currentScene.equals(Scenes.Lockscreen)) { if (currentScene.equals(Scenes.Lockscreen)) { if (currentOverlays.contains(Overlays.NotificationsShade) || currentOverlays.contains( Overlays.QuickSettingsShade)) { return StatusBarState.SHADE_LOCKED; } return StatusBarState.KEYGUARD; return StatusBarState.KEYGUARD; } else if (currentScene.equals(Scenes.Shade) } if (currentScene.equals(Scenes.Shade) && SceneStackKt.contains(backStack, Scenes.Lockscreen)) { && SceneStackKt.contains(backStack, Scenes.Lockscreen)) { return StatusBarState.SHADE_LOCKED; return StatusBarState.SHADE_LOCKED; } else if (deviceUnlockStatus.isUnlocked() || isOccluded) { } if (deviceUnlockStatus.isUnlocked() || isOccluded) { return StatusBarState.SHADE; return StatusBarState.SHADE; } else { return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene)); } } return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene)); } } /** Notifies that the {@link StatusBarState} has changed to the given new state. */ /** Notifies that the {@link StatusBarState} has changed to the given new state. */ Loading packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt +16 −12 Original line number Original line Diff line number Diff line Loading @@ -39,11 +39,7 @@ import kotlinx.coroutines.launch /** A class allowing Java classes to collect on Kotlin flows. */ /** A class allowing Java classes to collect on Kotlin flows. */ @SysUISingleton @SysUISingleton class JavaAdapter class JavaAdapter @Inject constructor(@Application private val scope: CoroutineScope) { @Inject constructor( @Application private val scope: CoroutineScope, ) { /** /** * Collect information for the given [flow], calling [consumer] for each emitted event. * Collect information for the given [flow], calling [consumer] for each emitted event. * * Loading @@ -55,10 +51,7 @@ constructor( * Do *not* call this method in a class's constructor. Instead, call it in * Do *not* call this method in a class's constructor. Instead, call it in * [com.android.systemui.CoreStartable.start] or similar method. * [com.android.systemui.CoreStartable.start] or similar method. */ */ fun <T> alwaysCollectFlow( fun <T> alwaysCollectFlow(flow: Flow<T>, consumer: Consumer<T>): Job { flow: Flow<T>, consumer: Consumer<T>, ): Job { return scope.launch { flow.collect { consumer.accept(it) } } return scope.launch { flow.collect { consumer.accept(it) } } } } Loading @@ -66,7 +59,7 @@ constructor( fun <T> stateInApp( fun <T> stateInApp( flow: Flow<T>, flow: Flow<T>, initialValue: T, initialValue: T, started: SharingStarted = SharingStarted.Eagerly started: SharingStarted = SharingStarted.Eagerly, ): StateFlow<T> { ): StateFlow<T> { return flow.stateIn(scope, started, initialValue) return flow.stateIn(scope, started, initialValue) } } Loading Loading @@ -117,7 +110,7 @@ fun <A, B, C, R> combineFlows( flow1: Flow<A>, flow1: Flow<A>, flow2: Flow<B>, flow2: Flow<B>, flow3: Flow<C>, flow3: Flow<C>, trifunction: (A, B, C) -> R trifunction: (A, B, C) -> R, ): Flow<R> { ): Flow<R> { return combine(flow1, flow2, flow3, trifunction) return combine(flow1, flow2, flow3, trifunction) } } Loading @@ -127,7 +120,18 @@ fun <T1, T2, T3, T4, R> combineFlows( flow2: Flow<T2>, flow2: Flow<T2>, flow3: Flow<T3>, flow3: Flow<T3>, flow4: Flow<T4>, flow4: Flow<T4>, transform: (T1, T2, T3, T4) -> R transform: (T1, T2, T3, T4) -> R, ): Flow<R> { ): Flow<R> { return combine(flow, flow2, flow3, flow4, transform) return combine(flow, flow2, flow3, flow4, transform) } } fun <T1, T2, T3, T4, T5, R> combineFlows( flow: Flow<T1>, flow2: Flow<T2>, flow3: Flow<T3>, flow4: Flow<T4>, flow5: Flow<T5>, transform: (T1, T2, T3, T4, T5) -> R, ): Flow<R> { return combine(flow, flow2, flow3, flow4, flow5, transform) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +94 −38 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.systemui.statusbar package com.android.systemui.statusbar import android.animation.ObjectAnimator import android.animation.ObjectAnimator import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.platform.test.flag.junit.FlagsParameterization import android.testing.TestableLooper import android.testing.TestableLooper import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest Loading Loading @@ -47,8 +49,10 @@ import com.android.systemui.scene.data.repository.setTransition import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos import com.android.systemui.testKosmos import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.util.kotlin.JavaAdapter Loading Loading @@ -79,6 +83,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest private val kosmos = testKosmos() private val kosmos = testKosmos() private val testScope = kosmos.testScope private val testScope = kosmos.testScope private val sceneInteractor = kosmos.sceneInteractor private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val mockDarkAnimator = mock<ObjectAnimator>() private val mockDarkAnimator = mock<ObjectAnimator>() Loading Loading @@ -229,14 +234,15 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest @Test @Test fun testSetDreamState_getterReturnsCurrentState() { fun testSetDreamState_getterReturnsCurrentState() { underTest.setIsDreaming(true) underTest.setIsDreaming(true) assertTrue(underTest.isDreaming()) assertTrue(underTest.isDreaming) underTest.setIsDreaming(false) underTest.setIsDreaming(false) assertFalse(underTest.isDreaming()) assertFalse(underTest.isDreaming) } } @Test @Test @EnableSceneContainer @EnableSceneContainer @DisableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_whileLocked() = fun start_hydratesStatusBarState_whileLocked() = testScope.runTest { testScope.runTest { var statusBarState = underTest.state var statusBarState = underTest.state Loading @@ -248,7 +254,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } } underTest.addCallback(listener) underTest.addCallback(listener) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) val deviceUnlockStatus by val deviceUnlockStatus by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) Loading @@ -258,45 +264,107 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest runCurrent() runCurrent() assertThat(deviceUnlockStatus!!.isUnlocked).isFalse() assertThat(deviceUnlockStatus!!.isUnlocked).isFalse() kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason") toScene = Scenes.Lockscreen, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) // Call start to begin hydrating based on the scene framework: // Call start to begin hydrating based on the scene framework: underTest.start() underTest.start() kosmos.sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Bouncer) assertThat(currentScene).isEqualTo(Scenes.Bouncer) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason") toScene = Scenes.QuickSettings, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) kosmos.sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Communal) assertThat(currentScene).isEqualTo(Scenes.Communal) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason") toScene = Scenes.Lockscreen, runCurrent() loggingReason = "reason" assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) } @Test @EnableSceneContainer @EnableFlags(DualShade.FLAG_NAME) fun start_hydratesStatusBarState_dualShade_whileLocked() = testScope.runTest { var statusBarState = underTest.state val listener = object : StatusBarStateController.StateListener { override fun onStateChanged(newState: Int) { statusBarState = newState } } underTest.addCallback(listener) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) val deviceUnlockStatus by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Password ) runCurrent() assertThat(deviceUnlockStatus!!.isUnlocked).isFalse() sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) // Call start to begin hydrating based on the scene framework: underTest.start() sceneInteractor.changeScene(Scenes.Bouncer, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Bouncer) assertThat(currentOverlays).isEmpty() assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason") runCurrent() sceneInteractor.showOverlay(Overlays.NotificationsShade, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) sceneInteractor.replaceOverlay( from = Overlays.NotificationsShade, to = Overlays.QuickSettingsShade, loggingReason = "reason", ) ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED) sceneInteractor.hideOverlay(Overlays.QuickSettingsShade, loggingReason = "reason") sceneInteractor.changeScene(Scenes.Communal, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Communal) assertThat(currentOverlays).isEmpty() assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason") runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentOverlays).isEmpty() assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) } } Loading @@ -313,7 +381,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } } underTest.addCallback(listener) underTest.addCallback(listener) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) val deviceUnlockStatus by val deviceUnlockStatus by collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( kosmos.fakeAuthenticationRepository.setAuthenticationMethod( Loading @@ -326,10 +394,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest assertThat(deviceUnlockStatus!!.isUnlocked).isTrue() assertThat(deviceUnlockStatus!!.isUnlocked).isTrue() kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason") toScene = Scenes.Lockscreen, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) Loading @@ -339,20 +404,17 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD) kosmos.sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Gone) assertThat(currentScene).isEqualTo(Scenes.Gone) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason") toScene = Scenes.QuickSettings, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) Loading @@ -371,7 +433,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest } } underTest.addCallback(listener) underTest.addCallback(listener) val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene) val currentScene by collectLastValue(sceneInteractor.currentScene) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) assertThat(currentScene).isEqualTo(Scenes.Lockscreen) val isOccluded by val isOccluded by collectLastValue(kosmos.sceneContainerOcclusionInteractor.invisibleDueToOcclusion) collectLastValue(kosmos.sceneContainerOcclusionInteractor.invisibleDueToOcclusion) Loading @@ -385,15 +447,12 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest // Call start to begin hydrating based on the scene framework: // Call start to begin hydrating based on the scene framework: underTest.start() underTest.start() kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason") runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(currentScene).isEqualTo(Scenes.Shade) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) kosmos.sceneInteractor.changeScene( sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason") toScene = Scenes.QuickSettings, loggingReason = "reason" ) runCurrent() runCurrent() assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) assertThat(statusBarState).isEqualTo(StatusBarState.SHADE) Loading @@ -415,10 +474,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest kosmos.setTransition( kosmos.setTransition( sceneTransition = Idle(Scenes.Gone), sceneTransition = Idle(Scenes.Gone), stateTransition = stateTransition = TransitionStep( TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE), from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE, ) ) ) assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(false) assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(false) Loading
packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +14 −4 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.view.animation.Interpolator; import androidx.annotation.NonNull; import androidx.annotation.NonNull; import com.android.app.animation.Interpolators; import com.android.app.animation.Interpolators; import com.android.compose.animation.scene.OverlayKey; import com.android.compose.animation.scene.SceneKey; import com.android.compose.animation.scene.SceneKey; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; Loading @@ -60,6 +61,7 @@ import com.android.systemui.scene.domain.interactor.SceneBackInteractor; import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.scene.shared.model.Overlays; import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.scene.shared.model.Scenes; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; Loading @@ -75,6 +77,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.ArrayList; import java.util.Comparator; import java.util.Comparator; import java.util.Map; import java.util.Map; import java.util.Set; import javax.inject.Inject; import javax.inject.Inject; Loading Loading @@ -230,6 +233,7 @@ public class StatusBarStateControllerImpl implements combineFlows( combineFlows( mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(), mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(), mSceneInteractorLazy.get().getCurrentScene(), mSceneInteractorLazy.get().getCurrentScene(), mSceneInteractorLazy.get().getCurrentOverlays(), mSceneBackInteractorLazy.get().getBackStack(), mSceneBackInteractorLazy.get().getBackStack(), mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(), mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(), this::calculateStateFromSceneFramework), this::calculateStateFromSceneFramework), Loading Loading @@ -690,19 +694,25 @@ public class StatusBarStateControllerImpl implements private int calculateStateFromSceneFramework( private int calculateStateFromSceneFramework( DeviceUnlockStatus deviceUnlockStatus, DeviceUnlockStatus deviceUnlockStatus, SceneKey currentScene, SceneKey currentScene, Set<OverlayKey> currentOverlays, SceneStack backStack, SceneStack backStack, boolean isOccluded) { boolean isOccluded) { SceneContainerFlag.isUnexpectedlyInLegacyMode(); SceneContainerFlag.isUnexpectedlyInLegacyMode(); if (currentScene.equals(Scenes.Lockscreen)) { if (currentScene.equals(Scenes.Lockscreen)) { if (currentOverlays.contains(Overlays.NotificationsShade) || currentOverlays.contains( Overlays.QuickSettingsShade)) { return StatusBarState.SHADE_LOCKED; } return StatusBarState.KEYGUARD; return StatusBarState.KEYGUARD; } else if (currentScene.equals(Scenes.Shade) } if (currentScene.equals(Scenes.Shade) && SceneStackKt.contains(backStack, Scenes.Lockscreen)) { && SceneStackKt.contains(backStack, Scenes.Lockscreen)) { return StatusBarState.SHADE_LOCKED; return StatusBarState.SHADE_LOCKED; } else if (deviceUnlockStatus.isUnlocked() || isOccluded) { } if (deviceUnlockStatus.isUnlocked() || isOccluded) { return StatusBarState.SHADE; return StatusBarState.SHADE; } else { return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene)); } } return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene)); } } /** Notifies that the {@link StatusBarState} has changed to the given new state. */ /** Notifies that the {@link StatusBarState} has changed to the given new state. */ Loading
packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt +16 −12 Original line number Original line Diff line number Diff line Loading @@ -39,11 +39,7 @@ import kotlinx.coroutines.launch /** A class allowing Java classes to collect on Kotlin flows. */ /** A class allowing Java classes to collect on Kotlin flows. */ @SysUISingleton @SysUISingleton class JavaAdapter class JavaAdapter @Inject constructor(@Application private val scope: CoroutineScope) { @Inject constructor( @Application private val scope: CoroutineScope, ) { /** /** * Collect information for the given [flow], calling [consumer] for each emitted event. * Collect information for the given [flow], calling [consumer] for each emitted event. * * Loading @@ -55,10 +51,7 @@ constructor( * Do *not* call this method in a class's constructor. Instead, call it in * Do *not* call this method in a class's constructor. Instead, call it in * [com.android.systemui.CoreStartable.start] or similar method. * [com.android.systemui.CoreStartable.start] or similar method. */ */ fun <T> alwaysCollectFlow( fun <T> alwaysCollectFlow(flow: Flow<T>, consumer: Consumer<T>): Job { flow: Flow<T>, consumer: Consumer<T>, ): Job { return scope.launch { flow.collect { consumer.accept(it) } } return scope.launch { flow.collect { consumer.accept(it) } } } } Loading @@ -66,7 +59,7 @@ constructor( fun <T> stateInApp( fun <T> stateInApp( flow: Flow<T>, flow: Flow<T>, initialValue: T, initialValue: T, started: SharingStarted = SharingStarted.Eagerly started: SharingStarted = SharingStarted.Eagerly, ): StateFlow<T> { ): StateFlow<T> { return flow.stateIn(scope, started, initialValue) return flow.stateIn(scope, started, initialValue) } } Loading Loading @@ -117,7 +110,7 @@ fun <A, B, C, R> combineFlows( flow1: Flow<A>, flow1: Flow<A>, flow2: Flow<B>, flow2: Flow<B>, flow3: Flow<C>, flow3: Flow<C>, trifunction: (A, B, C) -> R trifunction: (A, B, C) -> R, ): Flow<R> { ): Flow<R> { return combine(flow1, flow2, flow3, trifunction) return combine(flow1, flow2, flow3, trifunction) } } Loading @@ -127,7 +120,18 @@ fun <T1, T2, T3, T4, R> combineFlows( flow2: Flow<T2>, flow2: Flow<T2>, flow3: Flow<T3>, flow3: Flow<T3>, flow4: Flow<T4>, flow4: Flow<T4>, transform: (T1, T2, T3, T4) -> R transform: (T1, T2, T3, T4) -> R, ): Flow<R> { ): Flow<R> { return combine(flow, flow2, flow3, flow4, transform) return combine(flow, flow2, flow3, flow4, transform) } } fun <T1, T2, T3, T4, T5, R> combineFlows( flow: Flow<T1>, flow2: Flow<T2>, flow3: Flow<T3>, flow4: Flow<T4>, flow5: Flow<T5>, transform: (T1, T2, T3, T4, T5) -> R, ): Flow<R> { return combine(flow, flow2, flow3, flow4, flow5, transform) }