diff options
9 files changed, 182 insertions, 45 deletions
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index c37c804caaa8..8a4516aaa49f 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -42,4 +42,8 @@ the shade (in alpha) --> <dimen name="lockscreen_shade_scrim_transition_distance">200dp</dimen> + <!-- Distance that the full shade transition takes in order for media to fully transition to + the shade --> + <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt index d00630ead8e1..c6f716ca7ac4 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt @@ -799,6 +799,9 @@ class MediaHierarchyManager @Inject constructor( @TransformationType fun calculateTransformationType(): Int { if (isTransitioningToFullShade) { + if (inSplitShade) { + return TRANSFORMATION_TYPE_TRANSITION + } return TRANSFORMATION_TYPE_FADE } if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS || @@ -965,6 +968,7 @@ class MediaHierarchyManager @Inject constructor( (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS qsExpansion > 0.4f && onLockscreen -> LOCATION_QS !hasActiveMedia -> LOCATION_QS + onLockscreen && isSplitShadeExpanding() -> LOCATION_QS onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN else -> LOCATION_QQS @@ -990,6 +994,10 @@ class MediaHierarchyManager @Inject constructor( return location } + private fun isSplitShadeExpanding(): Boolean { + return inSplitShade && isTransitioningToFullShade + } + /** * Are we currently transforming to the full shade and already in QQS */ @@ -997,6 +1005,10 @@ class MediaHierarchyManager @Inject constructor( if (!isTransitioningToFullShade) { return false } + if (inSplitShade) { + // Split shade doesn't use QQS. + return false + } return fullShadeTransitionProgress > 0.5f } @@ -1004,6 +1016,10 @@ class MediaHierarchyManager @Inject constructor( * Is the current transformationType fading */ private fun isCurrentlyFading(): Boolean { + if (isSplitShadeExpanding()) { + // Split shade always uses transition instead of fade. + return false + } if (isTransitioningToFullShade) { return true } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 3c7933f0d218..3ef72202a591 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -513,7 +513,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mContainer.setExpansion(expansion); final float translationScaleY = (mInSplitShade ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); - boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard; + boolean onKeyguard = isKeyguardState(); + boolean onKeyguardAndExpanded = onKeyguard && !mShowCollapsedOnKeyguard; if (!mHeaderAnimating && !headerWillBeAnimating()) { getView().setTranslationY( onKeyguardAndExpanded @@ -547,6 +548,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mHeader.updateResources(); } } + mQSPanelController.setIsOnKeyguard(onKeyguard); mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion); mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion); mQSPanelController.setRevealExpansion(expansion); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 5126fcb4c34d..b04d75273831 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -110,6 +110,8 @@ public class QSPanel extends LinearLayout implements Tunable { private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>(); private final Rect mClippingRect = new Rect(); private boolean mUseNewFooter = false; + private ViewGroup mMediaHostView; + private boolean mShouldMoveMediaOnExpansion = true; public QSPanel(Context context, AttributeSet attrs) { super(context, attrs); @@ -289,9 +291,15 @@ public class QSPanel extends LinearLayout implements Tunable { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (move) { + int topOffset; + if (child == mMediaHostView && !mShouldMoveMediaOnExpansion) { + topOffset = 0; + } else { + topOffset = tileHeightOffset; + } int top = Objects.requireNonNull(mChildrenLayoutTop.get(child)); - child.setLeftTopRightBottom(child.getLeft(), top + tileHeightOffset, - child.getRight(), top + tileHeightOffset + child.getHeight()); + child.setLeftTopRightBottom(child.getLeft(), top + topOffset, + child.getRight(), top + topOffset + child.getHeight()); } if (child == mTileLayout) { move = true; @@ -463,6 +471,7 @@ public class QSPanel extends LinearLayout implements Tunable { if (!mUsingMediaPlayer) { return; } + mMediaHostView = hostView; ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this; ViewGroup currentParent = (ViewGroup) hostView.getParent(); if (currentParent != newParent) { @@ -656,6 +665,19 @@ public class QSPanel extends LinearLayout implements Tunable { updatePadding(); } + /** + * Sets whether the media container should move during the expansion of the QS Panel. + * + * As the QS Panel expands and the QS unsquish, the views below the QS tiles move to adapt to + * the new height of the QS tiles. + * + * In some cases this might not be wanted for media. One example is when there is a transition + * animation of the media container happening on split shade lock screen. + */ + public void setShouldMoveMediaOnExpansion(boolean shouldMoveMediaOnExpansion) { + mShouldMoveMediaOnExpansion = shouldMoveMediaOnExpansion; + } + private class H extends Handler { private static final int ANNOUNCE_FOR_ACCESSIBILITY = 1; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java index 3172aa9592dd..6572daa91269 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java @@ -419,6 +419,16 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr return mView.getBrightnessView(); } + /** Sets whether we are currently on lock screen. */ + public void setIsOnKeyguard(boolean isOnKeyguard) { + boolean isOnSplitShadeLockscreen = mShouldUseSplitNotificationShade && isOnKeyguard; + // When the split shade is expanding on lockscreen, the media container transitions from the + // lockscreen to QS. + // We have to prevent the media container position from moving during the transition to have + // a smooth translation animation without stuttering. + mView.setShouldMoveMediaOnExpansion(!isOnSplitShadeLockscreen); + } + /** */ public static final class TileRecord { public TileRecord(QSTile tile, com.android.systemui.plugins.qs.QSTileView tileView) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 8366bddaab9f..8a9d6ddb2e14 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -342,9 +342,7 @@ class LockscreenShadeTransitionController @Inject constructor( qS.setTransitionToFullShadeAmount(field, qSDragProgress) notificationPanelController.setTransitionToFullShadeAmount(field, false /* animate */, 0 /* delay */) - // TODO: appear media also in split shade - val mediaAmount = if (useSplitShade) 0f else field - mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount) + mediaHierarchyManager.setTransitionToFullShadeAmount(field) transitionToShadeAmountCommon(field) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt index e606be179cc6..b359ae5317b1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt @@ -33,10 +33,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.phone.KeyguardBypassController -import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.animation.UniqueObjectHostView -import junit.framework.Assert +import com.android.systemui.util.mockito.any +import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Rule @@ -44,16 +45,16 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers +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.any -import org.mockito.Mockito.anyBoolean -import org.mockito.Mockito.anyLong import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -83,8 +84,6 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Mock private lateinit var keyguardViewController: KeyguardViewController @Mock - private lateinit var configurationController: ConfigurationController - @Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView @Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController @@ -97,6 +96,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { val mockito = MockitoJUnit.rule() private lateinit var mediaHiearchyManager: MediaHierarchyManager private lateinit var mediaFrame: ViewGroup + private val configurationController = FakeConfigurationController() @Before fun setup() { @@ -176,12 +176,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() { @Test fun testGoingToFullShade() { - // Let's set it onto Lock screen - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( - true) - statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) - clearInvocations(mediaCarouselController) + goToLockscreen() // Let's transition all the way to full shade mediaHiearchyManager.setTransitionToFullShadeAmount(100000f) @@ -204,41 +199,48 @@ class MediaHierarchyManagerTest : SysuiTestCase() { // Let's make sure alpha is set mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f) - Assert.assertTrue("alpha should not be 1.0f when cross fading", mediaFrame.alpha != 1.0f) + assertThat(mediaFrame.alpha).isNotEqualTo(1.0f) } @Test fun testTransformationOnLockScreenIsFading() { - // Let's set it onto Lock screen - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( - true) - statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) - clearInvocations(mediaCarouselController) + goToLockscreen() + expandQS() + + val transformType = mediaHiearchyManager.calculateTransformationType() + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) + } + + @Test + fun calculateTransformationType_onLockShade_inSplitShade_goingToFullShade_returnsTransition() { + enableSplitShade() + goToLockscreen() + expandQS() + mediaHiearchyManager.setTransitionToFullShadeAmount(10000f) + + val transformType = mediaHiearchyManager.calculateTransformationType() + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION) + } + + @Test + fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() { + enableSplitShade() + goToLockscreen() + goToLockedShade() + expandQS() + mediaHiearchyManager.setTransitionToFullShadeAmount(0f) - // Let's transition from lockscreen to qs - mediaHiearchyManager.qsExpansion = 1.0f val transformType = mediaHiearchyManager.calculateTransformationType() - Assert.assertTrue("media isn't transforming to qs with a fade", - transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @Test fun testTransformationOnLockScreenToQQSisFading() { - // Let's set it onto Lock screen - `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) - `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( - true) - statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) - clearInvocations(mediaCarouselController) + goToLockscreen() + goToLockedShade() - // Let's transition from lockscreen to qs - `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) - statusBarCallback.value.onStatePreChange(StatusBarState.KEYGUARD, - StatusBarState.SHADE_LOCKED) val transformType = mediaHiearchyManager.calculateTransformationType() - Assert.assertTrue("media isn't transforming to qqswith a fade", - transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) + assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE) } @Test @@ -254,4 +256,32 @@ class MediaHierarchyManagerTest : SysuiTestCase() { verify(mediaCarouselController).closeGuts() } -}
\ No newline at end of file + + private fun enableSplitShade() { + context.getOrCreateTestableResources().addOverride( + R.bool.config_use_split_notification_shade, true + ) + configurationController.notifyConfigurationChanged() + } + + private fun goToLockscreen() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD) + whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn( + true + ) + statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD) + clearInvocations(mediaCarouselController) + } + + private fun goToLockedShade() { + whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED) + statusBarCallback.value.onStatePreChange( + StatusBarState.KEYGUARD, + StatusBarState.SHADE_LOCKED + ) + } + + private fun expandQS() { + mediaHiearchyManager.qsExpansion = 1.0f + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index 9076e1607be5..75ccd8f03a01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -23,7 +23,7 @@ import com.android.systemui.statusbar.phone.LSShadeTransitionLogger import com.android.systemui.statusbar.phone.NotificationPanelViewController import com.android.systemui.statusbar.phone.ScrimController import com.android.systemui.statusbar.phone.StatusBar -import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.FakeConfigurationController import org.junit.After import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -66,7 +66,6 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock lateinit var mediaHierarchyManager: MediaHierarchyManager @Mock lateinit var scrimController: ScrimController - @Mock lateinit var configurationController: ConfigurationController @Mock lateinit var falsingManager: FalsingManager @Mock lateinit var notificationPanelController: NotificationPanelViewController @Mock lateinit var nsslController: NotificationStackScrollLayoutController @@ -77,6 +76,8 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { @Mock lateinit var qS: QS @JvmField @Rule val mockito = MockitoJUnit.rule() + private val configurationController = FakeConfigurationController() + @Before fun setup() { val helper = NotificationTestHelper( @@ -244,4 +245,27 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat()) verify(depthController).transitionToFullShadeProgress = anyFloat() } + + @Test + fun setDragDownAmount_setsValueOnMediaHierarchyManager() { + transitionController.dragDownAmount = 10f + + verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f) + } + + @Test + fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() { + enableSplitShade() + + transitionController.dragDownAmount = 10f + + verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f) + } + + private fun enableSplitShade() { + context.getOrCreateTestableResources().addOverride( + R.bool.config_use_split_notification_shade, true + ) + configurationController.notifyConfigurationChanged() + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt new file mode 100644 index 000000000000..3a5d9ee16b0a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt @@ -0,0 +1,31 @@ +package com.android.systemui.statusbar.policy + +import android.content.res.Configuration + +/** Fake implementation of [ConfigurationController] for tests. */ +class FakeConfigurationController : ConfigurationController { + + private var listener: ConfigurationController.ConfigurationListener? = null + + override fun addCallback(listener: ConfigurationController.ConfigurationListener) { + this.listener = listener + } + + override fun removeCallback(listener: ConfigurationController.ConfigurationListener) { + this.listener = null + } + + override fun onConfigurationChanged(newConfiguration: Configuration?) { + listener?.onConfigChanged(newConfiguration) + } + + override fun notifyThemeChanged() { + listener?.onThemeChanged() + } + + fun notifyConfigurationChanged() { + onConfigurationChanged(newConfiguration = null) + } + + override fun isLayoutRtl(): Boolean = false +} |