Merge "Fix missing HUN Outro animations" into udc-dev am: 2803d28eb1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23601638

Change-Id: Idcea8a975b5364b0cb5befb0a4b7e2c451b111eb
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
András Kurucz
2023-06-12 15:55:00 +00:00
committed by Automerger Merge Worker
2 changed files with 110 additions and 22 deletions

View File

@@ -315,7 +315,8 @@ public class StackScrollAlgorithm {
float newNotificationEnd = newYTranslation + newHeight; float newNotificationEnd = newYTranslation + newHeight;
boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned(); boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
if (mClipNotificationScrollToTop if (mClipNotificationScrollToTop
&& ((isHeadsUp && !firstHeadsUp) || child.isHeadsUpAnimatingAway()) && !firstHeadsUp
&& (isHeadsUp || child.isHeadsUpAnimatingAway())
&& newNotificationEnd > firstHeadsUpEnd && newNotificationEnd > firstHeadsUpEnd
&& !ambientState.isShadeExpanded()) { && !ambientState.isShadeExpanded()) {
// The bottom of this view is peeking out from under the previous view. // The bottom of this view is peeking out from under the previous view.
@@ -619,13 +620,12 @@ public class StackScrollAlgorithm {
updateViewWithShelf(view, viewState, shelfStart); updateViewWithShelf(view, viewState, shelfStart);
} }
} }
// Avoid pulsing notification flicker during AOD to LS viewState.height = getMaxAllowedChildHeight(view);
// A pulsing notification is already expanded, no need to expand it again with animation if (!view.isPinned() && !view.isHeadsUpAnimatingAway()
if (ambientState.isPulsingRow(view)) { && !ambientState.isPulsingRow(view)) {
expansionFraction = 1.0f; // The expansion fraction should not affect HUNs or pulsing notifications.
viewState.height *= expansionFraction;
} }
// Clip height of view right before shelf.
viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction);
} }
algorithmState.mCurrentYPosition += algorithmState.mCurrentYPosition +=
@@ -785,6 +785,8 @@ public class StackScrollAlgorithm {
} }
} }
if (row.isPinned()) { if (row.isPinned()) {
// Make sure row yTranslation is at maximum the HUN yTranslation,
// which accounts for AmbientState.stackTopMargin in split-shade.
childState.setYTranslation( childState.setYTranslation(
Math.max(childState.getYTranslation(), headsUpTranslation)); Math.max(childState.getYTranslation(), headsUpTranslation));
childState.height = Math.max(row.getIntrinsicHeight(), childState.height); childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
@@ -809,7 +811,11 @@ public class StackScrollAlgorithm {
} }
} }
if (row.isHeadsUpAnimatingAway()) { if (row.isHeadsUpAnimatingAway()) {
childState.setYTranslation(Math.max(childState.getYTranslation(), mHeadsUpInset)); // Make sure row yTranslation is at maximum the HUN yTranslation,
// which accounts for AmbientState.stackTopMargin in split-shade.
childState.setYTranslation(
Math.max(childState.getYTranslation(), headsUpTranslation));
// keep it visible for the animation
childState.hidden = false; childState.hidden = false;
} }
} }

View File

