Merge "[flexiglass] Fixes issue where Flexiglass starts blank." into main
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 715fb17..4cddb9c 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
@@ -103,8 +103,11 @@
                 initialValue = false,
             )
 
-    // Authenticated by a TrustAgent like trusted device, location, etc or by face auth.
-    private val passivelyAuthenticated =
+    /**
+     * Whether the user is currently authenticated by a TrustAgent like trusted device, location,
+     * etc., or by face auth.
+     */
+    private val isPassivelyAuthenticated =
         merge(
                 trustRepository.isCurrentUserTrusted,
                 deviceEntryFaceAuthRepository.isAuthenticated,
@@ -117,25 +120,31 @@
      * mechanism like face or trust manager. This returns `false` whenever the lockscreen has been
      * dismissed.
      *
+     * A value of `null` is meaningless and is used as placeholder while the actual value is still
+     * being loaded in the background.
+     *
      * Note: `true` doesn't mean the lockscreen is visible. It may be occluded or covered by other
      * UI.
      */
-    val canSwipeToEnter =
+    val canSwipeToEnter: StateFlow<Boolean?> =
         combine(
                 // This is true when the user has chosen to show the lockscreen but has not made it
                 // secure.
                 authenticationInteractor.authenticationMethod.map {
                     it == AuthenticationMethodModel.None && repository.isLockscreenEnabled()
                 },
-                passivelyAuthenticated,
+                isPassivelyAuthenticated,
                 isDeviceEntered
-            ) { isSwipeAuthMethod, passivelyAuthenticated, isDeviceEntered ->
-                (isSwipeAuthMethod || passivelyAuthenticated) && !isDeviceEntered
+            ) { isSwipeAuthMethod, isPassivelyAuthenticated, isDeviceEntered ->
+                (isSwipeAuthMethod || isPassivelyAuthenticated) && !isDeviceEntered
             }
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
-                initialValue = false,
+                // Starts as null to prevent downstream collectors from falsely assuming that the
+                // user can or cannot swipe to enter the device while the real value is being loaded
+                // from upstream data sources.
+                initialValue = null,
             )
 
     /**
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 f3f9c91..1c5330e 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
@@ -146,19 +146,21 @@
                     isAnySimLocked -> {
                         switchToScene(
                             targetSceneKey = SceneKey.Bouncer,
-                            loggingReason = "Need to authenticate locked sim card."
+                            loggingReason = "Need to authenticate locked SIM card."
                         )
                     }
-                    isUnlocked && !canSwipeToEnter -> {
+                    isUnlocked && canSwipeToEnter == false -> {
                         switchToScene(
                             targetSceneKey = SceneKey.Gone,
-                            loggingReason = "Sim cards are unlocked."
+                            loggingReason = "All SIM cards unlocked and device already" +
+                                " unlocked and lockscreen doesn't require a swipe to dismiss."
                         )
                     }
                     else -> {
                         switchToScene(
                             targetSceneKey = SceneKey.Lockscreen,
-                            loggingReason = "Sim cards are unlocked."
+                            loggingReason = "All SIM cards unlocked and device still locked" +
+                                " or lockscreen still requires a swipe to dismiss."
                         )
                     }
                 }
@@ -205,11 +207,17 @@
                             //    when the user is passively authenticated, the false value here
                             //    when the unlock state changes indicates this is an active
                             //    authentication attempt.
-                            if (isBypassEnabled || !canSwipeToEnter)
-                                SceneKey.Gone to
-                                    "device has been unlocked on lockscreen with either " +
-                                        "bypass enabled or using an active authentication mechanism"
-                            else null
+                            when {
+                                isBypassEnabled ->
+                                    SceneKey.Gone to
+                                        "device has been unlocked on lockscreen with bypass" +
+                                            " enabled"
+                                canSwipeToEnter == false ->
+                                    SceneKey.Gone to
+                                        "device has been unlocked on lockscreen using an active" +
+                                            " authentication mechanism"
+                                else -> null
+                            }
                         // Not on lockscreen or bouncer, so remain in the current scene.
                         else -> null
                     }
@@ -232,7 +240,7 @@
                 } else {
                     val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value
                     val isUnlocked = deviceEntryInteractor.isUnlocked.value
-                    if (isUnlocked && !canSwipeToEnter) {
+                    if (isUnlocked && canSwipeToEnter == false) {
                         switchToScene(
                             targetSceneKey = SceneKey.Gone,
                             loggingReason =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index 2a071de..0065db3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -66,10 +66,10 @@
 
     private fun upDestinationSceneKey(
         isUnlocked: Boolean,
-        canSwipeToDismiss: Boolean,
+        canSwipeToDismiss: Boolean?,
     ): SceneKey {
         return when {
-            canSwipeToDismiss -> SceneKey.Lockscreen
+            canSwipeToDismiss == true -> SceneKey.Lockscreen
             isUnlocked -> SceneKey.Gone
             else -> SceneKey.Lockscreen
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
index 0004f52..910097e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorTest.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
 import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
 import com.android.systemui.keyguard.data.repository.FakeTrustRepository
@@ -56,6 +57,13 @@
         )
 
     @Test
+    fun canSwipeToEnter_startsNull() =
+        testScope.runTest {
+            val values by collectValues(underTest.canSwipeToEnter)
+            assertThat(values[0]).isNull()
+        }
+
+    @Test
     fun isUnlocked_whenAuthMethodIsNoneAndLockscreenDisabled_isTrue() =
         testScope.runTest {
             utils.authenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.None)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index c3294ff..c953743 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -61,7 +61,6 @@
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
-import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -273,6 +272,9 @@
     }
 
     @Test
+    fun startsInLockscreenScene() = testScope.runTest { assertCurrentScene(SceneKey.Lockscreen) }
+
+    @Test
     fun clickLockButtonAndEnterCorrectPin_unlocksDevice() =
         testScope.runTest {
             emulateUserDrivenTransition(SceneKey.Bouncer)
@@ -336,7 +338,7 @@
         testScope.runTest {
             val upDestinationSceneKey by collectLastValue(shadeSceneViewModel.upDestinationSceneKey)
             setAuthMethod(AuthenticationMethodModel.None, enableLockscreen = true)
-            assertTrue(deviceEntryInteractor.canSwipeToEnter.value)
+            assertThat(deviceEntryInteractor.canSwipeToEnter.value).isTrue()
             assertCurrentScene(SceneKey.Lockscreen)
 
             // Emulate a user swipe to dismiss the lockscreen.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index c4ec56c..adc1c61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -145,6 +145,18 @@
         }
 
     @Test
+    fun startsInLockscreenScene() =
+        testScope.runTest {
+            val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })
+            prepareState()
+
+            underTest.start()
+            runCurrent()
+
+            assertThat(currentSceneKey).isEqualTo(SceneKey.Lockscreen)
+        }
+
+    @Test
     fun switchToLockscreenWhenDeviceLocks() =
         testScope.runTest {
             val currentSceneKey by collectLastValue(sceneInteractor.desiredScene.map { it.key })