From cdc4baafd4e17124e1f0aed19197c18f0ca2742a Mon Sep 17 00:00:00 2001 From: Lyn Han Date: Fri, 5 Mar 2021 12:26:12 -0600 Subject: [PATCH] Round adjacent corners when swiping notification Unround corners instantly when notification starts to snap back, which feels more responsive. Fix bug where fast consecutive swipes are ignored because we did not set mTouchedView to the latest MotionEvent's view. Bug: 171817112 Test: swiped sandwiched notification => rounds bottom corners of notification before => rounds top corners of notification after (in the same section; other sections not affected) Test: swipe multiple notifications quickly => no jank Change-Id: I1a808dd92f9e46df4767681d861ea73530d732a8 --- .../src/com/android/systemui/SwipeHelper.java | 16 ++--- .../notification/row/ExpandableView.java | 9 --- .../stack/NotificationRoundnessManager.java | 63 ++++++++++++++++++- .../stack/NotificationStackScrollLayout.java | 55 ++++++++++------ ...tificationStackScrollLayoutController.java | 4 +- 5 files changed, 105 insertions(+), 42 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 3852b24fe4b37..fba34e0b8ad36 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -367,7 +367,7 @@ public class SwipeHelper implements Gefingerpoken { } /** - * @param view The view to be dismissed + * @param animView The view to be dismissed * @param velocity The desired pixels/second speed at which the view should move * @param endAction The action to perform at the end * @param delay The delay after which we should start @@ -477,12 +477,8 @@ public class SwipeHelper implements Gefingerpoken { public void snapChild(final View animView, final float targetLeft, float velocity) { final boolean canBeDismissed = mCallback.canChildBeDismissed(animView); - AnimatorUpdateListener updateListener = new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - onTranslationUpdate(animView, (float) animation.getAnimatedValue(), canBeDismissed); - } - }; + AnimatorUpdateListener updateListener = animation -> onTranslationUpdate(animView, + (float) animation.getAnimatedValue(), canBeDismissed); Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener); if (anim == null) { @@ -501,8 +497,6 @@ public class SwipeHelper implements Gefingerpoken { mSnappingChild = false; if (!wasCancelled) { updateSwipeProgressFromOffset(animView, canBeDismissed); - onChildSnappedBack(animView, targetLeft); - mCallback.onChildSnappedBack(animView, targetLeft); resetSwipeState(); } } @@ -513,6 +507,7 @@ public class SwipeHelper implements Gefingerpoken { mFlingAnimationUtils.apply(anim, getTranslation(animView), targetLeft, velocity, maxDistance); anim.start(); + mCallback.onChildSnappedBack(animView, targetLeft); } /** @@ -594,13 +589,12 @@ public class SwipeHelper implements Gefingerpoken { if (!mIsSwiping && !mMenuRowIntercepting) { if (mCallback.getChildAtPosition(ev) != null) { - // We are dragging directly over a card, make sure that we also catch the gesture // even if nobody else wants the touch event. + mTouchedView = mCallback.getChildAtPosition(ev); onInterceptTouchEvent(ev); return true; } else { - // We are not doing anything, make sure the long press callback // is not still ticking like a bomb waiting to go off. cancelLongPress(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index ba03d01b20b06..73e080423d408 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -69,7 +69,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { private float mContentTranslation; protected boolean mLastInSection; protected boolean mFirstInSection; - boolean mIsBeingSwiped; public ExpandableView(Context context, AttributeSet attrs) { super(context, attrs); @@ -174,14 +173,6 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { return false; } - public void setIsBeingSwiped(boolean swiped) { - mIsBeingSwiped = swiped; - } - - public boolean isBeingSwiped() { - return mIsBeingSwiped; - } - public boolean isHeadsUpAnimatingAway() { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java index 45f5b3136b9bd..b1ac12e84fb37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack; import android.content.res.Resources; import android.util.MathUtils; +import android.view.View; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; @@ -47,6 +48,10 @@ public class NotificationRoundnessManager { private ExpandableNotificationRow mTrackedHeadsUp; private float mAppearFraction; + private ExpandableView mSwipedView = null; + private ExpandableView mViewBeforeSwipedView = null; + private ExpandableView mViewAfterSwipedView = null; + @Inject NotificationRoundnessManager( KeyguardBypassController keyguardBypassController, @@ -68,6 +73,11 @@ public class NotificationRoundnessManager { boolean updateViewWithoutCallback(ExpandableView view, boolean animate) { + if (view == null + || view == mViewBeforeSwipedView + || view == mViewAfterSwipedView) { + return false; + } float topRoundness = getRoundness(view, true /* top */); float bottomRoundness = getRoundness(view, false /* top */); boolean topChanged = view.setTopRoundness(topRoundness, animate); @@ -105,9 +115,60 @@ public class NotificationRoundnessManager { return false; } + void setViewsAffectedBySwipe( + ExpandableView viewBefore, + ExpandableView viewSwiped, + ExpandableView viewAfter, + boolean cornerAnimationsEnabled) { + if (!cornerAnimationsEnabled) { + return; + } + final boolean animate = true; + + ExpandableView oldViewBefore = mViewBeforeSwipedView; + mViewBeforeSwipedView = viewBefore; + if (oldViewBefore != null) { + final float bottomRoundness = getRoundness(oldViewBefore, false /* top */); + oldViewBefore.setBottomRoundness(bottomRoundness, animate); + } + if (viewBefore != null) { + viewBefore.setBottomRoundness(1f, animate); + } + + ExpandableView oldSwipedview = mSwipedView; + mSwipedView = viewSwiped; + if (oldSwipedview != null) { + final float bottomRoundness = getRoundness(oldSwipedview, false /* top */); + final float topRoundness = getRoundness(oldSwipedview, true /* top */); + oldSwipedview.setTopRoundness(topRoundness, animate); + oldSwipedview.setBottomRoundness(bottomRoundness, animate); + } + if (viewSwiped != null) { + viewSwiped.setTopRoundness(1f, animate); + viewSwiped.setBottomRoundness(1f, animate); + } + + ExpandableView oldViewAfter = mViewAfterSwipedView; + mViewAfterSwipedView = viewAfter; + if (oldViewAfter != null) { + final float topRoundness = getRoundness(oldViewAfter, true /* top */); + oldViewAfter.setTopRoundness(topRoundness, animate); + } + if (viewAfter != null) { + viewAfter.setTopRoundness(1f, animate); + } + } + private float getRoundness(ExpandableView view, boolean top) { + if (view == null) { + return 0f; + } + if (view == mViewBeforeSwipedView + || view == mSwipedView + || view == mViewAfterSwipedView) { + return 1f; + } if ((view.isPinned() - || view.isBeingSwiped() || (view.isHeadsUpAnimatingAway()) && !mExpanded)) { return 1.0f; } 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 417ff5e9aed05..970efd5cbfe27 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 @@ -1025,8 +1025,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable boolean clip = clipStart > start && clipStart < end || clipEnd >= start && clipEnd <= end; clip &= !(first && mScrollAdapter.isScrolledToTop()); - child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0) - : ExpandableView.NO_ROUNDNESS); + child.setDistanceToTopRoundness(ExpandableView.NO_ROUNDNESS); first = false; } } @@ -2292,9 +2291,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable ExpandableView child = (ExpandableView) getChildAt(i); if (child.getVisibility() != View.GONE && !(child instanceof StackScrollerDecorView) - && child != mShelf - && (mSwipeHelper.getSwipedView() != child - || !child.getResources().getBoolean(R.bool.flag_notif_updates))) { + && child != mShelf) { children.add(child); } } @@ -4993,28 +4990,48 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mSwipedOutViews.add(v); } - void onSwipeBegin(View v) { - if (v instanceof ExpandableView) { - ExpandableView ev = (ExpandableView) v; - ev.setIsBeingSwiped(true); - mController.getNoticationRoundessManager() - .updateViewWithoutCallback(ev, true /* animate */); + void onSwipeBegin(View viewSwiped) { + if (!(viewSwiped instanceof ExpandableNotificationRow)) { + return; } - requestDisallowInterceptTouchEvent(true); + final int indexOfSwipedView = indexOfChild(viewSwiped); + if (indexOfSwipedView < 0) { + return; + } + mSectionsManager.updateFirstAndLastViewsForAllSections( + mSections, getChildrenWithBackground()); + View viewBefore = null; + if (indexOfSwipedView > 0) { + viewBefore = getChildAt(indexOfSwipedView - 1); + if (mSectionsManager.beginsSection(viewSwiped, viewBefore)) { + viewBefore = null; + } + } + View viewAfter = null; + if (indexOfSwipedView < getChildCount()) { + viewAfter = getChildAt(indexOfSwipedView + 1); + if (mSectionsManager.beginsSection(viewAfter, viewSwiped)) { + viewAfter = null; + } + } + mController.getNoticationRoundessManager() + .setViewsAffectedBySwipe((ExpandableView) viewBefore, + (ExpandableView) viewSwiped, + (ExpandableView) viewAfter, + getResources().getBoolean(R.bool.flag_notif_updates)); + updateFirstAndLastBackgroundViews(); + requestDisallowInterceptTouchEvent(true); updateContinuousShadowDrawing(); updateContinuousBackgroundDrawing(); requestChildrenUpdate(); } - void onSwipeEnd(View v) { - if (v instanceof ExpandableView) { - ExpandableView ev = (ExpandableView) v; - ev.setIsBeingSwiped(false); - mController.getNoticationRoundessManager() - .updateViewWithoutCallback(ev, true /* animate */); - } + void onSwipeEnd() { updateFirstAndLastBackgroundViews(); + mController.getNoticationRoundessManager() + .setViewsAffectedBySwipe(null, null, null, + getResources().getBoolean(R.bool.flag_notif_updates)); } void setTopHeadsUpEntry(NotificationEntry topEntry) { 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 399702869d704..7baad1cc265ed 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 @@ -399,7 +399,7 @@ public class NotificationStackScrollLayoutController { if (mView.getDismissAllInProgress()) { return; } - mView.onSwipeEnd(view); + mView.onSwipeEnd(); if (view instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) view; if (row.isHeadsUp()) { @@ -459,7 +459,7 @@ public class NotificationStackScrollLayoutController { @Override public void onChildSnappedBack(View animView, float targetLeft) { - mView.onSwipeEnd(animView); + mView.onSwipeEnd(); if (animView instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) animView; if (row.isPinned() && !canChildBeDismissed(row)