summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lucas Silva <lusilva@google.com> 2025-02-11 11:43:10 -0500
committer Lucas Silva <lusilva@google.com> 2025-02-11 11:45:14 -0500
commitcdeb4bb5458272a557da2b4b66db908e4bbadc08 (patch)
treee33645f8a94824fe2573b3018a290e46857ef7ac
parentfad62f2c5ebea02b6caab9fbfad6cb8d418afd05 (diff)
Remove custom timeout logic from hub v2
In v2, we can let PowerManagerService handle the timeout behavior since we no longer keep the dream active underneath the hub. Bug: 394915563 Test: atest CommunalSceneStartableTest Flag: com.android.systemui.glanceable_hub_v2 Change-Id: I24d7db4c09e17a4852cbc9d842352904ba4527fc
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt540
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt183
2 files changed, 327 insertions, 396 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index e9b88499a6f7..7051f81cfc88 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -24,45 +24,47 @@ import android.provider.Settings
import androidx.test.filters.SmallTest
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
import com.android.systemui.communal.domain.interactor.setCommunalAvailable
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalScenes
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.dock.dockManager
import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.notificationShadeWindowController
-import com.android.systemui.statusbar.phone.centralSurfacesOptional
import com.android.systemui.testKosmos
import com.android.systemui.util.settings.fakeSettings
import com.google.common.truth.Truth.assertThat
+import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
@EnableFlags(FLAG_COMMUNAL_HUB)
@@ -74,7 +76,8 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
@JvmStatic
@Parameters(name = "{0}")
fun getParams(): List<FlagsParameterization> {
- return FlagsParameterization.allCombinationsOf().andSceneContainer()
+ return FlagsParameterization.allCombinationsOf(FLAG_GLANCEABLE_HUB_V2)
+ .andSceneContainer()
}
}
@@ -82,9 +85,22 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
mSetFlagsRule.setFlagsParameterization(flags)
}
- private val kosmos = testKosmos()
-
- private lateinit var underTest: CommunalSceneStartable
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+
+ private val Kosmos.underTest by
+ Kosmos.Fixture {
+ CommunalSceneStartable(
+ communalInteractor = communalInteractor,
+ communalSettingsInteractor = communalSettingsInteractor,
+ communalSceneInteractor = communalSceneInteractor,
+ keyguardInteractor = keyguardInteractor,
+ systemSettings = fakeSettings,
+ notificationShadeWindowController = notificationShadeWindowController,
+ bgScope = applicationCoroutineScope,
+ mainDispatcher = testDispatcher,
+ uiEventLogger = uiEventLoggerFake,
+ )
+ }
@Before
fun setUp() {
@@ -94,352 +110,314 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
SCREEN_TIMEOUT,
UserHandle.USER_CURRENT,
)
- kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
-
- underTest =
- CommunalSceneStartable(
- dockManager = dockManager,
- communalInteractor = communalInteractor,
- communalSettingsInteractor = communalSettingsInteractor,
- communalSceneInteractor = communalSceneInteractor,
- keyguardTransitionInteractor = keyguardTransitionInteractor,
- keyguardInteractor = keyguardInteractor,
- systemSettings = fakeSettings,
- notificationShadeWindowController = notificationShadeWindowController,
- applicationScope = applicationCoroutineScope,
- bgScope = applicationCoroutineScope,
- mainDispatcher = testDispatcher,
- centralSurfacesOpt = centralSurfacesOptional,
- uiEventLogger = uiEventLoggerFake,
- )
- .apply { start() }
+ fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
+
+ underTest.start()
// Make communal available so that communalInteractor.desiredScene accurately reflects
// scene changes instead of just returning Blank.
- with(kosmos.testScope) {
- launch { setCommunalAvailable(true) }
- testScheduler.runCurrent()
- }
+ runBlocking { setCommunalAvailable(true) }
+ setCommunalV2ConfigEnabled(true)
}
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_whenDreaming_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_notDreaming_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is not dreaming and on communal.
- updateDreaming(false)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- // Scene stays as Communal
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
- }
+ kosmos.runTest {
+ // Device is not dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(false)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ // Scene stays as Communal
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_dreamStopped_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Dream stops, timeout is cancelled and device stays on hub, because the regular
- // screen timeout will take effect at this point.
- updateDreaming(false)
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Dream stops, timeout is cancelled and device stays on hub, because the regular
+ // screen timeout will take effect at this point.
+ fakeKeyguardRepository.setDreaming(false)
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_dreamStartedHalfway_goesToCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal, but not dreaming.
- updateDreaming(false)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Wait a bit, but not long enough to timeout, then start dreaming.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- updateDreaming(true)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Device times out after one screen timeout interval, dream doesn't reset timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ kosmos.runTest {
+ // Device is on communal, but not dreaming.
+ fakeKeyguardRepository.setDreaming(false)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Wait a bit, but not long enough to timeout, then start dreaming.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ fakeKeyguardRepository.setDreaming(true)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Device times out after one screen timeout interval, dream doesn't reset timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_dreamAfterInitialTimeout_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal.
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- // Device stays on the hub after the timeout since we're not dreaming.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Start dreaming.
- updateDreaming(true)
- advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
-
- // Hub times out immediately.
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ kosmos.runTest {
+ // Device is on communal.
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ testScope.advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Start dreaming.
+ fakeKeyguardRepository.setDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS.milliseconds)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_userActivityTriggered_resetsTimeout() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- // Send user interaction to reset timeout.
- communalInteractor.signalUserInteraction()
+ // Send user interaction to reset timeout.
+ communalInteractor.signalUserInteraction()
- // If user activity didn't reset timeout, we would have gone back to Blank by now.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
+ // If user activity didn't reset timeout, we would have gone back to Blank by now.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
- // Timeout happens one interval after the user interaction.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- }
+ // Timeout happens one interval after the user interaction.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
}
@Test
- @DisableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_SCENE_CONTAINER, FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_screenTimeoutChanged() =
- with(kosmos) {
- testScope.runTest {
- fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
-
- // Device is dreaming and on communal.
- updateDreaming(true)
- communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
-
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
-
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
- assertThat(uiEventLoggerFake.logs.first().eventId)
- .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
- assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
- }
+ kosmos.runTest {
+ fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
+
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")
+
+ val scene by collectLastValue(communalSceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Communal)
+
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(CommunalScenes.Blank)
+ assertThat(uiEventLoggerFake.logs.first().eventId)
+ .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_whenDreaming_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_notDreaming_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is not dreaming and on communal.
- updateDreaming(false)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- // Scene stays as Communal
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
- }
+ kosmos.runTest {
+ // Device is not dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(false)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ // Scene stays as Communal
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_dreamStopped_staysOnCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Dream stops, timeout is cancelled and device stays on hub, because the regular
- // screen timeout will take effect at this point.
- updateDreaming(false)
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
- }
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Dream stops, timeout is cancelled and device stays on hub, because the regular
+ // screen timeout will take effect at this point.
+ fakeKeyguardRepository.setDreaming(false)
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_dreamStartedHalfway_goesToCommunal() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal, but not dreaming.
- updateDreaming(false)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Wait a bit, but not long enough to timeout, then start dreaming.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- updateDreaming(true)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Device times out after one screen timeout interval, dream doesn't reset timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ kosmos.runTest {
+ // Device is on communal, but not dreaming.
+ fakeKeyguardRepository.setDreaming(false)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Wait a bit, but not long enough to timeout, then start dreaming.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ fakeKeyguardRepository.setDreaming(true)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Device times out after one screen timeout interval, dream doesn't reset timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_dreamAfterInitialTimeout_goesToBlank() =
- with(kosmos) {
- testScope.runTest {
- // Device is on communal.
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- // Device stays on the hub after the timeout since we're not dreaming.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Start dreaming.
- updateDreaming(true)
- advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
-
- // Hub times out immediately.
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ kosmos.runTest {
+ // Device is on communal.
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ // Device stays on the hub after the timeout since we're not dreaming.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds * 2)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Start dreaming.
+ fakeKeyguardRepository.setDreaming(true)
+ advanceTimeBy(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS.milliseconds)
+
+ // Hub times out immediately.
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_userActivityTriggered_resetsTimeout() =
- with(kosmos) {
- testScope.runTest {
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
+ kosmos.runTest {
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
- // Wait a bit, but not long enough to timeout.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ // Wait a bit, but not long enough to timeout.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- // Send user interaction to reset timeout.
- communalInteractor.signalUserInteraction()
+ // Send user interaction to reset timeout.
+ communalInteractor.signalUserInteraction()
- // If user activity didn't reset timeout, we would have gone back to Blank by now.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
+ // If user activity didn't reset timeout, we would have gone back to Blank by now.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
- // Timeout happens one interval after the user interaction.
- advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- }
+ // Timeout happens one interval after the user interaction.
+ advanceTimeBy((SCREEN_TIMEOUT / 2).milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
}
@Test
@EnableFlags(FLAG_SCENE_CONTAINER)
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
fun hubTimeout_withSceneContainer_screenTimeoutChanged() =
- with(kosmos) {
- testScope.runTest {
- fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
-
- // Device is dreaming and on communal.
- updateDreaming(true)
- sceneInteractor.changeScene(Scenes.Communal, "test")
-
- val scene by collectLastValue(sceneInteractor.currentScene)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- // Scene times out back to blank after the screen timeout.
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(Scenes.Communal)
-
- advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
- assertThat(scene).isEqualTo(Scenes.Dream)
- assertThat(uiEventLoggerFake.logs.first().eventId)
- .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
- assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
- }
- }
+ kosmos.runTest {
+ fakeSettings.putInt(Settings.System.SCREEN_OFF_TIMEOUT, SCREEN_TIMEOUT * 2)
- private fun TestScope.updateDreaming(dreaming: Boolean) =
- with(kosmos) {
- fakeKeyguardRepository.setDreaming(dreaming)
- runCurrent()
+ // Device is dreaming and on communal.
+ fakeKeyguardRepository.setDreaming(true)
+ sceneInteractor.changeScene(Scenes.Communal, "test")
+
+ val scene by collectLastValue(sceneInteractor.currentScene)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ // Scene times out back to blank after the screen timeout.
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Communal)
+
+ advanceTimeBy(SCREEN_TIMEOUT.milliseconds)
+ assertThat(scene).isEqualTo(Scenes.Dream)
+ assertThat(uiEventLoggerFake.logs.first().eventId)
+ .isEqualTo(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT.id)
+ assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
}
+
+ /**
+ * Advances time by duration + 1 millisecond, to ensure that tasks scheduled to run at
+ * currentTime + duration are scheduled.
+ */
+ private fun Kosmos.advanceTimeBy(duration: Duration) =
+ testScope.advanceTimeBy(duration + 1.milliseconds)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index 4f956fc802e4..e36e85565293 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -19,8 +19,6 @@ package com.android.systemui.communal
import android.os.UserHandle
import android.provider.Settings
import com.android.app.tracing.coroutines.launchTraced as launch
-import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.TransitionKey
import com.android.internal.logging.UiEventLogger
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -31,25 +29,16 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes.isCommunal
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dock.DockManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.statusbar.NotificationShadeWindowController
-import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.systemui.util.kotlin.emitOnStart
-import com.android.systemui.util.kotlin.getValue
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import com.android.systemui.util.settings.SystemSettings
-import java.util.Optional
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
-import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -68,16 +57,12 @@ import kotlinx.coroutines.withContext
class CommunalSceneStartable
@Inject
constructor(
- private val dockManager: DockManager,
private val communalInteractor: CommunalInteractor,
private val communalSettingsInteractor: CommunalSettingsInteractor,
private val communalSceneInteractor: CommunalSceneInteractor,
- private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val keyguardInteractor: KeyguardInteractor,
private val systemSettings: SystemSettings,
- centralSurfacesOpt: Optional<CentralSurfaces>,
private val notificationShadeWindowController: NotificationShadeWindowController,
- @Application private val applicationScope: CoroutineScope,
@Background private val bgScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
private val uiEventLogger: UiEventLogger,
@@ -88,75 +73,85 @@ constructor(
private var isDreaming: Boolean = false
- private val centralSurfaces: CentralSurfaces? by centralSurfacesOpt
-
override fun start() {
if (!communalSettingsInteractor.isCommunalFlagEnabled()) {
return
}
- systemSettings
- .observerFlow(Settings.System.SCREEN_OFF_TIMEOUT)
- // Read the setting value on start.
- .emitOnStart()
- .onEach {
- screenTimeout =
- systemSettings.getIntForUser(
- Settings.System.SCREEN_OFF_TIMEOUT,
- DEFAULT_SCREEN_TIMEOUT,
- UserHandle.USER_CURRENT,
- )
- }
- .launchIn(bgScope)
-
- // The hub mode timeout should start as soon as the user enters hub mode. At the end of the
- // timer, if the device is dreaming, hub mode should closed and reveal the dream. If the
- // dream is not running, nothing will happen. However if the dream starts again underneath
- // hub mode after the initial timeout expires, such as if the device is docked or the dream
- // app is updated by the Play store, a new timeout should be started.
bgScope.launch {
- combine(
- communalSceneInteractor.currentScene,
- // Emit a value on start so the combine starts.
- communalInteractor.userActivity.emitOnStart(),
- ) { scene, _ ->
- // Only timeout if we're on the hub is open.
- scene.isCommunal()
- }
- .collectLatest { shouldTimeout ->
- cancelHubTimeout()
- if (shouldTimeout) {
- startHubTimeout()
- }
+ communalSceneInteractor.isIdleOnCommunal.collectLatest {
+ withContext(mainDispatcher) {
+ notificationShadeWindowController.setGlanceableHubShowing(it)
}
+ }
}
- bgScope.launch {
- keyguardInteractor.isDreaming
- .sample(communalSceneInteractor.currentScene, ::Pair)
- .collectLatest { (isDreaming, scene) ->
- this@CommunalSceneStartable.isDreaming = isDreaming
- if (scene.isCommunal() && isDreaming && timeoutJob == null) {
- // If dreaming starts after timeout has expired, ex. if dream restarts under
- // the hub, wait for IS_ABLE_TO_DREAM_DELAY_MS and then close the hub. The
- // delay is necessary so the KeyguardInteractor.isAbleToDream flow passes
- // through that same amount of delay and publishes a new value which is then
- // picked up by the HomeSceneFamilyResolver such that the next call to
- // SceneInteractor.changeScene(Home) will resolve "Home" to "Dream".
- delay(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
- communalSceneInteractor.changeScene(
- CommunalScenes.Blank,
- "dream started after timeout",
+
+ // In V2, the timeout is handled by PowerManagerService since we no longer keep the dream
+ // active underneath the hub.
+ if (!communalSettingsInteractor.isV2FlagEnabled()) {
+ systemSettings
+ .observerFlow(Settings.System.SCREEN_OFF_TIMEOUT)
+ // Read the setting value on start.
+ .emitOnStart()
+ .onEach {
+ screenTimeout =
+ systemSettings.getIntForUser(
+ Settings.System.SCREEN_OFF_TIMEOUT,
+ DEFAULT_SCREEN_TIMEOUT,
+ UserHandle.USER_CURRENT,
)
- uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
- }
}
- }
+ .launchIn(bgScope)
- bgScope.launch {
- communalSceneInteractor.isIdleOnCommunal.collectLatest {
- withContext(mainDispatcher) {
- notificationShadeWindowController.setGlanceableHubShowing(it)
- }
+ // The hub mode timeout should start as soon as the user enters hub mode. At the end of
+ // the
+ // timer, if the device is dreaming, hub mode should closed and reveal the dream. If the
+ // dream is not running, nothing will happen. However if the dream starts again
+ // underneath
+ // hub mode after the initial timeout expires, such as if the device is docked or the
+ // dream
+ // app is updated by the Play store, a new timeout should be started.
+ bgScope.launch {
+ combine(
+ communalSceneInteractor.currentScene,
+ // Emit a value on start so the combine starts.
+ communalInteractor.userActivity.emitOnStart(),
+ ) { scene, _ ->
+ // Only timeout if we're on the hub is open.
+ scene.isCommunal()
+ }
+ .collectLatest { shouldTimeout ->
+ cancelHubTimeout()
+ if (shouldTimeout) {
+ startHubTimeout()
+ }
+ }
+ }
+
+ bgScope.launch {
+ keyguardInteractor.isDreaming
+ .sample(communalSceneInteractor.currentScene, ::Pair)
+ .collectLatest { (isDreaming, scene) ->
+ this@CommunalSceneStartable.isDreaming = isDreaming
+ if (scene.isCommunal() && isDreaming && timeoutJob == null) {
+ // If dreaming starts after timeout has expired, ex. if dream restarts
+ // under
+ // the hub, wait for IS_ABLE_TO_DREAM_DELAY_MS and then close the hub.
+ // The
+ // delay is necessary so the KeyguardInteractor.isAbleToDream flow
+ // passes
+ // through that same amount of delay and publishes a new value which is
+ // then
+ // picked up by the HomeSceneFamilyResolver such that the next call to
+ // SceneInteractor.changeScene(Home) will resolve "Home" to "Dream".
+ delay(KeyguardInteractor.IS_ABLE_TO_DREAM_DELAY_MS)
+ communalSceneInteractor.changeScene(
+ CommunalScenes.Blank,
+ "dream started after timeout",
+ )
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_TIMEOUT)
+ }
+ }
}
}
}
@@ -187,49 +182,7 @@ constructor(
}
}
- private suspend fun determineSceneAfterTransition(
- lastStartedTransition: TransitionStep
- ): Pair<SceneKey, TransitionKey>? {
- val to = lastStartedTransition.to
- val from = lastStartedTransition.from
- val docked = dockManager.isDocked
- val launchingActivityOverLockscreen =
- centralSurfaces?.isLaunchingActivityOverLockscreen ?: false
-
- return when {
- to == KeyguardState.OCCLUDED && !launchingActivityOverLockscreen -> {
- // Hide communal when an activity is started on keyguard, to ensure the activity
- // underneath the hub is shown. When launching activities over lockscreen, we only
- // change scenes once the activity launch animation is finished, so avoid
- // changing the scene here.
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- }
- to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
- // When transitioning to the hub from an occluded state, fade out the hub without
- // doing any translation.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
- }
- // Transitioning to Blank scene when entering the edit mode will be handled separately
- // with custom animations.
- to == KeyguardState.GONE && !communalInteractor.editModeOpen.value ->
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- !docked && !KeyguardState.deviceIsAwakeInState(to) -> {
- // If the user taps the screen and wakes the device within this timeout, we don't
- // want to dismiss the hub
- delay(AWAKE_DEBOUNCE_DELAY)
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- }
- from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
- // Make sure the communal hub is showing when transitioning from dozing to hub.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
- }
- else -> null
- }
- }
-
companion object {
- val AWAKE_DEBOUNCE_DELAY = 5.seconds
- val DOCK_DEBOUNCE_DELAY = 1.seconds
val DEFAULT_SCREEN_TIMEOUT = 15000
}
}