[Motion] Split-shade expansion on LS: move keyguard views
Moves the keyguard views (clock, smart space) vertically at the same
rate as the media view is moving.
Fixes: 222034043
Test: Manually
Change-Id: I66e87574d2664b8d5c3d4e0cf248cfcad8924903
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 31f466f..087817f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -113,6 +113,22 @@
}
}
+ /** Sets a translationY value on every child view except for the media view. */
+ public void setChildrenTranslationYExcludingMediaView(float translationY) {
+ setChildrenTranslationYExcluding(translationY, Set.of(mMediaHostContainer));
+ }
+
+ /** Sets a translationY value on every view except for the views in the provided set. */
+ private void setChildrenTranslationYExcluding(float translationY, Set<View> excludedViews) {
+ for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+ final View child = mStatusViewContainer.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setTranslationY(translationY);
+ }
+ }
+ }
+
public float getChildrenAlphaExcludingSmartSpace() {
return mChildrenAlphaExcludingSmartSpace;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index af3da9f..14c9cb2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -137,6 +137,13 @@
}
/**
+ * Sets a translationY on the views on the keyguard, except on the media view.
+ */
+ public void setTranslationYExcludingMedia(float translationY) {
+ mView.setChildrenTranslationYExcludingMediaView(translationY);
+ }
+
+ /**
* Set keyguard status view alpha.
*/
public void setAlpha(float alpha) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 18b6699..7a4dee2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -292,6 +292,18 @@
}
/**
+ * Returns the amount of translationY of the media container, during the current guided
+ * transformation, if running. If there is no guided transformation running, it will return 0.
+ */
+ fun getGuidedTransformationTranslationY(): Int {
+ if (!isCurrentlyInGuidedTransformation()) {
+ return -1
+ }
+ val startHost = getHost(previousLocation) ?: return 0
+ return targetBounds.top - startHost.currentBounds.top
+ }
+
+ /**
* Is the shade currently collapsing from the expanded qs? If we're on the lockscreen and in qs,
* we wouldn't want to transition in that case.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 1ab0345..ab4d0dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -406,6 +406,7 @@
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
transitionToShadeAmountCommon(field)
+ transitionToShadeAmountKeyguard(field)
}
}
}
@@ -420,11 +421,6 @@
val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
scrimController.setTransitionToFullShadeProgress(scrimProgress)
- // Fade out all content only visible on the lockscreen
- val npvcProgress =
- MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
- notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - npvcProgress)
-
if (depthControllerTransitionDistance > 0) {
val depthProgress =
MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
@@ -438,6 +434,22 @@
centralSurfaces.setTransitionToFullShadeProgress(statusBarProgress)
}
+ private fun transitionToShadeAmountKeyguard(dragDownAmount: Float) {
+ // Fade out all content only visible on the lockscreen
+ val keyguardAlphaProgress =
+ MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
+ val keyguardAlpha = 1f - keyguardAlphaProgress
+ val keyguardTranslationY = if (useSplitShade) {
+ // On split-shade, the translationY of the keyguard should stay in sync with the
+ // translation of media.
+ mediaHierarchyManager.getGuidedTransformationTranslationY()
+ } else {
+ 0
+ }
+ notificationPanelController
+ .setKeyguardTransitionProgress(keyguardAlpha, keyguardTranslationY)
+ }
+
private fun setDragDownAmountAnimated(
target: Float,
delay: Long = 0,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 0a2ea4c..cbdf5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -616,6 +616,11 @@
*/
private float mKeyguardOnlyContentAlpha = 1.0f;
+ /**
+ * The translationY of the views which only show on the keyguard but in shade / shade locked.
+ */
+ private int mKeyguardOnlyTransitionTranslationY = 0;
+
private float mUdfpsMaxYBurnInOffset;
/**
@@ -1575,6 +1580,8 @@
private void updateClock() {
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
+ mKeyguardStatusViewController
+ .setTranslationYExcludingMedia(mKeyguardOnlyTransitionTranslationY);
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setAlpha(alpha);
}
@@ -2732,11 +2739,12 @@
}
/**
- * Set the alpha of the keyguard elements which only show on the lockscreen, but not in
- * shade locked / shade. This is used when dragging down to the full shade.
+ * Set the alpha and translationY of the keyguard elements which only show on the lockscreen,
+ * but not in shade locked / shade. This is used when dragging down to the full shade.
*/
- public void setKeyguardOnlyContentAlpha(float keyguardAlpha) {
+ public void setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY) {
mKeyguardOnlyContentAlpha = Interpolators.ALPHA_IN.getInterpolation(keyguardAlpha);
+ mKeyguardOnlyTransitionTranslationY = keyguardTranslationY;
if (mBarState == KEYGUARD) {
// If the animator is running, it's already fading out the content and this is a reset
mBottomAreaShadeAlpha = mKeyguardOnlyContentAlpha;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 2fc9122..1753157 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -112,4 +112,13 @@
mKeyguardUpdateMonitorCallbackCaptor.getValue().onUserSwitchComplete(0);
verify(mKeyguardClockSwitchController).refreshFormat();
}
+
+ @Test
+ public void setTranslationYExcludingMedia_forwardsCallToView() {
+ float translationY = 123f;
+
+ mController.setTranslationYExcludingMedia(translationY);
+
+ verify(mKeyguardStatusView).setChildrenTranslationYExcludingMediaView(translationY);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
new file mode 100644
index 0000000..ce44f4d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -0,0 +1,55 @@
+package com.android.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class KeyguardStatusViewTest : SysuiTestCase() {
+
+ private lateinit var keyguardStatusView: KeyguardStatusView
+ private val mediaView: View
+ get() = keyguardStatusView.findViewById(R.id.status_view_media_container)
+ private val statusViewContainer: ViewGroup
+ get() = keyguardStatusView.findViewById(R.id.status_view_container)
+ private val childrenExcludingMedia
+ get() = statusViewContainer.children.filter { it != mediaView }
+
+ @Before
+ fun setUp() {
+ keyguardStatusView = LayoutInflater.from(context)
+ .inflate(R.layout.keyguard_status_view, /* root= */ null) as KeyguardStatusView
+ }
+
+ @Test
+ fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() {
+ val translationY = 1234f
+
+ keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+ assertThat(mediaView.translationY).isEqualTo(0)
+ }
+
+ @Test
+ fun setChildrenTranslationYExcludingMediaView_childrenAreTranslated() {
+ val translationY = 1234f
+
+ keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+ childrenExcludingMedia.forEach {
+ assertThat(it.translationY).isEqualTo(translationY)
+ }
+ }
+}
\ No newline at end of file
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 b359ae5..8e201b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -117,9 +117,9 @@
dreamOverlayStateController)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
- setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN)
- setupHost(qsHost, MediaHierarchyManager.LOCATION_QS)
- setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS)
+ setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
+ setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
+ setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
`when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
`when`(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
@@ -130,9 +130,9 @@
clearInvocations(mediaCarouselController)
}
- private fun setupHost(host: MediaHost, location: Int) {
+ private fun setupHost(host: MediaHost, location: Int, top: Int) {
`when`(host.location).thenReturn(location)
- `when`(host.currentBounds).thenReturn(Rect())
+ `when`(host.currentBounds).thenReturn(Rect(0, top, 0, top))
`when`(host.hostView).thenReturn(uniqueObjectHostView)
`when`(host.visible).thenReturn(true)
mediaHiearchyManager.register(host)
@@ -257,6 +257,20 @@
verify(mediaCarouselController).closeGuts()
}
+ @Test
+ fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() {
+ assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
+ }
+
+ @Test
+ fun getGuidedTransformationTranslationY_inGuidedTransformation_returnsCurrentTranslation() {
+ enterGuidedTransformation()
+
+ val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
+ assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY())
+ .isEqualTo(expectedTranslation)
+ }
+
private fun enableSplitShade() {
context.getOrCreateTestableResources().addOverride(
R.bool.config_use_split_notification_shade, true
@@ -284,4 +298,16 @@
private fun expandQS() {
mediaHiearchyManager.qsExpansion = 1.0f
}
+
+ private fun enterGuidedTransformation() {
+ mediaHiearchyManager.qsExpansion = 1.0f
+ goToLockscreen()
+ mediaHiearchyManager.setTransitionToFullShadeAmount(123f)
+ }
+
+ companion object {
+ private const val QQS_TOP = 123
+ private const val QS_TOP = 456
+ private const val LOCKSCREEN_TOP = 789
+ }
}
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 067caa9..64a0a23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -44,6 +44,7 @@
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.ArgumentMatchers.eq
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -260,6 +261,49 @@
}
@Test
+ fun setDragAmount_setsKeyguardTransitionProgress() {
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), anyInt())
+ }
+
+ @Test
+ fun setDragAmount_setsKeyguardAlphaBasedOnDistance() {
+ val alphaDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+ transitionController.dragDownAmount = 10f
+
+ val expectedAlpha = 1 - 10f / alphaDistance
+ verify(notificationPanelController)
+ .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
+ }
+
+ @Test
+ fun setDragAmount_notInSplitShade_setsKeyguardTranslationToZero() {
+ val mediaTranslationY = 123
+ disableSplitShade()
+ whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+ .thenReturn(mediaTranslationY)
+
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), eq(0))
+ }
+
+ @Test
+ fun setDragAmount_inSplitShade_setsKeyguardTranslationBasedOnMediaTranslation() {
+ val mediaTranslationY = 123
+ enableSplitShade()
+ whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+ .thenReturn(mediaTranslationY)
+
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController)
+ .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
+ }
+
+ @Test
fun setDragDownAmount_setsValueOnMediaHierarchyManager() {
transitionController.dragDownAmount = 10f
@@ -276,8 +320,16 @@
}
private fun enableSplitShade() {
+ setSplitShadeEnabled(true)
+ }
+
+ private fun disableSplitShade() {
+ setSplitShadeEnabled(false)
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, true
+ R.bool.config_use_split_notification_shade, enabled
)
configurationController.notifyConfigurationChanged()
}