Merge "Fix media staying too long during shade "immediate" expansion/collapsing" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c7359149cd
@@ -36,6 +36,7 @@ import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dreams.DreamOverlayStateController
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.NotifPanelEvents
|
||||
import com.android.systemui.statusbar.CrossFadeHelper
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
@@ -85,12 +86,21 @@ class MediaHierarchyManager @Inject constructor(
|
||||
private val bypassController: KeyguardBypassController,
|
||||
private val mediaCarouselController: MediaCarouselController,
|
||||
private val notifLockscreenUserManager: NotificationLockscreenUserManager,
|
||||
private val keyguardViewController: KeyguardViewController,
|
||||
private val dreamOverlayStateController: DreamOverlayStateController,
|
||||
configurationController: ConfigurationController,
|
||||
wakefulnessLifecycle: WakefulnessLifecycle,
|
||||
private val keyguardViewController: KeyguardViewController,
|
||||
private val dreamOverlayStateController: DreamOverlayStateController
|
||||
panelEventsEvents: NotifPanelEvents,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Whether we "skip" QQS during panel expansion.
|
||||
*
|
||||
* This means that when expanding the panel we go directly to QS. Also when we are on QS and
|
||||
* start closing the panel, it fully collapses instead of going to QQS.
|
||||
*/
|
||||
private var skipQqsOnExpansion: Boolean = false
|
||||
|
||||
/**
|
||||
* The root overlay of the hierarchy. This is where the media notification is attached to
|
||||
* whenever the view is transitioning from one host to another. It also make sure that the
|
||||
@@ -504,6 +514,13 @@ class MediaHierarchyManager @Inject constructor(
|
||||
mediaCarouselController.updateUserVisibility = {
|
||||
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
|
||||
}
|
||||
|
||||
panelEventsEvents.registerListener(object : NotifPanelEvents.Listener {
|
||||
override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
|
||||
skipQqsOnExpansion = isExpandImmediateEnabled
|
||||
updateDesiredLocation()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateConfiguration() {
|
||||
@@ -701,6 +718,9 @@ class MediaHierarchyManager @Inject constructor(
|
||||
if (isCurrentlyInGuidedTransformation()) {
|
||||
return false
|
||||
}
|
||||
if (skipQqsOnExpansion) {
|
||||
return false
|
||||
}
|
||||
// This is an invalid transition, and can happen when using the camera gesture from the
|
||||
// lock screen. Disallow.
|
||||
if (previousLocation == LOCATION_LOCKSCREEN &&
|
||||
@@ -852,6 +872,9 @@ class MediaHierarchyManager @Inject constructor(
|
||||
* otherwise
|
||||
*/
|
||||
private fun getTransformationProgress(): Float {
|
||||
if (skipQqsOnExpansion) {
|
||||
return -1.0f
|
||||
}
|
||||
val progress = getQSTransformationProgress()
|
||||
if (statusbarState != StatusBarState.KEYGUARD && progress >= 0) {
|
||||
return progress
|
||||
@@ -1042,6 +1065,10 @@ class MediaHierarchyManager @Inject constructor(
|
||||
// reattach it without an animation
|
||||
return LOCATION_LOCKSCREEN
|
||||
}
|
||||
if (skipQqsOnExpansion) {
|
||||
// When doing an immediate expand or collapse, we want to keep it in QS.
|
||||
return LOCATION_QS
|
||||
}
|
||||
return location
|
||||
}
|
||||
|
||||
|
||||
@@ -29,11 +29,25 @@ interface NotifPanelEvents {
|
||||
interface Listener {
|
||||
|
||||
/** Invoked when the notification panel starts or stops collapsing. */
|
||||
fun onPanelCollapsingChanged(isCollapsing: Boolean)
|
||||
@JvmDefault
|
||||
fun onPanelCollapsingChanged(isCollapsing: Boolean) {}
|
||||
|
||||
/**
|
||||
* Invoked when the notification panel starts or stops launching an [android.app.Activity].
|
||||
*/
|
||||
fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
|
||||
@JvmDefault
|
||||
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.
|
||||
*/
|
||||
@JvmDefault
|
||||
fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1745,12 +1745,17 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
}
|
||||
|
||||
if (mQsExpanded) {
|
||||
mQsExpandImmediate = true;
|
||||
setQsExpandImmediate(true);
|
||||
setShowShelfOnly(true);
|
||||
}
|
||||
super.collapse(delayed, speedUpFactor);
|
||||
}
|
||||
|
||||
private void setQsExpandImmediate(boolean expandImmediate) {
|
||||
mQsExpandImmediate = expandImmediate;
|
||||
mPanelEventsEmitter.notifyExpandImmediateChange(expandImmediate);
|
||||
}
|
||||
|
||||
private void setShowShelfOnly(boolean shelfOnly) {
|
||||
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(
|
||||
shelfOnly && !mSplitShadeEnabled);
|
||||
@@ -1803,7 +1808,7 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
|
||||
public void expandWithQs() {
|
||||
if (isQsExpansionEnabled()) {
|
||||
mQsExpandImmediate = true;
|
||||
setQsExpandImmediate(true);
|
||||
setShowShelfOnly(true);
|
||||
}
|
||||
if (mSplitShadeEnabled && isOnKeyguard()) {
|
||||
@@ -2132,7 +2137,7 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
if (mTwoFingerQsExpandPossible && isOpenQsEvent(event) && event.getY(event.getActionIndex())
|
||||
< mStatusBarMinHeight) {
|
||||
mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
|
||||
mQsExpandImmediate = true;
|
||||
setQsExpandImmediate(true);
|
||||
setShowShelfOnly(true);
|
||||
requestPanelHeightUpdate();
|
||||
|
||||
@@ -3334,7 +3339,7 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
} else {
|
||||
setListening(true);
|
||||
}
|
||||
mQsExpandImmediate = false;
|
||||
setQsExpandImmediate(false);
|
||||
setShowShelfOnly(false);
|
||||
mTwoFingerQsExpandPossible = false;
|
||||
updateTrackingHeadsUp(null);
|
||||
@@ -3392,7 +3397,7 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
super.onTrackingStarted();
|
||||
mScrimController.onTrackingStarted();
|
||||
if (mQsFullyExpanded) {
|
||||
mQsExpandImmediate = true;
|
||||
setQsExpandImmediate(true);
|
||||
setShowShelfOnly(true);
|
||||
}
|
||||
mNotificationStackScrollLayoutController.onPanelTrackingStarted();
|
||||
@@ -4959,7 +4964,7 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
// to locked will trigger this event and we're not actually in the process of opening
|
||||
// the shade, lockscreen is just always expanded
|
||||
if (mSplitShadeEnabled && !isOnKeyguard()) {
|
||||
mQsExpandImmediate = true;
|
||||
setQsExpandImmediate(true);
|
||||
}
|
||||
mCentralSurfaces.makeExpandedVisible(false);
|
||||
}
|
||||
@@ -5026,5 +5031,11 @@ public final class NotificationPanelViewController extends PanelViewController {
|
||||
cb.onPanelCollapsingChanged(isCollapsing);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyExpandImmediateChange(boolean expandImmediateEnabled) {
|
||||
for (NotifPanelEvents.Listener cb : mListeners) {
|
||||
cb.onExpandImmediateChanged(expandImmediateEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.android.systemui.media
|
||||
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import android.graphics.Rect
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
@@ -30,6 +29,7 @@ import com.android.systemui.controls.controller.ControlsControllerImplTest.Compa
|
||||
import com.android.systemui.dreams.DreamOverlayStateController
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.testing.FakeNotifPanelEvents
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||
@@ -50,10 +50,11 @@ import org.mockito.ArgumentMatchers.anyBoolean
|
||||
import org.mockito.ArgumentMatchers.anyLong
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
|
||||
@SmallTest
|
||||
@@ -61,32 +62,19 @@ import org.mockito.junit.MockitoJUnit
|
||||
@TestableLooper.RunWithLooper
|
||||
class MediaHierarchyManagerTest : SysuiTestCase() {
|
||||
|
||||
@Mock
|
||||
private lateinit var lockHost: MediaHost
|
||||
@Mock
|
||||
private lateinit var qsHost: MediaHost
|
||||
@Mock
|
||||
private lateinit var qqsHost: MediaHost
|
||||
@Mock
|
||||
private lateinit var bypassController: KeyguardBypassController
|
||||
@Mock
|
||||
private lateinit var keyguardStateController: KeyguardStateController
|
||||
@Mock
|
||||
private lateinit var statusBarStateController: SysuiStatusBarStateController
|
||||
@Mock
|
||||
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
|
||||
@Mock
|
||||
private lateinit var mediaCarouselController: MediaCarouselController
|
||||
@Mock
|
||||
private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
|
||||
@Mock
|
||||
private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
|
||||
@Mock
|
||||
private lateinit var keyguardViewController: KeyguardViewController
|
||||
@Mock
|
||||
private lateinit var uniqueObjectHostView: UniqueObjectHostView
|
||||
@Mock
|
||||
private lateinit var dreamOverlayStateController: DreamOverlayStateController
|
||||
@Mock private lateinit var lockHost: MediaHost
|
||||
@Mock private lateinit var qsHost: MediaHost
|
||||
@Mock private lateinit var qqsHost: MediaHost
|
||||
@Mock private lateinit var bypassController: KeyguardBypassController
|
||||
@Mock private lateinit var keyguardStateController: KeyguardStateController
|
||||
@Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
|
||||
@Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
|
||||
@Mock private lateinit var mediaCarouselController: MediaCarouselController
|
||||
@Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
|
||||
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
|
||||
@Mock private lateinit var keyguardViewController: KeyguardViewController
|
||||
@Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView
|
||||
@Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController
|
||||
@Captor
|
||||
private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
|
||||
@Captor
|
||||
@@ -97,6 +85,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
|
||||
private lateinit var mediaHiearchyManager: MediaHierarchyManager
|
||||
private lateinit var mediaFrame: ViewGroup
|
||||
private val configurationController = FakeConfigurationController()
|
||||
private val notifPanelEvents = FakeNotifPanelEvents()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
@@ -111,10 +100,12 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
|
||||
bypassController,
|
||||
mediaCarouselController,
|
||||
notificationLockscreenUserManager,
|
||||
keyguardViewController,
|
||||
dreamOverlayStateController,
|
||||
configurationController,
|
||||
wakefulnessLifecycle,
|
||||
keyguardViewController,
|
||||
dreamOverlayStateController)
|
||||
notifPanelEvents,
|
||||
)
|
||||
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
|
||||
verify(statusBarStateController).addCallback(statusBarCallback.capture())
|
||||
setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
|
||||
@@ -211,6 +202,25 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
|
||||
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun calculateTransformationType_notOnLockscreen_returnsTransition() {
|
||||
expandQS()
|
||||
|
||||
val transformType = mediaHiearchyManager.calculateTransformationType()
|
||||
|
||||
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun calculateTransformationType_onLockscreen_returnsTransition() {
|
||||
goToLockscreen()
|
||||
expandQS()
|
||||
|
||||
val transformType = mediaHiearchyManager.calculateTransformationType()
|
||||
|
||||
assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun calculateTransformationType_onLockShade_inSplitShade_goingToFullShade_returnsTransition() {
|
||||
enableSplitShade()
|
||||
@@ -294,6 +304,18 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
|
||||
assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isCurrentlyInGuidedTransformation_hostsVisible_expandImmediateEnabled_returnsFalse() {
|
||||
notifPanelEvents.changeExpandImmediate(expandImmediate = true)
|
||||
goToLockscreen()
|
||||
enterGuidedTransformation()
|
||||
whenever(lockHost.visible).thenReturn(true)
|
||||
whenever(qsHost.visible).thenReturn(true)
|
||||
whenever(qqsHost.visible).thenReturn(true)
|
||||
|
||||
assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isCurrentlyInGuidedTransformation_hostNotVisible_returnsTrue() {
|
||||
goToLockscreen()
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.testing
|
||||
|
||||
import com.android.systemui.shade.NotifPanelEvents
|
||||
|
||||
/** Fake implementation of [NotifPanelEvents] for testing. */
|
||||
class FakeNotifPanelEvents : NotifPanelEvents {
|
||||
|
||||
private val listeners = mutableListOf<NotifPanelEvents.Listener>()
|
||||
|
||||
override fun registerListener(listener: NotifPanelEvents.Listener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
override fun unregisterListener(listener: NotifPanelEvents.Listener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
fun changeExpandImmediate(expandImmediate: Boolean) {
|
||||
listeners.forEach { it.onExpandImmediateChanged(expandImmediate) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user