diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt index 075bc700cfa00..edbf18789e285 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt @@ -186,6 +186,12 @@ class MediaHierarchyManager @Inject constructor( @MediaLocation private var currentAttachmentLocation = -1 + /** + * Is there any active media in the carousel? + */ + private var hasActiveMedia: Boolean = false + get() = mediaHosts.get(LOCATION_QQS)?.visible == true + /** * Are we currently waiting on an animation to start? */ @@ -476,8 +482,12 @@ class MediaHierarchyManager @Inject constructor( val viewHost = createUniqueObjectHost() mediaObject.hostView = viewHost mediaObject.addVisibilityChangeListener { + // If QQS changes visibility, we need to force an update to ensure the transition + // goes into the correct state + val stateUpdate = mediaObject.location == LOCATION_QQS + // Never animate because of a visibility change, only state changes should do that - updateDesiredLocation(forceNoAnimation = true) + updateDesiredLocation(forceNoAnimation = true, forceStateUpdate = stateUpdate) } mediaHosts[mediaObject.location] = mediaObject if (mediaObject.location == desiredLocation) { @@ -521,10 +531,15 @@ class MediaHierarchyManager @Inject constructor( * going from the old desired location to the new one. * * @param forceNoAnimation optional parameter telling the system not to animate + * @param forceStateUpdate optional parameter telling the system to update transition state + * even if location did not change */ - private fun updateDesiredLocation(forceNoAnimation: Boolean = false) { + private fun updateDesiredLocation( + forceNoAnimation: Boolean = false, + forceStateUpdate: Boolean = false + ) { val desiredLocation = calculateLocation() - if (desiredLocation != this.desiredLocation) { + if (desiredLocation != this.desiredLocation || forceStateUpdate) { if (this.desiredLocation >= 0) { previousLocation = this.desiredLocation } @@ -784,7 +799,7 @@ class MediaHierarchyManager @Inject constructor( private fun getQSTransformationProgress(): Float { val currentHost = getHost(desiredLocation) val previousHost = getHost(previousLocation) - if (currentHost?.location == LOCATION_QS) { + if (hasActiveMedia && currentHost?.location == LOCATION_QS) { if (previousHost?.location == LOCATION_QQS) { if (previousHost.visible || statusbarState != StatusBarState.KEYGUARD) { return qsExpansion @@ -917,6 +932,7 @@ class MediaHierarchyManager @Inject constructor( val location = when { qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS + !hasActiveMedia -> LOCATION_QS onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN else -> LOCATION_QQS diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index e1a66b2c07ee5..7b8a6a0a8d0e8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -539,8 +539,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost, boolean expanded) { View hostView = mediaHost.getHostView(); - // on keyguard we cross-fade to expanded, so no need to pin it. - if (mLastQSExpansion > 0 && !isKeyguardState()) { + // On keyguard we cross-fade to expanded, so no need to pin it. + // If the collapsed qs isn't visible, we also just keep it at the laid out position. + if (mLastQSExpansion > 0 && !isKeyguardState() && mQqsMediaHost.getVisible()) { float targetPosition = absoluteBottomPosition - getTotalBottomMargin(hostView) - hostView.getHeight(); float currentPosition = mediaHost.getCurrentBounds().top