Aggressively reset SwipeHelper state
* Resetting just swipe (used internally as resetSwipeState) when snap was also in progress will now clear the mSnappingChild field, which also ensures snapChildIfNeeded() doesn't return early. * Resetting all state (used externally as resetTouchState) will always clear mSnappingChild and will cancel snap animations and reset state. * NSSL will now also resetTouchState whenever the notifications are hidden or unhidden. These changes all assume that the mTouchedView still pointed to the view which was misaligned in order to fix the bug. If the mTouchedView does NOT point to the misaligned view, then the fix for this bug is going to require one of two things: 1) we could track all active swipe/snap/dismiss views, rather than just the latest one, so that we can appropriately tear down all state. This is a major project. 2) we could, when notifications become visible, iterate all rows recursively and reset all their swipe translations naively. I'm worried about possible jank this could cause. Fixes: 259529672 Test: dumpsysui SwipeHelper Test: atest NotificationStackScrollLayoutTest Change-Id: I53d8e217e7f133388943e07be088d63623c4b735
This commit is contained in:
@@ -817,13 +817,39 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
|
||||
}
|
||||
}
|
||||
|
||||
public void resetSwipeState() {
|
||||
View swipedView = getSwipedView();
|
||||
private void resetSwipeState() {
|
||||
resetSwipeStates(/* resetAll= */ false);
|
||||
}
|
||||
|
||||
public void resetTouchState() {
|
||||
resetSwipeStates(/* resetAll= */ true);
|
||||
}
|
||||
|
||||
/** This method resets the swipe state, and if `resetAll` is true, also resets the snap state */
|
||||
private void resetSwipeStates(boolean resetAll) {
|
||||
final View touchedView = mTouchedView;
|
||||
final boolean wasSnapping = mSnappingChild;
|
||||
final boolean wasSwiping = mIsSwiping;
|
||||
mTouchedView = null;
|
||||
mIsSwiping = false;
|
||||
if (swipedView != null) {
|
||||
snapChildIfNeeded(swipedView, false, 0);
|
||||
onChildSnappedBack(swipedView, 0);
|
||||
// If we were swiping, then we resetting swipe requires resetting everything.
|
||||
resetAll |= wasSwiping;
|
||||
if (resetAll) {
|
||||
mSnappingChild = false;
|
||||
}
|
||||
if (touchedView == null) return; // No view to reset visually
|
||||
// When snap needs to be reset, first thing is to cancel any translation animation
|
||||
final boolean snapNeedsReset = resetAll && wasSnapping;
|
||||
if (snapNeedsReset) {
|
||||
cancelTranslateAnimation(touchedView);
|
||||
}
|
||||
// actually reset the view to default state
|
||||
if (resetAll) {
|
||||
snapChildIfNeeded(touchedView, false, 0);
|
||||
}
|
||||
// report if a swipe or snap was reset.
|
||||
if (wasSwiping || snapNeedsReset) {
|
||||
onChildSnappedBack(touchedView, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4395,6 +4395,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
boolean nowHiddenAtAll = mAmbientState.isHiddenAtAll();
|
||||
if (nowFullyHidden != wasFullyHidden) {
|
||||
updateVisibility();
|
||||
mSwipeHelper.resetTouchState();
|
||||
}
|
||||
if (!wasHiddenAtAll && nowHiddenAtAll) {
|
||||
resetExposedMenuView(true /* animate */, true /* animate */);
|
||||
@@ -5850,7 +5851,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
|
||||
}
|
||||
|
||||
private void cancelActiveSwipe() {
|
||||
mSwipeHelper.resetSwipeState();
|
||||
mSwipeHelper.resetTouchState();
|
||||
updateContinuousShadowDrawing();
|
||||
}
|
||||
|
||||
|
||||
@@ -794,7 +794,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onShadeClosesWithAnimationWillResetSwipeState() {
|
||||
public void onShadeClosesWithAnimationWillResetTouchState() {
|
||||
// GIVEN shade is expanded
|
||||
mStackScroller.setIsExpanded(true);
|
||||
clearInvocations(mNotificationSwipeHelper);
|
||||
@@ -804,12 +804,12 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
mStackScroller.setIsExpanded(false);
|
||||
mStackScroller.onExpansionStopped();
|
||||
|
||||
// VERIFY swipe is reset
|
||||
verify(mNotificationSwipeHelper).resetSwipeState();
|
||||
// VERIFY touch is reset
|
||||
verify(mNotificationSwipeHelper).resetTouchState();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onShadeClosesWithoutAnimationWillResetSwipeState() {
|
||||
public void onShadeClosesWithoutAnimationWillResetTouchState() {
|
||||
// GIVEN shade is expanded
|
||||
mStackScroller.setIsExpanded(true);
|
||||
clearInvocations(mNotificationSwipeHelper);
|
||||
@@ -817,8 +817,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
|
||||
// WHEN closing the shade without the animation
|
||||
mStackScroller.setIsExpanded(false);
|
||||
|
||||
// VERIFY swipe is reset
|
||||
verify(mNotificationSwipeHelper).resetSwipeState();
|
||||
// VERIFY touch is reset
|
||||
verify(mNotificationSwipeHelper).resetTouchState();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user