Merge "Fix media staying too long during shade "immediate" expansion/collapsing" into tm-qpr-dev

This commit is contained in:
Christian Göllner
2022-08-19 12:24:46 +00:00
committed by Android (Google) Code Review
5 changed files with 151 additions and 40 deletions

View File

@@ -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
}

View File

@@ -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) {}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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()

View File

@@ -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) }
}
}