summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author burakov <burakov@google.com> 2024-09-25 11:52:14 +0000
committer burakov <burakov@google.com> 2024-09-27 12:03:24 +0000
commite46d53bb215e0723c5ebc44ed70f26bcb418cf3d (patch)
tree956c363aa0a5b060946a58ac80d68ea3767a7394
parent0a415b7b132652597ffb8379ff9c50c99fea243e (diff)
[bc25] Collapse the shade when switching to bouncer.
Bug: 356596436 Bug: 369513770 Flag: com.android.systemui.scene_container Flag: com.android.systemui.dual_shade Test: Added unit tests. Test: Existing unit tests still pass. Test: Verified manually by opening both shades on lockscreen, long pressing on Bluetooth, and observing that the shade is closed while the bouncer opens. Change-Id: I5edc7e72e65c5af729a957d0ad962b7c1fb2e5c2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt89
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt89
-rw-r--r--packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt42
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt43
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt2
6 files changed, 255 insertions, 12 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
index 3388c75bcf78..ada2138d4d52 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModelTest.kt
@@ -21,19 +21,34 @@ import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
+import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.shade.ui.viewmodel.notificationsShadeOverlayContentViewModel
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@@ -47,18 +62,84 @@ class NotificationsShadeOverlayContentViewModelTest : SysuiTestCase() {
private val underTest by lazy { kosmos.notificationsShadeOverlayContentViewModel }
+ @Before
+ fun setUp() {
+ kosmos.sceneContainerStartable.start()
+ underTest.activateIn(testScope)
+ }
+
@Test
fun onScrimClicked_hidesShade() =
testScope.runTest {
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- sceneInteractor.showOverlay(
- overlay = Overlays.NotificationsShade,
- loggingReason = "test",
- )
+ sceneInteractor.showOverlay(Overlays.NotificationsShade, "test")
assertThat(currentOverlays).contains(Overlays.NotificationsShade)
underTest.onScrimClicked()
assertThat(currentOverlays).doesNotContain(Overlays.NotificationsShade)
}
+
+ @Test
+ fun deviceLocked_hidesShade() =
+ testScope.runTest {
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ unlockDevice()
+ sceneInteractor.showOverlay(Overlays.NotificationsShade, "test")
+ assertThat(currentOverlays).contains(Overlays.NotificationsShade)
+
+ lockDevice()
+
+ assertThat(currentOverlays).doesNotContain(Overlays.NotificationsShade)
+ }
+
+ @Test
+ fun bouncerShown_hidesShade() =
+ testScope.runTest {
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ lockDevice()
+ sceneInteractor.showOverlay(Overlays.NotificationsShade, "test")
+ assertThat(currentOverlays).contains(Overlays.NotificationsShade)
+
+ sceneInteractor.changeScene(Scenes.Bouncer, "test")
+ runCurrent()
+
+ assertThat(currentOverlays).doesNotContain(Overlays.NotificationsShade)
+ }
+
+ @Test
+ fun shadeNotTouchable_hidesShade() =
+ testScope.runTest {
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val isShadeTouchable by collectLastValue(kosmos.shadeInteractor.isShadeTouchable)
+ assertThat(isShadeTouchable).isTrue()
+ sceneInteractor.showOverlay(Overlays.NotificationsShade, "test")
+ assertThat(currentOverlays).contains(Overlays.NotificationsShade)
+
+ lockDevice()
+ assertThat(isShadeTouchable).isFalse()
+ assertThat(currentOverlays).doesNotContain(Overlays.NotificationsShade)
+ }
+
+ private fun TestScope.lockDevice() {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ kosmos.powerInteractor.setAsleepForTest()
+ runCurrent()
+
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ private suspend fun TestScope.unlockDevice() {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ kosmos.powerInteractor.setAwakeForTest()
+ runCurrent()
+ assertThat(
+ kosmos.authenticationInteractor.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN
+ )
+ )
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
+
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt
index 8c7ec4743e7c..f32894dfd383 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelTest.kt
@@ -21,18 +21,33 @@ import android.testing.TestableLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
+import com.android.systemui.authentication.domain.interactor.AuthenticationResult
+import com.android.systemui.authentication.domain.interactor.authenticationInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
+import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
+import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.domain.startable.sceneContainerStartable
import com.android.systemui.scene.shared.model.Overlays
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
@@ -46,18 +61,84 @@ class QuickSettingsShadeOverlayContentViewModelTest : SysuiTestCase() {
private val underTest by lazy { kosmos.quickSettingsShadeOverlayContentViewModel }
+ @Before
+ fun setUp() {
+ kosmos.sceneContainerStartable.start()
+ underTest.activateIn(testScope)
+ }
+
@Test
fun onScrimClicked_hidesShade() =
testScope.runTest {
val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
- sceneInteractor.showOverlay(
- overlay = Overlays.QuickSettingsShade,
- loggingReason = "test",
- )
+ sceneInteractor.showOverlay(Overlays.QuickSettingsShade, "test")
assertThat(currentOverlays).contains(Overlays.QuickSettingsShade)
underTest.onScrimClicked()
assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade)
}
+
+ @Test
+ fun deviceLocked_hidesShade() =
+ testScope.runTest {
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ unlockDevice()
+ sceneInteractor.showOverlay(Overlays.QuickSettingsShade, "test")
+ assertThat(currentOverlays).contains(Overlays.QuickSettingsShade)
+
+ lockDevice()
+
+ assertThat(currentOverlays).isEmpty()
+ }
+
+ @Test
+ fun bouncerShown_hidesShade() =
+ testScope.runTest {
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ lockDevice()
+ sceneInteractor.showOverlay(Overlays.QuickSettingsShade, "test")
+ assertThat(currentOverlays).contains(Overlays.QuickSettingsShade)
+
+ sceneInteractor.changeScene(Scenes.Bouncer, "test")
+ runCurrent()
+
+ assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade)
+ }
+
+ @Test
+ fun shadeNotTouchable_hidesShade() =
+ testScope.runTest {
+ val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
+ val isShadeTouchable by collectLastValue(kosmos.shadeInteractor.isShadeTouchable)
+ assertThat(isShadeTouchable).isTrue()
+ sceneInteractor.showOverlay(Overlays.QuickSettingsShade, "test")
+ assertThat(currentOverlays).contains(Overlays.QuickSettingsShade)
+
+ lockDevice()
+ assertThat(isShadeTouchable).isFalse()
+ assertThat(currentOverlays).doesNotContain(Overlays.QuickSettingsShade)
+ }
+
+ private fun TestScope.lockDevice() {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ kosmos.powerInteractor.setAsleepForTest()
+ runCurrent()
+
+ assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ private suspend fun TestScope.unlockDevice() {
+ val currentScene by collectLastValue(sceneInteractor.currentScene)
+ kosmos.powerInteractor.setAwakeForTest()
+ runCurrent()
+ assertThat(
+ kosmos.authenticationInteractor.authenticate(
+ FakeAuthenticationRepository.DEFAULT_PIN
+ )
+ )
+ .isEqualTo(AuthenticationResult.SUCCEEDED)
+
+ assertThat(currentScene).isEqualTo(Scenes.Gone)
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
index 219e45c36b50..0e5404164ba1 100644
--- a/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/notifications/ui/viewmodel/NotificationsShadeOverlayContentViewModel.kt
@@ -16,11 +16,19 @@
package com.android.systemui.notifications.ui.viewmodel
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.launch
/**
* Models UI state used to render the content of the notifications shade overlay.
@@ -33,10 +41,40 @@ class NotificationsShadeOverlayContentViewModel
constructor(
val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
+ val sceneInteractor: SceneInteractor,
private val shadeInteractor: ShadeInteractor,
-) {
+) : ExclusiveActivatable() {
+
+ override suspend fun onActivated(): Nothing {
+ coroutineScope {
+ launch {
+ sceneInteractor.currentScene.collect { currentScene ->
+ when (currentScene) {
+ // TODO(b/369513770): The ShadeSession should be preserved in this scenario.
+ Scenes.Bouncer ->
+ shadeInteractor.collapseNotificationsShade(
+ loggingReason = "bouncer shown while shade is open"
+ )
+ }
+ }
+ }
+
+ launch {
+ shadeInteractor.isShadeTouchable
+ .distinctUntilChanged()
+ .filter { !it }
+ .collect {
+ shadeInteractor.collapseNotificationsShade(
+ loggingReason = "device became non-interactive"
+ )
+ }
+ }
+ }
+ awaitCancellation()
+ }
+
fun onScrimClicked() {
- shadeInteractor.collapseNotificationsShade(loggingReason = "Shade scrim clicked")
+ shadeInteractor.collapseNotificationsShade(loggingReason = "shade scrim clicked")
}
@AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt
index 7c8fbeaec0d5..afb9a788ec24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModel.kt
@@ -16,10 +16,18 @@
package com.android.systemui.qs.ui.viewmodel
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.launch
/**
* Models UI state used to render the content of the quick settings shade overlay.
@@ -31,11 +39,42 @@ class QuickSettingsShadeOverlayContentViewModel
@AssistedInject
constructor(
val shadeInteractor: ShadeInteractor,
+ val sceneInteractor: SceneInteractor,
val shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory,
val quickSettingsContainerViewModel: QuickSettingsContainerViewModel,
-) {
+) : ExclusiveActivatable() {
+
+ override suspend fun onActivated(): Nothing {
+ coroutineScope {
+ launch {
+ sceneInteractor.currentScene.collect { currentScene ->
+ when (currentScene) {
+ // TODO(b/369513770): The ShadeSession should be preserved in this scenario.
+ Scenes.Bouncer ->
+ shadeInteractor.collapseQuickSettingsShade(
+ loggingReason = "bouncer shown while shade is open"
+ )
+ }
+ }
+ }
+
+ launch {
+ shadeInteractor.isShadeTouchable
+ .distinctUntilChanged()
+ .filter { !it }
+ .collect {
+ shadeInteractor.collapseQuickSettingsShade(
+ loggingReason = "device became non-interactive"
+ )
+ }
+ }
+ }
+
+ awaitCancellation()
+ }
+
fun onScrimClicked() {
- shadeInteractor.collapseQuickSettingsShade(loggingReason = "Shade scrim clicked")
+ shadeInteractor.collapseQuickSettingsShade(loggingReason = "shade scrim clicked")
}
@AssistedFactory
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt
index a80a4095a264..6540ed6bba45 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeOverlayContentViewModelKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory
@@ -24,6 +25,7 @@ val Kosmos.quickSettingsShadeOverlayContentViewModel: QuickSettingsShadeOverlayC
Kosmos.Fixture {
QuickSettingsShadeOverlayContentViewModel(
shadeInteractor = shadeInteractor,
+ sceneInteractor = sceneInteractor,
shadeHeaderViewModelFactory = shadeHeaderViewModelFactory,
quickSettingsContainerViewModel = quickSettingsContainerViewModel,
)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
index 7a15fdf95734..718347fc3490 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeOverlayContentViewModelKosmos.kt
@@ -19,6 +19,7 @@ package com.android.systemui.shade.ui.viewmodel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationsPlaceholderViewModelFactory
@@ -27,6 +28,7 @@ val Kosmos.notificationsShadeOverlayContentViewModel:
NotificationsShadeOverlayContentViewModel(
shadeHeaderViewModelFactory = shadeHeaderViewModelFactory,
notificationsPlaceholderViewModelFactory = notificationsPlaceholderViewModelFactory,
+ sceneInteractor = sceneInteractor,
shadeInteractor = shadeInteractor,
)
}