From c29777f4059da03ac663c3cc5b61d0f011aac8bb Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Wed, 8 Jun 2022 19:11:50 +0000 Subject: [PATCH 1/2] Fix squished notifications on the lockscreen. This fixes a stale state caused when stack height is not recalculated after being frozen. NSSL uses shouldSkipHeightUpdate() to prevent the stack height from being recalculated during various animations and gestures, but we didn't correctly trigger a recalculation after that 'freeze', so this CL adds the necessary recalculation at those transition points to prevent the old stack height from persisting until the next update. This also fixes a visual jump when unfreezing the stack height if it was frozen while the appear fraction was still changing. This jump is fixed by allowing the appear fraction to continue to apply and update the stackHeight (from the stackEndHeight) even while the stackEndHeight is frozen. Fixes: 235366457 Bug: 234824085 Test: drag shade up during aod->ls transition Change-Id: Ice6de1149b05564294e5c51308e962112cf4eda7 (cherry picked from commit 82596c5c5dd6c11da61000a17488615bfe12b01d) --- .../stack/NotificationStackScrollLayout.java | 28 +++++++ ...tificationStackScrollLayoutController.java | 4 + .../NotificationPanelViewController.java | 4 +- .../NotificationStackScrollLayoutTest.java | 76 ++++++++++++++++++- 4 files changed, 106 insertions(+), 6 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index c9d70d1ad44c2..e2ed1d83530b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -1323,10 +1323,24 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (mOnStackYChanged != null) { mOnStackYChanged.accept(listenerNeedsAnimation); } + updateStackEndHeightAndStackHeight(fraction); + } + + @VisibleForTesting + public void updateStackEndHeightAndStackHeight(float fraction) { + final float oldStackHeight = mAmbientState.getStackHeight(); if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) { final float endHeight = updateStackEndHeight( getHeight(), getEmptyBottomMargin(), mTopPadding); updateStackHeight(endHeight, fraction); + } else { + // Always updateStackHeight to prevent jumps in the stack height when this fraction + // suddenly reapplies after a freeze. + final float endHeight = mAmbientState.getStackEndHeight(); + updateStackHeight(endHeight, fraction); + } + if (oldStackHeight != mAmbientState.getStackHeight()) { + requestChildrenUpdate(); } } @@ -1343,6 +1357,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return stackEndHeight; } + @VisibleForTesting public void updateStackHeight(float endHeight, float fraction) { // During the (AOD<=>LS) transition where dozeAmount is changing, // apply dozeAmount to stack height instead of expansionFraction @@ -5041,6 +5056,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void setUnlockHintRunning(boolean running) { mAmbientState.setUnlockHintRunning(running); + if (!running) { + // re-calculate the stack height which was frozen while running this animation + updateStackPosition(); + } + } + + @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) + public void setPanelFlinging(boolean flinging) { + mAmbientState.setIsFlinging(flinging); + if (!flinging) { + // re-calculate the stack height which was frozen while flinging + updateStackPosition(); + } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 2493ccbe5a484..010e6cf908174 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -1190,6 +1190,10 @@ public class NotificationStackScrollLayoutController { mView.setUnlockHintRunning(running); } + public void setPanelFlinging(boolean flinging) { + mView.setPanelFlinging(flinging); + } + public boolean isFooterViewNotGone() { return mView.isFooterViewNotGone(); } 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 2cac0017db9c3..3580fe6cdbc52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -1782,14 +1782,14 @@ public class NotificationPanelViewController extends PanelViewController { mHeadsUpTouchHelper.notifyFling(!expand); mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */); setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f); - mAmbientState.setIsFlinging(true); + mNotificationStackScrollLayoutController.setPanelFlinging(true); super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing); } @Override protected void onFlingEnd(boolean cancelled) { super.onFlingEnd(cancelled); - mAmbientState.setIsFlinging(false); + mNotificationStackScrollLayoutController.setPanelFlinging(false); } private boolean onQsIntercept(MotionEvent event) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index f5fe6f3a1a5f4..b83743c90623c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -39,6 +39,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -122,12 +123,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { allowTestableLooperAsMainThread(); // Interact with real instance of AmbientState. - mAmbientState = new AmbientState( + mAmbientState = spy(new AmbientState( mContext, mDumpManager, mNotificationSectionsManager, mBypassController, - mStatusBarKeyguardViewManager); + mStatusBarKeyguardViewManager)); // Inject dependencies before initializing the layout mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState); @@ -190,7 +191,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { endHeight, dozeAmount); mStackScroller.updateStackHeight(endHeight, expansionFraction); - assertTrue(mAmbientState.getStackHeight() == expected); + assertThat(mAmbientState.getStackHeight()).isEqualTo(expected); } @Test @@ -205,7 +206,74 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { endHeight, expansionFraction); mStackScroller.updateStackHeight(endHeight, expansionFraction); - assertTrue(mAmbientState.getStackHeight() == expected); + assertThat(mAmbientState.getStackHeight()).isEqualTo(expected); + } + + @Test + public void updateStackEndHeightAndStackHeight_normallyUpdatesBoth() { + final float expansionFraction = 0.5f; + mAmbientState.setStatusBarState(StatusBarState.KEYGUARD); + + // Validate that by default we update everything + clearInvocations(mAmbientState); + mStackScroller.updateStackEndHeightAndStackHeight(expansionFraction); + verify(mAmbientState).setStackEndHeight(anyFloat()); + verify(mAmbientState).setStackHeight(anyFloat()); + } + + @Test + public void updateStackEndHeightAndStackHeight_onlyUpdatesStackHeightDuringSwipeUp() { + final float expansionFraction = 0.5f; + mAmbientState.setStatusBarState(StatusBarState.KEYGUARD); + mAmbientState.setSwipingUp(true); + + // Validate that when the gesture is in progress, we update only the stackHeight + clearInvocations(mAmbientState); + mStackScroller.updateStackEndHeightAndStackHeight(expansionFraction); + verify(mAmbientState, never()).setStackEndHeight(anyFloat()); + verify(mAmbientState).setStackHeight(anyFloat()); + } + + @Test + public void setPanelFlinging_updatesStackEndHeightOnlyOnFinish() { + final float expansionFraction = 0.5f; + mAmbientState.setStatusBarState(StatusBarState.KEYGUARD); + mAmbientState.setSwipingUp(true); + mStackScroller.setPanelFlinging(true); + mAmbientState.setSwipingUp(false); + + // Validate that when the animation is running, we update only the stackHeight + clearInvocations(mAmbientState); + mStackScroller.updateStackEndHeightAndStackHeight(expansionFraction); + verify(mAmbientState, never()).setStackEndHeight(anyFloat()); + verify(mAmbientState).setStackHeight(anyFloat()); + + // Validate that when the animation ends the stackEndHeight is recalculated immediately + clearInvocations(mAmbientState); + mStackScroller.setPanelFlinging(false); + verify(mAmbientState).setIsFlinging(eq(false)); + verify(mAmbientState).setStackEndHeight(anyFloat()); + verify(mAmbientState).setStackHeight(anyFloat()); + } + + @Test + public void setUnlockHintRunning_updatesStackEndHeightOnlyOnFinish() { + final float expansionFraction = 0.5f; + mAmbientState.setStatusBarState(StatusBarState.KEYGUARD); + mStackScroller.setUnlockHintRunning(true); + + // Validate that when the animation is running, we update only the stackHeight + clearInvocations(mAmbientState); + mStackScroller.updateStackEndHeightAndStackHeight(expansionFraction); + verify(mAmbientState, never()).setStackEndHeight(anyFloat()); + verify(mAmbientState).setStackHeight(anyFloat()); + + // Validate that when the animation ends the stackEndHeight is recalculated immediately + clearInvocations(mAmbientState); + mStackScroller.setUnlockHintRunning(false); + verify(mAmbientState).setUnlockHintRunning(eq(false)); + verify(mAmbientState).setStackEndHeight(anyFloat()); + verify(mAmbientState).setStackHeight(anyFloat()); } @Test From 28dc43e6a7698f4e6ace7718ce71a2d7a5b8bec4 Mon Sep 17 00:00:00 2001 From: Steve Elliott Date: Fri, 24 Jun 2022 11:01:49 -0400 Subject: [PATCH 2/2] Fix stale NSSL "fling" state caused by no-op fling If a fling gesture ends with the current Y position in the exact end position for the fling, then the code to run the fling animation is bypassed, but the flag in AmbientState tracking whether a fling is active is never reset. This CL replaces the short circuit logic with the standard fling-end logic, ensuring that all expected code paths are executed. Fixes: 234824085 Fixes: 237272856 Test: manual 1. Enter lockscreen 2. Swipe up and then down to the exact same position, in one continuous gesture 3. Wait for a notification update Observe: Shade resizes correctly to match the new contents Change-Id: Ie8ddf1dbaaf1ba607657646db05d3eb622fc9415 Merged-In: Ie8ddf1dbaaf1ba607657646db05d3eb622fc9415 (cherry picked from commit 7f387f9ae92490d7ab196eb2274019b543b8ab88) --- .../statusbar/phone/PanelViewController.java | 4 +--- .../NotificationPanelViewControllerTest.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 82ca842d48c9a..5d417e0b59e24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -599,9 +599,7 @@ public abstract class PanelViewController { float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) { if (target == mExpandedHeight && mOverExpansion == 0.0f) { // We're at the target and didn't fling and there's no overshoot - endJankMonitoring(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE); - mKeyguardStateController.notifyPanelFlingEnd(); - notifyExpandingFinished(); + onFlingEnd(false /* cancelled */); return; } mIsFlinging = true; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java index d47644f047a29..8900d8ff9fdac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java @@ -985,6 +985,21 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { verify(mKeyguardStateController).notifyPanelFlingEnd(); } + @Test + public void testSwipe_exactlyToTarget_notifiesNssl() { + // No over-expansion + mNotificationPanelViewController.setOverExpansion(0f); + // Fling to a target that is equal to the current position (i.e. a no-op fling). + mNotificationPanelViewController.flingToHeight( + 0f, + true, + mNotificationPanelViewController.mExpandedHeight, + 1f, + false); + // Verify that the NSSL is notified that the panel is *not* flinging. + verify(mNotificationStackScrollLayoutController).setPanelFlinging(false); + } + @Test public void testDoubleTapRequired_Keyguard() { FalsingManager.FalsingTapListener listener = getFalsingTapListener();