summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author burakov <burakov@google.com> 2024-05-03 14:41:51 +0000
committer burakov <burakov@google.com> 2024-05-06 16:58:15 +0000
commit6bcca2e18adc1a54b32d9a56345b46d5a5a254a7 (patch)
tree33456b84a9b00cc3ef9d52ffe3d5868bf23a51e2
parente2d3dbdbeb9e0a1e5e612d3a6d9b7338ef9aba6c (diff)
[bc25] Create the `QuickSettingsShade` scene.
The scope of the CL includes the following: * New scene key for the Quick Settings Shade scene. * New module for the Quick Settings Shade scene. * Conditional references to the new scene key wherever appropriate. * Define the scene navigational mapping. * Create the new scene composable, reusing OverlayShade. * Create the scene view model with basic destination scenes mapping. * New unit tests for the QuickSettingsShadeSceneViewModel. Test: Manually verified by swiping down and swiping up on both the lockscreen and gone scenes, with the feature flag both enabled and disabled. Test: Added unit tests. Fix: 338009249. Flag: ACONFIG com.android.systemui.dual_shade DEVELOPMENT Change-Id: I001e14383e45b6a0f7ecb5d7cf1d3968cb87f99a
-rw-r--r--packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt29
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt71
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt124
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt29
16 files changed, 380 insertions, 10 deletions
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
new file mode 100644
index 000000000000..3d7401d8f263
--- /dev/null
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/QuickSettingsShadeSceneModule.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene
+
+import com.android.systemui.qs.ui.composable.QuickSettingsShadeScene
+import com.android.systemui.scene.shared.model.Scene
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+
+@Module
+interface QuickSettingsShadeSceneModule {
+
+ @Binds @IntoSet fun quickSettingsShade(scene: QuickSettingsShadeScene): Scene
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
new file mode 100644
index 000000000000..636c6c3b7d14
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.composable
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.ui.composable.ComposableScene
+import com.android.systemui.shade.ui.composable.OverlayShade
+import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+
+@SysUISingleton
+class QuickSettingsShadeScene
+@Inject
+constructor(
+ viewModel: QuickSettingsShadeSceneViewModel,
+ private val overlayShadeViewModel: OverlayShadeViewModel,
+) : ComposableScene {
+
+ override val key = Scenes.QuickSettingsShade
+
+ override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
+ viewModel.destinationScenes
+
+ @Composable
+ override fun SceneScope.Content(
+ modifier: Modifier,
+ ) {
+ OverlayShade(
+ viewModel = overlayShadeViewModel,
+ modifier = modifier,
+ horizontalArrangement = Arrangement.End,
+ ) {
+ Text(
+ text = "Quick settings grid",
+ modifier = Modifier.padding(QuickSettingsShade.Dimensions.Padding)
+ )
+ }
+ }
+}
+
+object QuickSettingsShade {
+ object Dimensions {
+ val Padding = 16.dp
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
new file mode 100644
index 000000000000..034c2e9b6789
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModelTest.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.viewmodel
+
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.Swipe
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.ui.viewmodel.quickSettingsShadeSceneViewModel
+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.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+@EnableSceneContainer
+class QuickSettingsShadeSceneViewModelTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val sceneInteractor = kosmos.sceneInteractor
+ private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
+
+ private val underTest = kosmos.quickSettingsShadeSceneViewModel
+
+ @Test
+ fun upTransitionSceneKey_deviceLocked_lockscreen() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ lockDevice()
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun upTransitionSceneKey_deviceUnlocked_gone() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ lockDevice()
+ unlockDevice()
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone)
+ }
+
+ @Test
+ fun upTransitionSceneKey_authMethodSwipe_lockscreenNotDismissed_goesToLockscreen() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.None
+ )
+ sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Lockscreen)
+ }
+
+ @Test
+ fun upTransitionSceneKey_authMethodSwipe_lockscreenDismissed_goesToGone() =
+ testScope.runTest {
+ val destinationScenes by collectLastValue(underTest.destinationScenes)
+ kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true)
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
+ AuthenticationMethodModel.None
+ )
+ runCurrent()
+ sceneInteractor.changeScene(Scenes.Gone, "reason")
+
+ assertThat(destinationScenes?.get(Swipe.Up)?.toScene).isEqualTo(Scenes.Gone)
+ }
+
+ private fun TestScope.lockDevice() {
+ val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)
+
+ kosmos.fakeAuthenticationRepository.setAuthenticationMethod(AuthenticationMethodModel.Pin)
+ assertThat(deviceUnlockStatus?.isUnlocked).isFalse()
+ sceneInteractor.changeScene(Scenes.Lockscreen, "reason")
+ runCurrent()
+ }
+
+ private fun TestScope.unlockDevice() {
+ val deviceUnlockStatus by collectLastValue(deviceUnlockedInteractor.deviceUnlockStatus)
+
+ kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus(
+ SuccessFingerprintAuthenticationStatus(0, true)
+ )
+ assertThat(deviceUnlockStatus?.isUnlocked).isTrue()
+ sceneInteractor.changeScene(Scenes.Gone, "reason")
+ runCurrent()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index 2c1e75e2263b..d8b50133949d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -100,7 +100,13 @@ constructor(
// Swiping down from the top edge goes to QS (or shade if in split shade mode).
swipeDownFromTop(pointerCount = 1) to quickSettingsIfSingleShade,
- swipeDownFromTop(pointerCount = 2) to quickSettingsIfSingleShade,
+ swipeDownFromTop(pointerCount = 2) to
+ // TODO(b/338577208): Remove 'Dual' once we add Dual Shade invocation zones.
+ if (shadeMode is ShadeMode.Dual) {
+ Scenes.QuickSettingsShade
+ } else {
+ quickSettingsIfSingleShade
+ },
// Swiping down, not from the edge, always navigates to the shade scene.
swipeDown(pointerCount = 1) to shadeSceneKey,
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index 0c07c0543246..89e4760615f0 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -85,7 +85,10 @@ constructor(
{
it.scene == Scenes.NotificationsShade || it.scene == Scenes.Shade
},
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it.scene == Scenes.QuickSettings },
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
+ {
+ it.scene == Scenes.QuickSettingsShade || it.scene == Scenes.QuickSettings
+ },
SYSUI_STATE_BOUNCER_SHOWING to { it.scene == Scenes.Bouncer },
SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
{
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt
new file mode 100644
index 000000000000..d48d55dd9918
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsShadeSceneViewModel.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.ui.viewmodel
+
+import com.android.compose.animation.scene.Back
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+/** Models UI state and handles user input for the Quick Settings Shade scene. */
+@SysUISingleton
+class QuickSettingsShadeSceneViewModel
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ overlayShadeViewModel: OverlayShadeViewModel,
+) {
+ val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
+ overlayShadeViewModel.backgroundScene
+ .map(::destinationScenes)
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = destinationScenes(overlayShadeViewModel.backgroundScene.value),
+ )
+
+ private fun destinationScenes(backgroundScene: SceneKey): Map<UserAction, UserActionResult> {
+ return mapOf(
+ Swipe.Up to backgroundScene,
+ Back to backgroundScene,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
index aa8ecfc41fc1..28569d817279 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/KeyguardlessSceneContainerFrameworkModule.kt
@@ -63,7 +63,8 @@ interface KeyguardlessSceneContainerFrameworkModule {
sceneKeys =
listOfNotNull(
Scenes.Gone,
- Scenes.QuickSettings,
+ Scenes.QuickSettings.takeUnless { DualShade.isEnabled },
+ Scenes.QuickSettingsShade.takeIf { DualShade.isEnabled },
Scenes.NotificationsShade.takeIf { DualShade.isEnabled },
Scenes.Shade.takeUnless { DualShade.isEnabled },
),
@@ -73,7 +74,8 @@ interface KeyguardlessSceneContainerFrameworkModule {
Scenes.Gone to 0,
Scenes.NotificationsShade to 1.takeIf { DualShade.isEnabled },
Scenes.Shade to 1.takeUnless { DualShade.isEnabled },
- Scenes.QuickSettings to 2,
+ Scenes.QuickSettingsShade to 2.takeIf { DualShade.isEnabled },
+ Scenes.QuickSettings to 2.takeUnless { DualShade.isEnabled },
)
.filterValues { it != null }
.mapValues { checkNotNull(it.value) }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 551aa124727d..dbe0342a5319 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -41,6 +41,7 @@ import dagger.multibindings.IntoMap
LockscreenSceneModule::class,
QuickSettingsSceneModule::class,
ShadeSceneModule::class,
+ QuickSettingsShadeSceneModule::class,
NotificationsShadeSceneModule::class,
],
)
@@ -71,7 +72,8 @@ interface SceneContainerFrameworkModule {
Scenes.Communal,
Scenes.Lockscreen,
Scenes.Bouncer,
- Scenes.QuickSettings,
+ Scenes.QuickSettings.takeUnless { DualShade.isEnabled },
+ Scenes.QuickSettingsShade.takeIf { DualShade.isEnabled },
Scenes.NotificationsShade.takeIf { DualShade.isEnabled },
Scenes.Shade.takeUnless { DualShade.isEnabled },
),
@@ -83,7 +85,8 @@ interface SceneContainerFrameworkModule {
Scenes.Communal to 1,
Scenes.NotificationsShade to 2.takeIf { DualShade.isEnabled },
Scenes.Shade to 2.takeUnless { DualShade.isEnabled },
- Scenes.QuickSettings to 3,
+ Scenes.QuickSettingsShade to 3.takeIf { DualShade.isEnabled },
+ Scenes.QuickSettings to 3.takeUnless { DualShade.isEnabled },
Scenes.Bouncer to 4,
)
.filterValues { it != null }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
index ace449136fad..6bcd92316106 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt
@@ -127,6 +127,7 @@ constructor(
Scenes.Lockscreen -> true
Scenes.NotificationsShade -> false
Scenes.QuickSettings -> false
+ Scenes.QuickSettingsShade -> false
Scenes.Shade -> false
else -> error("SceneKey \"$this\" doesn't have a mapping for canBeOccluded!")
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
index de3b87aebcd3..9c2b992c0de6 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/WindowRootViewVisibilityInteractor.kt
@@ -78,13 +78,16 @@ constructor(
is ObservableTransitionState.Idle ->
state.currentScene == Scenes.Shade ||
state.currentScene == Scenes.NotificationsShade ||
+ state.currentScene == Scenes.QuickSettingsShade ||
state.currentScene == Scenes.Lockscreen
is ObservableTransitionState.Transition ->
state.toScene == Scenes.Shade ||
state.toScene == Scenes.NotificationsShade ||
+ state.toScene == Scenes.QuickSettingsShade ||
state.toScene == Scenes.Lockscreen ||
state.fromScene == Scenes.Shade ||
state.fromScene == Scenes.NotificationsShade ||
+ state.fromScene == Scenes.QuickSettingsShade ||
state.fromScene == Scenes.Lockscreen
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
index 08f1be908afd..6d139da99345 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scenes.kt
@@ -47,19 +47,45 @@ object Scenes {
* overlay UI.
*
* It's used only in the dual shade configuration, where there are two separate shades: one for
- * notifications (this scene) and another for quick settings (where a separate scene is used).
+ * notifications (this scene) and another for [QuickSettingsShade].
*
* It's not used in the single/accordion configuration (swipe down once to reveal the shade,
- * swipe down again the to expand quick settings) and for the "split" shade configuration (on
+ * swipe down again the to expand quick settings) or in the "split" shade configuration (on
* large screens or unfolded foldables, where notifications and quick settings are shown
* side-by-side in their own columns).
*/
@JvmField val NotificationsShade = SceneKey("notifications_shade")
- /** The quick settings scene shows the quick setting tiles. */
+ /**
+ * The quick settings scene shows the quick setting tiles.
+ *
+ * This scene is used for single/accordion configuration (swipe down once to reveal the shade,
+ * swipe down again the to expand quick settings).
+ *
+ * For the "split" shade configuration (on large screens or unfolded foldables, where
+ * notifications and quick settings are shown side-by-side in their own columns), the [Shade]
+ * scene is used].
+ *
+ * For the dual shade configuration, where there are two separate shades: one for notifications
+ * and one for quick settings, [NotificationsShade] and [QuickSettingsShade] scenes are used
+ * respectively.
+ */
@JvmField val QuickSettings = SceneKey("quick_settings")
/**
+ * The quick settings shade scene shows the quick setting tiles as an overlay UI.
+ *
+ * It's used only in the dual shade configuration, where there are two separate shades: one for
+ * quick settings (this scene) and another for [NotificationsShade].
+ *
+ * It's not used in the single/accordion configuration (swipe down once to reveal the shade,
+ * swipe down again the to expand quick settings) or in the "split" shade configuration (on
+ * large screens or unfolded foldables, where notifications and quick settings are shown
+ * side-by-side in their own columns).
+ */
+ @JvmField val QuickSettingsShade = SceneKey("quick_settings_shade")
+
+ /**
* The shade is the scene that shows a scrollable list of notifications and the minimized
* version of quick settings (AKA "quick quick settings" or "QQS").
*
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
index e4435ccd205c..b0af7f9ce072 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
@@ -60,6 +60,16 @@ constructor(
)] = UserActionResult(Scenes.QuickSettings)
}
+ // TODO(b/338577208): Remove this once we add Dual Shade invocation zones.
+ if (shadeMode is ShadeMode.Dual) {
+ this[
+ Swipe(
+ pointerCount = 2,
+ fromSource = Edge.Top,
+ direction = SwipeDirection.Down,
+ )] = UserActionResult(Scenes.QuickSettingsShade)
+ }
+
this[Swipe(direction = SwipeDirection.Down)] =
UserActionResult(
if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 7fbede475e69..09c80b09a388 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -127,6 +127,7 @@ constructor(
Scenes.NotificationsShade -> Classifier.NOTIFICATION_DRAG_DOWN
Scenes.Shade -> Classifier.NOTIFICATION_DRAG_DOWN
Scenes.QuickSettings -> Classifier.QUICK_SETTINGS
+ Scenes.QuickSettingsShade -> Classifier.QUICK_SETTINGS
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 5cc30bd8c27f..43e782c44206 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -203,7 +203,11 @@ constructor(
}
override fun expandToQs() {
- sceneInteractor.changeScene(Scenes.QuickSettings, "ShadeController.animateExpandQs")
+ val shadeMode = shadeInteractor.shadeMode.value
+ sceneInteractor.changeScene(
+ if (shadeMode is ShadeMode.Dual) Scenes.QuickSettingsShade else Scenes.QuickSettings,
+ "ShadeController.animateExpandQs"
+ )
}
override fun setVisibilityListener(listener: ShadeVisibilityListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 96a50f7686b9..70632d5aa27a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -679,6 +679,7 @@ public class StatusBarStateControllerImpl implements
Scenes.Shade, StatusBarState.SHADE_LOCKED,
Scenes.NotificationsShade, StatusBarState.SHADE_LOCKED,
Scenes.QuickSettings, StatusBarState.SHADE_LOCKED,
+ Scenes.QuickSettingsShade, StatusBarState.SHADE_LOCKED,
Scenes.Gone, StatusBarState.SHADE
);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt
new file mode 100644
index 000000000000..8c5ff1d5d216
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/QuickSettingsShadeSceneViewModelKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
+
+val Kosmos.quickSettingsShadeSceneViewModel: QuickSettingsShadeSceneViewModel by
+ Kosmos.Fixture {
+ QuickSettingsShadeSceneViewModel(
+ applicationScope = applicationCoroutineScope,
+ overlayShadeViewModel = overlayShadeViewModel,
+ )
+ }