@@ -35,7 +35,6 @@ import org.mockito.Mockito.`when` as whenever
@SmallTest @SmallTest
class StackScrollAlgorithmTest : SysuiTestCase() { class StackScrollAlgorithmTest : SysuiTestCase() {
@JvmField @Rule @JvmField @Rule
var expect: Expect = Expect.create() var expect: Expect = Expect.create()
@@ -82,26 +81,58 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
fun resetViewStates_defaultHun_yTranslationIsInset() { fun resetViewStates_defaultHun_yTranslationIsInset() {
whenever(notificationRow.isPinned).thenReturn(true) whenever(notificationRow.isPinned).thenReturn(true)
whenever(notificationRow.isHeadsUp).thenReturn(true) whenever(notificationRow.isHeadsUp).thenReturn(true)
resetViewStates_hunYTranslationIsInset()
stackScrollAlgorithm.resetViewStates(ambientState, 0)
assertThat(notificationRow.viewState.yTranslation)
.isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
} }
@Test @Test
fun resetViewStates_stackMargin_changesHunYTranslation() { fun resetViewStates_defaultHunWithStackMargin_changesHunYTranslation() {
whenever(notificationRow.isPinned).thenReturn(true) whenever(notificationRow.isPinned).thenReturn(true)
whenever(notificationRow.isHeadsUp).thenReturn(true) whenever(notificationRow.isHeadsUp).thenReturn(true)
val minHeadsUpTranslation = context.resources resetViewStates_stackMargin_changesHunYTranslation()
.getDimensionPixelSize(R.dimen.notification_side_paddings) }
// split shade case with top margin introduced by shade's status bar @Test
ambientState.stackTopMargin = 100 fun resetViewStates_hunAnimatingAway_yTranslationIsInset() {
stackScrollAlgorithm.resetViewStates(ambientState, 0) whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
resetViewStates_hunYTranslationIsInset()
}
// top margin presence should decrease heads up translation up to minHeadsUpTranslation @Test
assertThat(notificationRow.viewState.yTranslation).isEqualTo(minHeadsUpTranslation) fun resetViewStates_hunAnimatingAway_StackMarginChangesHunYTranslation() {
whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
resetViewStates_stackMargin_changesHunYTranslation()
}
@Test
fun resetViewStates_hunAnimatingAway_bottomNotClipped() {
whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
assertThat(notificationRow.viewState.clipBottomAmount).isEqualTo(0)
}
@Test
fun resetViewStates_hunsOverlapping_bottomHunClipped() {
val topHun = mockExpandableNotificationRow()
val bottomHun = mockExpandableNotificationRow()
whenever(topHun.isHeadsUp).thenReturn(true)
whenever(topHun.isPinned).thenReturn(true)
whenever(bottomHun.isHeadsUp).thenReturn(true)
whenever(bottomHun.isPinned).thenReturn(true)
resetViewStates_hunsOverlapping_bottomHunClipped(topHun, bottomHun)
}
@Test
fun resetViewStates_hunsOverlappingAndBottomHunAnimatingAway_bottomHunClipped() {
val topHun = mockExpandableNotificationRow()
val bottomHun = mockExpandableNotificationRow()
whenever(topHun.isHeadsUp).thenReturn(true)
whenever(topHun.isPinned).thenReturn(true)
whenever(bottomHun.isHeadsUpAnimatingAway).thenReturn(true)
resetViewStates_hunsOverlapping_bottomHunClipped(topHun, bottomHun)
} }
@Test @Test
@@ -855,6 +886,57 @@ class StackScrollAlgorithmTest : SysuiTestCase() {
ambientState.stackHeight = ambientState.stackEndHeight * fraction ambientState.stackHeight = ambientState.stackEndHeight * fraction
} }
private fun resetViewStates_hunYTranslationIsInset() {
stackScrollAlgorithm.resetViewStates(ambientState, 0)
assertThat(notificationRow.viewState.yTranslation)
.isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
}
private fun resetViewStates_stackMargin_changesHunYTranslation() {
val stackTopMargin = 50
val headsUpTranslationY = stackScrollAlgorithm.mHeadsUpInset - stackTopMargin
// we need the shelf to mock the real-life behaviour of StackScrollAlgorithm#updateChild
ambientState.shelf = notificationShelf
// split shade case with top margin introduced by shade's status bar
ambientState.stackTopMargin = stackTopMargin
stackScrollAlgorithm.resetViewStates(ambientState, 0)
// heads up translation should be decreased by the top margin
assertThat(notificationRow.viewState.yTranslation).isEqualTo(headsUpTranslationY)
}
private fun resetViewStates_hunsOverlapping_bottomHunClipped(
topHun: ExpandableNotificationRow,
bottomHun: ExpandableNotificationRow
) {
val topHunHeight = mContext.resources.getDimensionPixelSize(
R.dimen.notification_content_min_height)
val bottomHunHeight = mContext.resources.getDimensionPixelSize(
R.dimen.notification_max_heads_up_height)
whenever(topHun.intrinsicHeight).thenReturn(topHunHeight)
whenever(bottomHun.intrinsicHeight).thenReturn(bottomHunHeight)
// we need the shelf to mock the real-life behaviour of StackScrollAlgorithm#updateChild
ambientState.shelf = notificationShelf
// add two overlapping HUNs
hostView.removeAllViews()
hostView.addView(topHun)
hostView.addView(bottomHun)
stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
// the height shouldn't change
assertThat(topHun.viewState.height).isEqualTo(topHunHeight)
assertThat(bottomHun.viewState.height).isEqualTo(bottomHunHeight)
// the HUN at the bottom should be clipped
assertThat(topHun.viewState.clipBottomAmount).isEqualTo(0)
assertThat(bottomHun.viewState.clipBottomAmount).isEqualTo(bottomHunHeight - topHunHeight)
}
private fun resetViewStates_expansionChanging_notificationAlphaUpdated( private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
expansionFraction: Float, expansionFraction: Float,
expectedAlpha: Float, expectedAlpha: Float,