diff options
12 files changed, 102 insertions, 55 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt index b1ff708d020b..9d6e9b4f3ed5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt @@ -46,8 +46,7 @@ import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.media.dream.MediaDreamComplication import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R -import com.android.systemui.shade.ShadeStateEvents -import com.android.systemui.shade.ShadeStateEvents.ShadeStateEventsListener +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.CrossFadeHelper import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController @@ -103,7 +102,7 @@ constructor( private val communalInteractor: CommunalInteractor, configurationController: ConfigurationController, wakefulnessLifecycle: WakefulnessLifecycle, - panelEventsEvents: ShadeStateEvents, + shadeInteractor: ShadeInteractor, private val secureSettings: SecureSettings, @Main private val handler: Handler, @Application private val coroutineScope: CoroutineScope, @@ -545,14 +544,12 @@ constructor( mediaHosts.forEach { it?.updateViewVisibility() } } - panelEventsEvents.addShadeStateEventsListener( - object : ShadeStateEventsListener { - override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) { - skipQqsOnExpansion = isExpandImmediateEnabled - updateDesiredLocation() - } + coroutineScope.launch { + shadeInteractor.isQsBypassingShade.collect { isExpandImmediateEnabled -> + skipQqsOnExpansion = isExpandImmediateEnabled + updateDesiredLocation() } - ) + } val settingsObserver: ContentObserver = object : ContentObserver(handler) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 4ca763f9c0dd..a33e298ed1b3 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -207,12 +207,6 @@ public class QuickSettingsController implements Dumpable { /** Indicates QS is at its max height */ private boolean mFullyExpanded; - /** - * Determines if QS should be already expanded when expanding shade. - * Used for split shade, two finger gesture as well as accessibility shortcut to QS. - * It needs to be set when movement starts as it resets at the end of expansion/collapse. - */ - private boolean mExpandImmediate; private boolean mExpandedWhenExpandingStarted; private boolean mAnimatingHiddenFromCollapsed; private boolean mVisible; @@ -512,7 +506,7 @@ public class QuickSettingsController implements Dumpable { /** */ @VisibleForTesting boolean isExpandImmediate() { - return mExpandImmediate; + return mShadeRepository.getLegacyExpandImmediate().getValue(); } float getInitialTouchY() { @@ -602,7 +596,7 @@ public class QuickSettingsController implements Dumpable { // close the whole shade with one motion. Also this will be always true when closing // split shade as there QS are always expanded so every collapsing motion is motion from // expanded QS to closed panel - return mExpandImmediate || (getExpanded() + return isExpandImmediate() || (getExpanded() && !isTracking() && !isExpansionAnimating() && !mExpansionFromOverscroll); } @@ -792,7 +786,7 @@ public class QuickSettingsController implements Dumpable { && mBarState == SHADE) { Log.wtf(TAG, "setting QS height to 0 in split shade while shade is open(ing). " - + "Value of mExpandImmediate = " + mExpandImmediate); + + "Value of isExpandImmediate() = " + isExpandImmediate()); } int maxHeight = getMaxExpansionHeight(); height = Math.min(Math.max( @@ -941,10 +935,9 @@ public class QuickSettingsController implements Dumpable { } void setExpandImmediate(boolean expandImmediate) { - if (expandImmediate != mExpandImmediate) { + if (expandImmediate != isExpandImmediate()) { mShadeLog.logQsExpandImmediateChanged(expandImmediate); - mExpandImmediate = expandImmediate; - mShadeExpansionStateManager.notifyExpandImmediateChange(expandImmediate); + mShadeRepository.setLegacyExpandImmediate(expandImmediate); } } @@ -996,7 +989,7 @@ public class QuickSettingsController implements Dumpable { public void updateExpansion() { if (mQs == null) return; final float squishiness; - if ((mExpandImmediate || getExpanded()) && !mSplitShadeEnabled) { + if ((isExpandImmediate() || getExpanded()) && !mSplitShadeEnabled) { squishiness = 1; } else if (mTransitioningToFullShadeProgress > 0.0f) { squishiness = mLockscreenShadeTransitionController.getQsSquishTransitionFraction(); @@ -2077,8 +2070,8 @@ public class QuickSettingsController implements Dumpable { ipw.println(getExpanded()); ipw.print("mFullyExpanded="); ipw.println(mFullyExpanded); - ipw.print("mExpandImmediate="); - ipw.println(mExpandImmediate); + ipw.print("isExpandImmediate()="); + ipw.println(isExpandImmediate()); ipw.print("mExpandedWhenExpandingStarted="); ipw.println(mExpandedWhenExpandingStarted); ipw.print("mAnimatingHiddenFromCollapsed="); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt index fca98f580702..e20534cc7840 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt @@ -169,12 +169,6 @@ class ShadeExpansionStateManager @Inject constructor() : ShadeStateEvents { } } - fun notifyExpandImmediateChange(expandImmediateEnabled: Boolean) { - for (cb in shadeStateEventsListeners) { - cb.onExpandImmediateChanged(expandImmediateEnabled) - } - } - private fun debugLog(msg: String) { if (!DEBUG) return Log.v(TAG, msg) diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt index 5804040a8676..c8511d76f5f0 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeStateEvents.kt @@ -35,16 +35,5 @@ interface ShadeStateEvents { * Invoked when the notification panel starts or stops launching an [android.app.Activity]. */ fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {} - - /** - * Invoked when the "expand immediate" attribute changes. - * - * An example of expanding immediately is when swiping down from the top with two fingers. - * Instead of going to QQS, we immediately expand to full QS. - * - * Another example is when full QS is showing, and we swipe up from the bottom. Instead of - * going to QQS, the panel fully collapses. - */ - fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {} } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt index 8bab6696e2d3..56017a405fdc 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt @@ -93,6 +93,22 @@ interface ShadeRepository { */ @Deprecated("Use ShadeInteractor instead") val legacyIsQsExpanded: StateFlow<Boolean> + /** + * QuickSettingsController.mExpandImmediate as a flow. Indicates that Quick Settings is being + * expanded without first expanding the Shade or Quick Settings is being collapsed without first + * collapsing to shade, i.e. expanding with 2-finger swipe or collapsing by flinging from the + * bottom of the screen. Replaced by ShadeInteractor.isQsBypassingShade. + */ + @Deprecated("Use ShadeInteractor.isQsBypassingShade instead") + val legacyExpandImmediate: StateFlow<Boolean> + + /** + * Sets whether Quick Settings is being expanded without first expanding the Shade or Quick + * Settings is being collapsed without first collapsing to shade. + */ + @Deprecated("Use ShadeInteractor instead") + fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) + /** Sets whether QS is expanded. */ @Deprecated("Use ShadeInteractor instead") fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) @@ -199,6 +215,13 @@ constructor(shadeExpansionStateManager: ShadeExpansionStateManager) : ShadeRepos @Deprecated("Use ShadeInteractor instead") override val legacyIsQsExpanded: StateFlow<Boolean> = _legacyIsQsExpanded.asStateFlow() + private val _legacyExpandImmediate = MutableStateFlow(false) + override val legacyExpandImmediate: StateFlow<Boolean> = _legacyExpandImmediate.asStateFlow() + + override fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) { + _legacyExpandImmediate.value = legacyExpandImmediate + } + @Deprecated("Use ShadeInteractor instead") override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) { _legacyIsQsExpanded.value = legacyIsQsExpanded 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 5f7b07760a5b..7d7b288039d4 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 @@ -74,6 +74,14 @@ interface BaseShadeInteractor { val isQsExpanded: StateFlow<Boolean> /** + * Emits true whenever Quick Settings is being expanded without first expanding the Shade or if + * if Quick Settings is being collapsed without first collapsing to shade, i.e. expanding with + * 2-finger swipe or collapsing by flinging from the bottom of the screen. This concept was + * previously called "expand immediate" in the legacy codebase. + */ + val isQsBypassingShade: Flow<Boolean> + + /** * Whether the user is expanding or collapsing the shade with user input. This will be true even * if the user's input gesture has ended but a transition they initiated is animating. */ 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 e36897c94964..3704d1b08708 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 @@ -31,6 +31,7 @@ class ShadeInteractorEmptyImpl @Inject constructor() : ShadeInteractor { override val shadeExpansion: Flow<Float> = inactiveFlowFloat override val qsExpansion: StateFlow<Float> = inactiveFlowFloat override val isQsExpanded: StateFlow<Boolean> = inactiveFlowBoolean + override val isQsBypassingShade: Flow<Boolean> = inactiveFlowBoolean override val anyExpansion: StateFlow<Float> = inactiveFlowFloat override val isAnyFullyExpanded: Flow<Boolean> = inactiveFlowBoolean override val isAnyExpanded: StateFlow<Boolean> = inactiveFlowBoolean 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 5b3834b343bb..18a90b90b095 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 @@ -75,6 +75,8 @@ constructor( override val isQsExpanded: StateFlow<Boolean> = repository.legacyIsQsExpanded + override val isQsBypassingShade: Flow<Boolean> = repository.legacyExpandImmediate + override val anyExpansion: StateFlow<Float> = createAnyExpansionFlow(scope, shadeExpansion, qsExpansion) 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 58ebbc6ac8bf..0a4636ef73ae 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 @@ -69,6 +69,20 @@ constructor( .distinctUntilChanged() .stateIn(scope, SharingStarted.Eagerly, false) + override val isQsBypassingShade: Flow<Boolean> = + sceneInteractor.transitionState + .flatMapLatest { state -> + when (state) { + is ObservableTransitionState.Idle -> flowOf(false) + is ObservableTransitionState.Transition -> + flowOf( + state.toScene == SceneKey.QuickSettings && + state.fromScene != SceneKey.Shade + ) + } + } + .distinctUntilChanged() + override val anyExpansion: StateFlow<Float> = createAnyExpansionFlow(scope, shadeExpansion, qsExpansion) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt index a2eb5ef9e463..db7c9876f21b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt @@ -35,7 +35,7 @@ import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.media.dream.MediaDreamComplication import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.res.R -import com.android.systemui.shade.ShadeExpansionStateManager +import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.KeyguardBypassController @@ -50,6 +50,7 @@ import com.android.systemui.util.settings.FakeSettings import com.android.systemui.utils.os.FakeHandler import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -74,7 +75,7 @@ import org.mockito.junit.MockitoJUnit @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper(setAsMainLooper = true) class MediaHierarchyManagerTest : SysuiTestCase() { @Mock private lateinit var lockHost: MediaHost @@ -91,6 +92,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Mock private lateinit var mediaDataManager: MediaDataManager @Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView @Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController + @Mock private lateinit var shadeInteractor: ShadeInteractor @Mock lateinit var logger: MediaViewLogger @Captor private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)> @@ -101,12 +103,12 @@ class MediaHierarchyManagerTest : SysuiTestCase() { ArgumentCaptor<(DreamOverlayStateController.Callback)> @JvmField @Rule val mockito = MockitoJUnit.rule() private lateinit var mediaHierarchyManager: MediaHierarchyManager + private lateinit var isQsBypassingShade: MutableStateFlow<Boolean> private lateinit var mediaFrame: ViewGroup private val configurationController = FakeConfigurationController() private val communalRepository = FakeCommunalRepository(isCommunalEnabled = true) private val communalInteractor = CommunalInteractorFactory.create(communalRepository = communalRepository).communalInteractor - private val notifPanelEvents = ShadeExpansionStateManager() private val settings = FakeSettings() private lateinit var testableLooper: TestableLooper private lateinit var fakeHandler: FakeHandler @@ -122,6 +124,8 @@ class MediaHierarchyManagerTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) fakeHandler = FakeHandler(testableLooper.looper) whenever(mediaCarouselController.mediaFrame).thenReturn(mediaFrame) + isQsBypassingShade = MutableStateFlow(false) + whenever(shadeInteractor.isQsBypassingShade).thenReturn(isQsBypassingShade) mediaHierarchyManager = MediaHierarchyManager( context, @@ -135,7 +139,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { communalInteractor, configurationController, wakefulnessLifecycle, - notifPanelEvents, + shadeInteractor, settings, fakeHandler, testScope.backgroundScope, @@ -430,17 +434,21 @@ class MediaHierarchyManagerTest : SysuiTestCase() { assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isTrue() } + @OptIn(ExperimentalCoroutinesApi::class) @Test - fun isCurrentlyInGuidedTransformation_hostsVisible_expandImmediateEnabled_returnsFalse() { - notifPanelEvents.notifyExpandImmediateChange(true) - goToLockscreen() - enterGuidedTransformation() - whenever(lockHost.visible).thenReturn(true) - whenever(qsHost.visible).thenReturn(true) - whenever(qqsHost.visible).thenReturn(true) + fun isCurrentlyInGuidedTransformation_hostsVisible_expandImmediateEnabled_returnsFalse() = + testScope.runTest { + runCurrent() + isQsBypassingShade.value = true + runCurrent() + goToLockscreen() + enterGuidedTransformation() + whenever(lockHost.visible).thenReturn(true) + whenever(qsHost.visible).thenReturn(true) + whenever(qqsHost.visible).thenReturn(true) - assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse() - } + assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse() + } @Test fun isCurrentlyInGuidedTransformation_hostNotVisible_returnsFalse_with_active() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt index 20b19fd16f4f..4f9bb0becc87 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt @@ -207,4 +207,13 @@ class ShadeRepositoryImplTest : SysuiTestCase() { underTest.setLegacyIsQsExpanded(true) assertThat(underTest.legacyIsQsExpanded.value).isEqualTo(true) } + + @Test + fun updateLegacyExpandImmediate() = + testScope.runTest { + assertThat(underTest.legacyExpandImmediate.value).isEqualTo(false) + + underTest.setLegacyExpandImmediate(true) + assertThat(underTest.legacyExpandImmediate.value).isEqualTo(true) + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt index 02318abe8488..6c35fe70b00c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt @@ -66,6 +66,15 @@ class FakeShadeRepository @Inject constructor() : ShadeRepository { _legacyIsQsExpanded.value = legacyIsQsExpanded } + private val _legacyExpandImmediate = MutableStateFlow(false) + @Deprecated("Use ShadeInteractor instead") + override val legacyExpandImmediate = _legacyExpandImmediate + + @Deprecated("Use ShadeInteractor instead") + override fun setLegacyExpandImmediate(legacyExpandImmediate: Boolean) { + _legacyExpandImmediate.value = legacyExpandImmediate + } + @Deprecated("Use ShadeInteractor instead") override fun setLegacyExpandedOrAwaitingInputTransfer( legacyExpandedOrAwaitingInputTransfer: Boolean |