diff options
12 files changed, 395 insertions, 132 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt index 2a2817b9af73..ad2b23e49536 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt @@ -88,6 +88,26 @@ class ShadeModeInteractorImplTest : SysuiTestCase() { } @Test + @EnableFlags(DualShade.FLAG_NAME) + fun isDualShade_flagEnabled_true() = + testScope.runTest { + // Initiate collection. + val shadeMode by collectLastValue(underTest.shadeMode) + + assertThat(underTest.isDualShade).isTrue() + } + + @Test + @DisableFlags(DualShade.FLAG_NAME) + fun isDualShade_flagDisabled_false() = + testScope.runTest { + // Initiate collection. + val shadeMode by collectLastValue(underTest.shadeMode) + + assertThat(underTest.isDualShade).isFalse() + } + + @Test fun getTopEdgeSplitFraction_narrowScreen_splitInHalf() = testScope.runTest { // Ensure isShadeLayoutWide is collected. diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index a402a9d5ae7c..ac49e91c777c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -101,10 +101,10 @@ import com.android.systemui.navigationbar.views.buttons.KeyButtonView; import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener; import com.android.systemui.scene.domain.interactor.SceneInteractor; import com.android.systemui.scene.shared.flag.SceneContainerFlag; -import com.android.systemui.scene.shared.model.SceneFamilies; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeViewController; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.QuickStepContract; @@ -158,6 +158,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis private final ScreenPinningRequest mScreenPinningRequest; private final NotificationShadeWindowController mStatusBarWinController; private final Provider<SceneInteractor> mSceneInteractor; + private final Provider<ShadeInteractor> mShadeInteractor; private final KeyboardTouchpadEduStatsInteractor mKeyboardTouchpadEduStatsInteractor; @@ -246,11 +247,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } else if (action == ACTION_UP) { // Gesture was too short to be picked up by scene container touch - // handling; programmatically start the transition to shade scene. - mSceneInteractor.get().changeScene( - SceneFamilies.NotifShade, - "short launcher swipe" - ); + // handling; programmatically start the transition to the shade. + mShadeInteractor.get().expandNotificationShade("short launcher swipe"); } } event.recycle(); @@ -267,10 +265,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mSceneInteractor.get().onRemoteUserInputStarted( "trackpad swipe"); } else if (action == ACTION_UP) { - mSceneInteractor.get().changeScene( - SceneFamilies.NotifShade, - "short trackpad swipe" - ); + mShadeInteractor.get().expandNotificationShade("short trackpad swipe"); } mStatusBarWinController.getWindowRootView().dispatchTouchEvent(event); } else { @@ -652,6 +647,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, Provider<SceneInteractor> sceneInteractor, + Provider<ShadeInteractor> shadeInteractor, UserTracker userTracker, UserManager userManager, WakefulnessLifecycle wakefulnessLifecycle, @@ -688,6 +684,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis mScreenPinningRequest = screenPinningRequest; mStatusBarWinController = statusBarWinController; mSceneInteractor = sceneInteractor; + mShadeInteractor = shadeInteractor; mUserTracker = userTracker; mConnectionBackoffAttempts = 0; mRecentsComponentName = ComponentName.unflattenFromString(context.getString( diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt index 5d03a28e7f09..361226a4df18 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt @@ -91,17 +91,14 @@ constructor( } override fun instantCollapseShade() { - sceneInteractor.snapToScene( - SceneFamilies.Home, - "hide shade", - ) + sceneInteractor.snapToScene(SceneFamilies.Home, "hide shade") } override fun animateCollapseShade( flags: Int, force: Boolean, delayed: Boolean, - speedUpFactor: Float + speedUpFactor: Float, ) { if (!force && !shadeInteractor.isAnyExpanded.value) { runPostCollapseActions() @@ -147,7 +144,7 @@ constructor( if (shadeInteractor.isAnyExpanded.value) { commandQueue.animateCollapsePanels( CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, - true /* force */ + true, /* force */ ) assistManagerLazy.get().hideAssist() } @@ -172,17 +169,11 @@ constructor( } override fun expandToNotifications() { - sceneInteractor.changeScene( - SceneFamilies.NotifShade, - "ShadeController.animateExpandShade", - ) + shadeInteractor.expandNotificationShade("ShadeController.animateExpandShade") } override fun expandToQs() { - sceneInteractor.changeScene( - SceneFamilies.QuickSettings, - "ShadeController.animateExpandQs", - ) + shadeInteractor.expandQuickSettingsShade("ShadeController.animateExpandQs") } override fun setVisibilityListener(listener: ShadeVisibilityListener) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt index 6fb96da2c186..b046c50b05d3 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt @@ -140,6 +140,18 @@ interface BaseShadeInteractor { * animating. */ val isUserInteractingWithQs: Flow<Boolean> + + /** + * Triggers the expansion (opening) of the notification shade. If the notification shade is + * already open, this has no effect. + */ + fun expandNotificationShade(loggingReason: String) + + /** + * Triggers the expansion (opening) of the quick settings shade. If the quick settings shade is + * already open, this has no effect. + */ + fun expandQuickSettingsShade(loggingReason: String) } fun createAnyExpansionFlow( diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt index 6c0b55a5dd57..fb1482890b87 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt @@ -49,4 +49,8 @@ class ShadeInteractorEmptyImpl @Inject constructor() : ShadeInteractor { override val isShadeLayoutWide: StateFlow<Boolean> = inactiveFlowBoolean override fun getTopEdgeSplitFraction(): Float = 0.5f + + override fun expandNotificationShade(loggingReason: String) {} + + override fun expandQuickSettingsShade(loggingReason: String) {} } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt index f48e31e1d7eb..df094864a71b 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt @@ -61,7 +61,7 @@ constructor( keyguardRepository.statusBarState, repository.legacyShadeExpansion, repository.qsExpansion, - sharedNotificationContainerInteractor.isSplitShadeEnabled + sharedNotificationContainerInteractor.isSplitShadeEnabled, ) { lockscreenShadeExpansion, statusBarState, @@ -97,13 +97,13 @@ constructor( repository.legacyExpandedOrAwaitingInputTransfer.stateIn( scope, SharingStarted.Eagerly, - false + false, ) override val isUserInteractingWithShade: Flow<Boolean> = combine( userInteractingFlow(repository.legacyShadeTracking, repository.legacyShadeExpansion), - repository.legacyLockscreenShadeTracking + repository.legacyLockscreenShadeTracking, ) { legacyShadeTracking, legacyLockscreenShadeTracking -> legacyShadeTracking || legacyLockscreenShadeTracking } @@ -111,6 +111,18 @@ constructor( override val isUserInteractingWithQs: Flow<Boolean> = userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion) + override fun expandNotificationShade(loggingReason: String) { + throw UnsupportedOperationException( + "expandNotificationShade() is not supported in legacy shade" + ) + } + + override fun expandQuickSettingsShade(loggingReason: String) { + throw UnsupportedOperationException( + "expandQuickSettingsShade() is not supported in legacy shade" + ) + } + /** * Return a flow for whether a user is interacting with an expandable shade component using * tracking and expansion flows. NOTE: expansion must be a `StateFlow` to guarantee that @@ -118,7 +130,7 @@ constructor( */ private fun userInteractingFlow( tracking: Flow<Boolean>, - expansion: StateFlow<Float> + expansion: StateFlow<Float>, ): Flow<Boolean> { return flow { // initial value is false diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt index e84cfa51dd67..81bf712f21e5 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt @@ -17,81 +17,70 @@ package com.android.systemui.shade.domain.interactor import com.android.app.tracing.FlowTracing.traceAsCounter +import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.OverlayKey import com.android.compose.animation.scene.SceneKey import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlag -import com.android.systemui.scene.shared.model.SceneFamilies -import com.android.systemui.shade.data.repository.ShadeRepository +import com.android.systemui.scene.shared.model.Overlays +import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** ShadeInteractor implementation for Scene Container. */ +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class ShadeInteractorSceneContainerImpl @Inject constructor( @Application scope: CoroutineScope, - sceneInteractor: SceneInteractor, - shadeRepository: ShadeRepository, + private val sceneInteractor: SceneInteractor, + private val shadeModeInteractor: ShadeModeInteractor, ) : BaseShadeInteractor { init { SceneContainerFlag.assertInNewMode() } override val shadeExpansion: StateFlow<Float> = - sceneBasedExpansion(sceneInteractor, SceneFamilies.NotifShade) + shadeModeInteractor.shadeMode + .flatMapLatest { shadeMode -> + transitionProgressExpansion(shadeMode.notificationsContentKey) + } .traceAsCounter("panel_expansion") { (it * 100f).toInt() } .stateIn(scope, SharingStarted.Eagerly, 0f) - private val sceneBasedQsExpansion = - sceneBasedExpansion(sceneInteractor, SceneFamilies.QuickSettings) - override val qsExpansion: StateFlow<Float> = - combine( - shadeRepository.isShadeLayoutWide, - shadeExpansion, - sceneBasedQsExpansion, - ) { isSplitShadeEnabled, shadeExpansion, qsExpansion -> - if (isSplitShadeEnabled) { - shadeExpansion - } else { - qsExpansion - } - } + shadeModeInteractor.shadeMode + .flatMapLatest { shadeMode -> transitionProgressExpansion(shadeMode.qsContentKey) } .stateIn(scope, SharingStarted.Eagerly, 0f) override val isQsExpanded: StateFlow<Boolean> = - qsExpansion - .map { it > 0 } - .distinctUntilChanged() - .stateIn(scope, SharingStarted.Eagerly, false) + qsExpansion.map { it > 0 }.stateIn(scope, SharingStarted.Eagerly, false) override val isQsBypassingShade: Flow<Boolean> = - combine( - sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings), - sceneInteractor.resolveSceneFamily(SceneFamilies.NotifShade), - ::Pair - ) - .flatMapLatestConflated { (quickSettingsScene, notificationsScene) -> + shadeModeInteractor.shadeMode + .flatMapLatestConflated { shadeMode -> sceneInteractor.transitionState .map { state -> when (state) { is ObservableTransitionState.Idle -> false is ObservableTransitionState.Transition -> - state.toContent == quickSettingsScene && - state.fromContent != notificationsScene + state.toContent == shadeMode.qsContentKey && + state.fromContent != shadeMode.notificationsContentKey } } .distinctUntilChanged() @@ -99,21 +88,22 @@ constructor( .distinctUntilChanged() override val isQsFullscreen: Flow<Boolean> = - combine( - shadeRepository.isShadeLayoutWide, - sceneInteractor.resolveSceneFamily(SceneFamilies.QuickSettings), - ::Pair - ) - .flatMapLatestConflated { (isShadeLayoutWide, quickSettingsScene) -> - sceneInteractor.transitionState - .map { state -> - when (state) { - is ObservableTransitionState.Idle -> - !isShadeLayoutWide && state.currentScene == quickSettingsScene - is ObservableTransitionState.Transition -> false - } - } - .distinctUntilChanged() + shadeModeInteractor.shadeMode + .flatMapLatest { shadeMode -> + when (shadeMode) { + ShadeMode.Single -> + sceneInteractor.transitionState + .map { state -> + when (state) { + is ObservableTransitionState.Idle -> + state.currentScene == Scenes.QuickSettings + is ObservableTransitionState.Transition -> false + } + } + .distinctUntilChanged() + ShadeMode.Split, + ShadeMode.Dual -> flowOf(false) + } } .distinctUntilChanged() @@ -121,16 +111,79 @@ constructor( createAnyExpansionFlow(scope, shadeExpansion, qsExpansion) override val isAnyExpanded = - anyExpansion - .map { it > 0f } - .distinctUntilChanged() - .stateIn(scope, SharingStarted.Eagerly, false) + anyExpansion.map { it > 0f }.stateIn(scope, SharingStarted.Eagerly, false) override val isUserInteractingWithShade: Flow<Boolean> = - sceneBasedInteracting(sceneInteractor, SceneFamilies.NotifShade) + shadeModeInteractor.shadeMode.flatMapLatest { shadeMode -> + when (shadeMode) { + ShadeMode.Single, + ShadeMode.Split -> sceneBasedInteracting(sceneInteractor, Scenes.Shade) + ShadeMode.Dual -> + overlayBasedInteracting(sceneInteractor, Overlays.NotificationsShade) + } + } override val isUserInteractingWithQs: Flow<Boolean> = - sceneBasedInteracting(sceneInteractor, SceneFamilies.QuickSettings) + shadeModeInteractor.shadeMode.flatMapLatest { shadeMode -> + when (shadeMode) { + ShadeMode.Single -> sceneBasedInteracting(sceneInteractor, Scenes.QuickSettings) + ShadeMode.Split -> sceneBasedInteracting(sceneInteractor, Scenes.Shade) + ShadeMode.Dual -> + overlayBasedInteracting(sceneInteractor, Overlays.QuickSettingsShade) + } + } + + override fun expandNotificationShade(loggingReason: String) { + if (shadeModeInteractor.isDualShade) { + if (Overlays.QuickSettingsShade in sceneInteractor.currentOverlays.value) { + sceneInteractor.replaceOverlay( + from = Overlays.QuickSettingsShade, + to = Overlays.NotificationsShade, + loggingReason = loggingReason, + ) + } else { + sceneInteractor.showOverlay( + overlay = Overlays.NotificationsShade, + loggingReason = loggingReason, + ) + } + } else { + sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = loggingReason) + } + } + + override fun expandQuickSettingsShade(loggingReason: String) { + if (shadeModeInteractor.isDualShade) { + if (Overlays.NotificationsShade in sceneInteractor.currentOverlays.value) { + sceneInteractor.replaceOverlay( + from = Overlays.NotificationsShade, + to = Overlays.QuickSettingsShade, + loggingReason = loggingReason, + ) + } else { + sceneInteractor.showOverlay( + overlay = Overlays.QuickSettingsShade, + loggingReason = loggingReason, + ) + } + } else { + sceneInteractor.changeScene( + toScene = Scenes.QuickSettings, + loggingReason = loggingReason, + ) + } + } + + /** + * Returns a flow that uses scene transition progress to and from a content to a 0-1 expansion + * amount float. + */ + private fun transitionProgressExpansion(contentKey: ContentKey): Flow<Float> { + return when (contentKey) { + is SceneKey -> sceneBasedExpansion(sceneInteractor, contentKey) + is OverlayKey -> overlayBasedExpansion(sceneInteractor, contentKey) + } + } /** * Returns a flow that uses scene transition progress to and from a scene that is pulled down @@ -181,4 +234,60 @@ constructor( } } .distinctUntilChanged() + + /** + * Returns a flow that uses scene transition progress to and from [overlay] to a 0-1 expansion + * amount float. + */ + private fun overlayBasedExpansion(sceneInteractor: SceneInteractor, overlay: OverlayKey) = + sceneInteractor.transitionState + .flatMapLatestConflated { state -> + when (state) { + is ObservableTransitionState.Idle -> + flowOf(if (overlay in state.currentOverlays) 1f else 0f) + is ObservableTransitionState.Transition -> + if (state.toContent == overlay) { + state.progress + } else if (state.fromContent == overlay) { + state.progress.map { progress -> 1 - progress } + } else { + flowOf(0f) + } + } + } + .distinctUntilChanged() + + /** + * Returns a flow that uses scene transition data to determine whether the user is interacting + * with [overlay]. + */ + private fun overlayBasedInteracting(sceneInteractor: SceneInteractor, overlay: OverlayKey) = + sceneInteractor.transitionState + .map { state -> + when (state) { + is ObservableTransitionState.Idle -> false + is ObservableTransitionState.Transition -> + state.isInitiatedByUserInput && + (state.toContent == overlay || state.fromContent == overlay) + } + } + .distinctUntilChanged() + + private val ShadeMode.notificationsContentKey: ContentKey + get() { + return when (this) { + ShadeMode.Single, + ShadeMode.Split -> Scenes.Shade + ShadeMode.Dual -> Overlays.NotificationsShade + } + } + + private val ShadeMode.qsContentKey: ContentKey + get() { + return when (this) { + ShadeMode.Single -> Scenes.QuickSettings + ShadeMode.Split -> Scenes.Shade + ShadeMode.Dual -> Overlays.QuickSettingsShade + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt index e525b86a2f9e..0fb379017be9 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeLockscreenInteractorImpl.kt @@ -21,9 +21,10 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.scene.domain.interactor.SceneInteractor -import com.android.systemui.scene.shared.model.SceneFamilies +import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.ShadeRepository +import com.android.systemui.shade.shared.model.ShadeMode import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -45,10 +46,14 @@ constructor( override val udfpsTransitionToFullShadeProgress = shadeRepository.udfpsTransitionToFullShadeProgress + @Deprecated("Use ShadeInteractor instead") override fun expandToNotifications() { - changeToShadeScene() + shadeInteractor.expandNotificationShade( + loggingReason = "ShadeLockscreenInteractorImpl.expandToNotifications" + ) } + @Deprecated("Use ShadeInteractor instead") override val isExpanded get() = shadeInteractor.isAnyExpanded.value @@ -60,15 +65,26 @@ constructor( lockIconViewController.dozeTimeTick() } + @Deprecated("Not supported by scenes") override fun blockExpansionForCurrentTouch() { // TODO("b/324280998") Implement replacement or delete } override fun resetViews(animate: Boolean) { + val loggingReason = "ShadeLockscreenInteractorImpl.resetViews" // The existing comment to the only call to this claims it only calls it to collapse QS - changeToShadeScene() + if (shadeInteractor.shadeMode.value == ShadeMode.Dual) { + // TODO(b/356596436): Hide without animation if !animate. + sceneInteractor.hideOverlay( + overlay = Overlays.QuickSettingsShade, + loggingReason = loggingReason, + ) + } else { + shadeInteractor.expandNotificationShade(loggingReason) + } } + @Deprecated("Not supported by scenes") override fun setPulsing(pulsing: Boolean) { // Now handled elsewhere. Do nothing. } @@ -76,22 +92,30 @@ constructor( override fun transitionToExpandedShade(delay: Long) { backgroundScope.launch { delay(delay) - withContext(mainDispatcher) { changeToShadeScene() } + withContext(mainDispatcher) { + shadeInteractor.expandNotificationShade( + "ShadeLockscreenInteractorImpl.transitionToExpandedShade" + ) + } } } + @Deprecated("Not supported by scenes") override fun resetViewGroupFade() { // Now handled elsewhere. Do nothing. } + @Deprecated("Not supported by scenes") override fun setKeyguardTransitionProgress(keyguardAlpha: Float, keyguardTranslationY: Int) { // Now handled elsewhere. Do nothing. } + @Deprecated("Not supported by scenes") override fun setOverStretchAmount(amount: Float) { // Now handled elsewhere. Do nothing. } + @Deprecated("TODO(b/325072511) delete this") override fun setKeyguardStatusBarAlpha(alpha: Float) { // TODO(b/325072511) delete this } @@ -100,11 +124,4 @@ constructor( sceneInteractor.changeScene(Scenes.Lockscreen, "showAodUi", sceneState = KeyguardState.AOD) // TODO(b/330311871) implement transition to AOD } - - private fun changeToShadeScene() { - sceneInteractor.changeScene( - SceneFamilies.NotifShade, - "ShadeLockscreenInteractorImpl.expandToNotifications", - ) - } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt index 77ae679bf018..caa45137ed98 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt @@ -51,6 +51,10 @@ interface ShadeModeInteractor { */ val isShadeLayoutWide: StateFlow<Boolean> + /** Convenience shortcut for querying whether the current [shadeMode] is [ShadeMode.Dual]. */ + val isDualShade: Boolean + get() = shadeMode.value is ShadeMode.Dual + /** * The fraction between [0..1] (i.e., percentage) of screen width to consider the threshold * between "top-left" and "top-right" for the purposes of dual-shade invocation. diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt index b02cccc2bb8d..4959224ead2d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt @@ -146,9 +146,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { whenever(packageManager.resolveServiceAsUser(any(), anyInt(), anyInt())) .thenReturn(mock(ResolveInfo::class.java)) - mSetFlagsRule.disableFlags( - com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR, - ) + mSetFlagsRule.disableFlags(com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR) subject = createOverviewProxyService(context) } @@ -283,6 +281,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { statusBarWinController, sysUiState, mock(), + mock(), userTracker, userManager, wakefulnessLifecycle, @@ -294,7 +293,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { dumpManager, unfoldTransitionProgressForwarder, broadcastDispatcher, - keyboardTouchpadEduStatsInteractor + keyboardTouchpadEduStatsInteractor, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt index b65a90200837..a1750cdd0c84 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt @@ -16,6 +16,8 @@ package com.android.systemui.shade.domain.interactor +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState @@ -27,16 +29,18 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.kosmos.testScope import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shadeTestUtil +import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.testKosmos -import com.google.common.truth.Truth import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -53,7 +57,12 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { private val sceneInteractor = kosmos.sceneInteractor private val shadeTestUtil = kosmos.shadeTestUtil - private val underTest = kosmos.shadeInteractorSceneContainerImpl + private lateinit var underTest: ShadeInteractorSceneContainerImpl + + @Before + fun setUp() { + underTest = kosmos.shadeInteractorSceneContainerImpl + } @Test fun qsExpansionWhenInSplitShadeAndQsExpanded() = @@ -80,7 +89,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { keyguardRepository.setStatusBarState(StatusBarState.SHADE) // THEN legacy shade expansion is passed through - Truth.assertThat(actual).isEqualTo(.3f) + assertThat(actual).isEqualTo(.3f) } @Test @@ -109,7 +118,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN shade expansion is zero - Truth.assertThat(actual).isEqualTo(.7f) + assertThat(actual).isEqualTo(.7f) } @Test @@ -134,7 +143,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is not fullscreen - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -152,7 +161,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is not fullscreen - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -171,7 +180,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is not fullscreen - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -189,7 +198,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN QS is fullscreen - Truth.assertThat(actual).isTrue() + assertThat(actual).isTrue() } @Test @@ -206,7 +215,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 1 - Truth.assertThat(expansionAmount).isEqualTo(1f) + assertThat(expansionAmount).isEqualTo(1f) } @Test @@ -224,7 +233,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) } @Test @@ -251,19 +260,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) // WHEN transition state is partially to the scene progress.value = .4f // THEN expansion matches the progress - Truth.assertThat(expansionAmount).isEqualTo(.4f) + assertThat(expansionAmount).isEqualTo(.4f) // WHEN transition completes progress.value = 1f // THEN expansion is 1 - Truth.assertThat(expansionAmount).isEqualTo(1f) + assertThat(expansionAmount).isEqualTo(1f) } @Test @@ -290,19 +299,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 1 - Truth.assertThat(expansionAmount).isEqualTo(1f) + assertThat(expansionAmount).isEqualTo(1f) // WHEN transition state is partially to the scene progress.value = .4f // THEN expansion reflects the progress - Truth.assertThat(expansionAmount).isEqualTo(.6f) + assertThat(expansionAmount).isEqualTo(.6f) // WHEN transition completes progress.value = 1f // THEN expansion is 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) } fun isQsBypassingShade_goneToQs() = @@ -326,7 +335,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN qs is bypassing shade - Truth.assertThat(actual).isTrue() + assertThat(actual).isTrue() } fun isQsBypassingShade_shadeToQs() = @@ -350,7 +359,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { runCurrent() // THEN qs is not bypassing shade - Truth.assertThat(actual).isFalse() + assertThat(actual).isFalse() } @Test @@ -376,19 +385,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN expansion is 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) // WHEN transition state is partially complete progress.value = .4f // THEN expansion is still 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) // WHEN transition completes progress.value = 1f // THEN expansion is still 0 - Truth.assertThat(expansionAmount).isEqualTo(0f) + assertThat(expansionAmount).isEqualTo(0f) } @Test @@ -405,7 +414,7 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() } @Test @@ -432,19 +441,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() // WHEN transition state is partially to the scene progress.value = .4f // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() // WHEN transition completes progress.value = 1f // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() } @Test @@ -471,19 +480,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN interacting is true - Truth.assertThat(interacting).isTrue() + assertThat(interacting).isTrue() // WHEN transition state is partially to the scene progress.value = .4f // THEN interacting is true - Truth.assertThat(interacting).isTrue() + assertThat(interacting).isTrue() // WHEN transition completes progress.value = 1f // THEN interacting is true - Truth.assertThat(interacting).isTrue() + assertThat(interacting).isTrue() } @Test @@ -510,19 +519,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() // WHEN transition state is partially to the scene progress.value = .4f // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() // WHEN transition completes progress.value = 1f // THEN interacting is false - Truth.assertThat(interacting).isFalse() + assertThat(interacting).isFalse() } @Test @@ -549,19 +558,19 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { sceneInteractor.setTransitionState(transitionState) // THEN interacting is true - Truth.assertThat(interacting).isTrue() + assertThat(interacting).isTrue() // WHEN transition state is partially to the scene progress.value = .4f // THEN interacting is true - Truth.assertThat(interacting).isTrue() + assertThat(interacting).isTrue() // WHEN transition completes progress.value = 1f // THEN interacting is true - Truth.assertThat(interacting).isTrue() + assertThat(interacting).isTrue() } @Test @@ -572,7 +581,6 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { val interacting by collectLastValue(interactingFlow) // WHEN transition state is starting to between different scenes - val progress = MutableStateFlow(0f) val transitionState = MutableStateFlow<ObservableTransitionState>( ObservableTransitionState.Transition( @@ -589,4 +597,94 @@ class ShadeInteractorSceneContainerImplTest : SysuiTestCase() { // THEN interacting is false assertThat(interacting).isFalse() } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun expandNotificationShade_dualShadeEnabled_opensOverlay() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).isEmpty() + + underTest.expandNotificationShade("reason") + + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade) + } + + @Test + @DisableFlags(DualShade.FLAG_NAME) + fun expandNotificationShade_dualShadeDisabled_switchesToShadeScene() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).isEmpty() + + underTest.expandNotificationShade("reason") + + assertThat(currentScene).isEqualTo(Scenes.Shade) + assertThat(currentOverlays).isEmpty() + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun expandNotificationShade_dualShadeEnabledAndQuickSettingsOpen_replacesOverlay() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + underTest.expandQuickSettingsShade("reason") + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade) + + underTest.expandNotificationShade("reason") + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade) + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun expandQuickSettingsShade_dualShadeEnabled_opensOverlay() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).isEmpty() + + underTest.expandQuickSettingsShade("reason") + + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade) + } + + @Test + @DisableFlags(DualShade.FLAG_NAME) + fun expandQuickSettingsShade_dualShadeDisabled_switchesToQuickSettingsScene() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).isEmpty() + + underTest.expandQuickSettingsShade("reason") + + assertThat(currentScene).isEqualTo(Scenes.QuickSettings) + assertThat(currentOverlays).isEmpty() + } + + @Test + @EnableFlags(DualShade.FLAG_NAME) + fun expandQuickSettingsShade_dualShadeEnabledAndNotificationsOpen_replacesOverlay() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + underTest.expandNotificationShade("reason") + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade) + + underTest.expandQuickSettingsShade("reason") + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade) + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt index 04d930c72792..92075ea75c4a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt @@ -44,7 +44,7 @@ val Kosmos.shadeInteractorSceneContainerImpl by ShadeInteractorSceneContainerImpl( scope = applicationCoroutineScope, sceneInteractor = sceneInteractor, - shadeRepository = shadeRepository, + shadeModeInteractor = shadeModeInteractor, ) } val Kosmos.shadeInteractorLegacyImpl by |