[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
This commit is contained in:
Christian Göllner
2022-03-08 12:44:54 +01:00
parent f54c03715a
commit aabb969232
9 changed files with 211 additions and 14 deletions

View File

@@ -113,6 +113,22 @@ public class KeyguardStatusView extends GridLayout {
}
}
/** 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;
}

View File

@@ -136,6 +136,13 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
return mKeyguardClockSwitchController.hasCustomClock();
}
/**
* 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.
*/

View File

@@ -291,6 +291,18 @@ class MediaHierarchyManager @Inject constructor(
fullShadeTransitionProgress = progress
}
/**
* 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.

View File

@@ -406,6 +406,7 @@ class LockscreenShadeTransitionController @Inject constructor(
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
transitionToShadeAmountCommon(field)
transitionToShadeAmountKeyguard(field)
}
}
}
@@ -420,11 +421,6 @@ class LockscreenShadeTransitionController @Inject constructor(
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 @@ class LockscreenShadeTransitionController @Inject constructor(
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,

View File

@@ -616,6 +616,11 @@ public class NotificationPanelViewController extends PanelViewController {
*/
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 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateClock() {
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
mKeyguardStatusViewController
.setTranslationYExcludingMedia(mKeyguardOnlyTransitionTranslationY);
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setAlpha(alpha);
}
@@ -2732,11 +2739,12 @@ public class NotificationPanelViewController extends PanelViewController {
}
/**
* 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;

View File

@@ -112,4 +112,13 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mKeyguardUpdateMonitorCallbackCaptor.getValue().onUserSwitchComplete(0);
verify(mKeyguardClockSwitchController).refreshFormat();
}
@Test
public void setTranslationYExcludingMedia_forwardsCallToView() {
float translationY = 123f;
mController.setTranslationYExcludingMedia(translationY);
verify(mKeyguardStatusView).setChildrenTranslationYExcludingMediaView(translationY);
}
}

View File

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

View File

@@ -117,9 +117,9 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
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 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
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 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
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 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
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
}
}

View File

@@ -44,6 +44,7 @@ import org.mockito.Mockito.never
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>()
@@ -259,6 +260,49 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
verify(depthController, never()).transitionToFullShadeProgress
}
@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 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() {
}
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()
}