diff options
| author | 2023-05-15 18:02:41 +0000 | |
|---|---|---|
| committer | 2023-05-15 18:02:41 +0000 | |
| commit | e843c8aaa91c1a9d495c1875fac6ebc56cdb2f5e (patch) | |
| tree | 451577801aa36c2204bcfb0c8786c307fb2ee353 | |
| parent | 0f287709a3fa17185c0ff5710acd782707942a8d (diff) | |
| parent | 51a5c2fd3bdcbeb4ee31b405a42b144a2fd6b3b7 (diff) | |
Merge "Fix Notification clipping flicker during AOD=>LS" into udc-dev am: 51a5c2fd3b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23048202
Change-Id: Id4db6e5945366c4c35a1604059a30d3f4c77c9f8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
3 files changed, 152 insertions, 2 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java index ae7c216adcbb..b0f3f598cb91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java @@ -93,6 +93,12 @@ public class AmbientState implements Dumpable { private boolean mAppearing; private float mPulseHeight = MAX_PULSE_HEIGHT; + /** + * The ExpandableNotificationRow that is pulsing, or the one that was pulsing + * when the device started to transition from AOD to LockScreen. + */ + private ExpandableNotificationRow mPulsingRow; + /** Fraction of lockscreen to shade animation (on lockscreen swipe down). */ private float mFractionToShade; @@ -564,6 +570,19 @@ public class AmbientState implements Dumpable { return mPulsing && entry.isAlerting(); } + public void setPulsingRow(ExpandableNotificationRow row) { + mPulsingRow = row; + } + + /** + * @param row The row to check + * @return true if row is the pulsing row when the device started to transition from AOD to lock + * screen + */ + public boolean isPulsingRow(ExpandableView row) { + return mPulsingRow == row; + } + public boolean isPanelTracking() { return mPanelTracking; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 92d767a419f1..6f1c378f429d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -548,7 +548,7 @@ public class StackScrollAlgorithm { ExpandableViewState viewState = view.getViewState(); viewState.location = ExpandableViewState.LOCATION_UNKNOWN; - final float expansionFraction = getExpansionFractionWithoutShelf( + float expansionFraction = getExpansionFractionWithoutShelf( algorithmState, ambientState); // Add gap between sections. @@ -619,6 +619,11 @@ public class StackScrollAlgorithm { updateViewWithShelf(view, viewState, shelfStart); } } + // Avoid pulsing notification flicker during AOD to LS + // A pulsing notification is already expanded, no need to expand it again with animation + if (ambientState.isPulsingRow(view)) { + expansionFraction = 1.0f; + } // Clip height of view right before shelf. viewState.height = (int) (getMaxAllowedChildHeight(view) * expansionFraction); } @@ -700,9 +705,11 @@ public class StackScrollAlgorithm { && !(child instanceof FooterView); } - private void updatePulsingStates(StackScrollAlgorithmState algorithmState, + @VisibleForTesting + void updatePulsingStates(StackScrollAlgorithmState algorithmState, AmbientState ambientState) { int childCount = algorithmState.visibleChildren.size(); + ExpandableNotificationRow pulsingRow = null; for (int i = 0; i < childCount; i++) { View child = algorithmState.visibleChildren.get(i); if (!(child instanceof ExpandableNotificationRow)) { @@ -714,6 +721,19 @@ public class StackScrollAlgorithm { } ExpandableViewState viewState = row.getViewState(); viewState.hidden = false; + pulsingRow = row; + } + + // Set AmbientState#pulsingRow to the current pulsing row when on AOD. + // Set AmbientState#pulsingRow=null when on lockscreen, since AmbientState#pulsingRow + // is only used for skipping the unfurl animation for (the notification that was already + // showing at full height on AOD) during the AOD=>lockscreen transition, where + // dozeAmount=[1f, 0f). We also need to reset the pulsingRow once it is no longer used + // because it will interfere with future unfurling animations - for example, during the + // LS=>AOD animation, the pulsingRow may stay at full height when it should squish with the + // rest of the stack. + if (ambientState.getDozeAmount() == 0.0f || ambientState.getDozeAmount() == 1.0f) { + ambientState.setPulsingRow(pulsingRow); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 7f20f1e53d97..e12d179c5aa5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -716,6 +716,94 @@ class StackScrollAlgorithmTest : SysuiTestCase() { .isLessThan(px(R.dimen.heads_up_pinned_elevation)) } + @Test + fun aodToLockScreen_hasPulsingNotification_pulsingNotificationRowDoesNotChange() { + // Given: Before AOD to LockScreen, there was a pulsing notification + val pulsingNotificationView = createPulsingViewMock() + val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState() + algorithmState.visibleChildren.add(pulsingNotificationView) + ambientState.setPulsingRow(pulsingNotificationView) + + // When: during AOD to LockScreen, any dozeAmount between (0, 1.0) is equivalent as a middle + // stage; here we use 0.5 for testing. + // stackScrollAlgorithm.updatePulsingStates is called + ambientState.dozeAmount = 0.5f + stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState) + + // Then: ambientState.pulsingRow should still be pulsingNotificationView + assertTrue(ambientState.isPulsingRow(pulsingNotificationView)) + } + + @Test + fun deviceOnAod_hasPulsingNotification_recordPulsingNotificationRow() { + // Given: Device is on AOD, there is a pulsing notification + // ambientState.pulsingRow is null before stackScrollAlgorithm.updatePulsingStates + ambientState.dozeAmount = 1.0f + val pulsingNotificationView = createPulsingViewMock() + val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState() + algorithmState.visibleChildren.add(pulsingNotificationView) + ambientState.setPulsingRow(null) + + // When: stackScrollAlgorithm.updatePulsingStates is called + stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState) + + // Then: ambientState.pulsingRow should record the pulsingNotificationView + assertTrue(ambientState.isPulsingRow(pulsingNotificationView)) + } + + @Test + fun deviceOnLockScreen_hasPulsingNotificationBefore_clearPulsingNotificationRowRecord() { + // Given: Device finished AOD to LockScreen, there was a pulsing notification, and + // ambientState.pulsingRow was not null before AOD to LockScreen + // pulsingNotificationView.showingPulsing() returns false since the device is on LockScreen + ambientState.dozeAmount = 0.0f + val pulsingNotificationView = createPulsingViewMock() + whenever(pulsingNotificationView.showingPulsing()).thenReturn(false) + val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState() + algorithmState.visibleChildren.add(pulsingNotificationView) + ambientState.setPulsingRow(pulsingNotificationView) + + // When: stackScrollAlgorithm.updatePulsingStates is called + stackScrollAlgorithm.updatePulsingStates(algorithmState, ambientState) + + // Then: ambientState.pulsingRow should be null + assertTrue(ambientState.isPulsingRow(null)) + } + + @Test + fun aodToLockScreen_hasPulsingNotification_pulsingNotificationRowShowAtFullHeight() { + // Given: Before AOD to LockScreen, there was a pulsing notification + val pulsingNotificationView = createPulsingViewMock() + val algorithmState = StackScrollAlgorithm.StackScrollAlgorithmState() + algorithmState.visibleChildren.add(pulsingNotificationView) + ambientState.setPulsingRow(pulsingNotificationView) + + // When: during AOD to LockScreen, any dozeAmount between (0, 1.0) is equivalent as a middle + // stage; here we use 0.5 for testing. The expansionFraction is also 0.5. + // stackScrollAlgorithm.resetViewStates is called. + ambientState.dozeAmount = 0.5f + setExpansionFractionWithoutShelfDuringAodToLockScreen( + ambientState, + algorithmState, + fraction = 0.5f + ) + stackScrollAlgorithm.resetViewStates(ambientState, 0) + + // Then: pulsingNotificationView should show at full height + assertEquals( + stackScrollAlgorithm.getMaxAllowedChildHeight(pulsingNotificationView), + pulsingNotificationView.viewState.height + ) + + // After: reset dozeAmount and expansionFraction + ambientState.dozeAmount = 0f + setExpansionFractionWithoutShelfDuringAodToLockScreen( + ambientState, + algorithmState, + fraction = 1f + ) + } + private fun createHunViewMock( isShadeOpen: Boolean, fullyVisible: Boolean, @@ -744,6 +832,29 @@ class StackScrollAlgorithmTest : SysuiTestCase() { headsUpIsVisible = fullyVisible } + private fun createPulsingViewMock( + ) = + mock<ExpandableNotificationRow>().apply { + whenever(this.viewState).thenReturn(ExpandableViewState()) + whenever(this.showingPulsing()).thenReturn(true) + } + + private fun setExpansionFractionWithoutShelfDuringAodToLockScreen( + ambientState: AmbientState, + algorithmState: StackScrollAlgorithm.StackScrollAlgorithmState, + fraction: Float + ) { + // showingShelf: false + algorithmState.firstViewInShelf = null + // scrimPadding: 0, because device is on lock screen + ambientState.setStatusBarState(StatusBarState.KEYGUARD) + ambientState.dozeAmount = 0.0f + // set stackEndHeight and stackHeight + // ExpansionFractionWithoutShelf == stackHeight / stackEndHeight + ambientState.stackEndHeight = 100f + ambientState.stackHeight = ambientState.stackEndHeight * fraction + } + private fun resetViewStates_expansionChanging_notificationAlphaUpdated( expansionFraction: Float, expectedAlpha: Float, |