diff options
4 files changed, 75 insertions, 4 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index ac66e6657a75..e40c8eecca0f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -14,7 +14,7 @@   * limitations under the License.   */ -@file:OptIn(ExperimentalCoroutinesApi::class, ExperimentalCoroutinesApi::class) +@file:OptIn(ExperimentalCoroutinesApi::class)  package com.android.systemui.scene.domain.startable @@ -395,6 +395,7 @@ class SceneContainerStartableTest : SysuiTestCase() {                  )              assertThat(currentSceneKey).isEqualTo(Scenes.Gone)              underTest.start() +            runCurrent()              kosmos.fakePowerRepository.updateWakefulness(                  rawState = WakefulnessState.STARTING_TO_SLEEP, @@ -1285,6 +1286,42 @@ class SceneContainerStartableTest : SysuiTestCase() {          }      @Test +    fun switchToGone_whenSurfaceBehindLockscreenVisibleMidTransition() = +        testScope.runTest { +            val currentScene by collectLastValue(sceneInteractor.currentScene) +            val transitionStateFlow = +                prepareState( +                    authenticationMethod = AuthenticationMethodModel.None, +                ) +            underTest.start() +            assertThat(currentScene).isEqualTo(Scenes.Lockscreen) +            // Swipe to Gone, more than halfway +            transitionStateFlow.value = +                ObservableTransitionState.Transition( +                    fromScene = Scenes.Lockscreen, +                    toScene = Scenes.Gone, +                    currentScene = flowOf(Scenes.Gone), +                    progress = flowOf(0.51f), +                    isInitiatedByUserInput = true, +                    isUserInputOngoing = flowOf(true), +                ) +            runCurrent() +            // Lift finger +            transitionStateFlow.value = +                ObservableTransitionState.Transition( +                    fromScene = Scenes.Lockscreen, +                    toScene = Scenes.Gone, +                    currentScene = flowOf(Scenes.Gone), +                    progress = flowOf(0.51f), +                    isInitiatedByUserInput = true, +                    isUserInputOngoing = flowOf(false), +                ) +            runCurrent() + +            assertThat(currentScene).isEqualTo(Scenes.Gone) +        } + +    @Test      fun switchToGone_extendUnlock() =          testScope.runTest {              val currentScene by collectLastValue(sceneInteractor.currentScene) diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt index 9d110e665ebe..10d6881e4f93 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractor.kt @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.domain.interactor.TrustInteractor  import com.android.systemui.scene.domain.interactor.SceneInteractor  import com.android.systemui.scene.shared.model.Scenes  import com.android.systemui.util.kotlin.Quad +import com.android.systemui.utils.coroutines.flow.mapLatestConflated  import javax.inject.Inject  import kotlinx.coroutines.CoroutineScope  import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -37,6 +38,7 @@ import kotlinx.coroutines.flow.SharingStarted  import kotlinx.coroutines.flow.StateFlow  import kotlinx.coroutines.flow.combine  import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first  import kotlinx.coroutines.flow.flatMapLatest  import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.flow.map @@ -96,7 +98,16 @@ constructor(              .filter { currentScene ->                  currentScene == Scenes.Gone || currentScene == Scenes.Lockscreen              } -            .map { it == Scenes.Gone } +            .mapLatestConflated { scene -> +                if (scene == Scenes.Gone) { +                    // Make sure device unlock status is definitely unlocked before we consider the +                    // device "entered". +                    deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked } +                    true +                } else { +                    false +                } +            }              .stateIn(                  scope = applicationScope,                  started = SharingStarted.Eagerly, diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index 0304e730cb68..1e689bd11fa3 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -39,6 +39,7 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor  import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor  import com.android.systemui.deviceentry.shared.model.DeviceUnlockSource  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor +import com.android.systemui.keyguard.domain.interactor.WindowManagerLockscreenVisibilityInteractor  import com.android.systemui.model.SceneContainerPlugin  import com.android.systemui.model.SysUiState  import com.android.systemui.model.updateFlags @@ -81,6 +82,7 @@ import kotlinx.coroutines.flow.emptyFlow  import kotlinx.coroutines.flow.filter  import kotlinx.coroutines.flow.filterIsInstance  import kotlinx.coroutines.flow.filterNot +import kotlinx.coroutines.flow.first  import kotlinx.coroutines.flow.flatMapLatest  import kotlinx.coroutines.flow.flowOf  import kotlinx.coroutines.flow.map @@ -120,6 +122,7 @@ constructor(      private val uiEventLogger: UiEventLogger,      private val sceneBackInteractor: SceneBackInteractor,      private val shadeSessionStorage: SessionStorage, +    private val windowMgrLockscreenVisInteractor: WindowManagerLockscreenVisibilityInteractor,  ) : CoreStartable {      private val centralSurfaces: CentralSurfaces?          get() = centralSurfacesOptLazy.get().getOrNull() @@ -227,6 +230,25 @@ constructor(          handleDeviceUnlockStatus()          handlePowerState()          handleShadeTouchability() +        handleSurfaceBehindKeyguardVisibility() +    } + +    private fun handleSurfaceBehindKeyguardVisibility() { +        applicationScope.launch { +            sceneInteractor.currentScene.collectLatest { currentScene -> +                if (currentScene == Scenes.Lockscreen) { +                    // Wait for surface to become visible +                    windowMgrLockscreenVisInteractor.surfaceBehindVisibility.first { it } +                    // Make sure the device is actually unlocked before force-changing the scene +                    deviceUnlockedInteractor.deviceUnlockStatus.first { it.isUnlocked } +                    // Override the current transition, if any, by forcing the scene to Gone +                    sceneInteractor.changeScene( +                        toScene = Scenes.Gone, +                        loggingReason = "surface behind keyguard is visible", +                    ) +                } +            } +        }      }      private fun handleBouncerImeVisibility() { @@ -329,8 +351,7 @@ constructor(                                  Scenes.Gone to "device was unlocked in Bouncer scene"                              } else {                                  val prevScene = previousScene.value -                                (prevScene -                                    ?: Scenes.Gone) to +                                (prevScene ?: Scenes.Gone) to                                      "device was unlocked in Bouncer scene, from sceneKey=$prevScene"                              }                          isOnLockscreen -> diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt index d82286fd3569..cf18c0e295ea 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/interactor/SceneContainerStartableKosmos.kt @@ -26,6 +26,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryFaceAuthInt  import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor  import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor  import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.domain.interactor.windowManagerLockscreenVisibilityInteractor  import com.android.systemui.kosmos.Kosmos  import com.android.systemui.kosmos.Kosmos.Fixture  import com.android.systemui.kosmos.testScope @@ -67,5 +68,6 @@ val Kosmos.sceneContainerStartable by Fixture {          uiEventLogger = uiEventLogger,          sceneBackInteractor = sceneBackInteractor,          shadeSessionStorage = shadeSessionStorage, +        windowMgrLockscreenVisInteractor = windowManagerLockscreenVisibilityInteractor,      )  }  |