Merge "Fix to snap notification view back when not clearable while updating" into nyc-dev
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 81ba23f..a08b2c1 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -34,6 +34,8 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
+import java.util.HashMap;
+
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
     private static final boolean DEBUG = false;
@@ -70,6 +72,7 @@
     private float mInitialTouchPos;
     private float mPerpendicularInitialTouchPos;
     private boolean mDragging;
+    private boolean mSnappingChild;
     private View mCurrView;
     private boolean mCanCurrViewBeDimissed;
     private float mDensityScale;
@@ -85,6 +88,8 @@
     private boolean mTouchAboveFalsingThreshold;
     private boolean mDisableHwLayers;
 
+    private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
+
     public SwipeHelper(int swipeDirection, Callback callback, Context context) {
         mCallback = callback;
         mHandler = new Handler();
@@ -252,6 +257,7 @@
             case MotionEvent.ACTION_DOWN:
                 mTouchAboveFalsingThreshold = false;
                 mDragging = false;
+                mSnappingChild = false;
                 mLongPressSent = false;
                 mVelocityTracker.clear();
                 mCurrView = mCallback.getChildAtPosition(ev);
@@ -391,9 +397,18 @@
             anim.setStartDelay(delay);
         }
         anim.addListener(new AnimatorListenerAdapter() {
+            private boolean mCancelled;
+
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
             public void onAnimationEnd(Animator animation) {
                 updateSwipeProgressFromOffset(animView, canBeDismissed);
-                mCallback.onChildDismissed(animView);
+                mDismissPendingMap.remove(animView);
+                if (!mCancelled) {
+                    mCallback.onChildDismissed(animView);
+                }
                 if (endAction != null) {
                     endAction.run();
                 }
@@ -402,7 +417,9 @@
                 }
             }
         });
+
         prepareDismissAnimation(animView, anim);
+        mDismissPendingMap.put(animView, anim);
         anim.start();
     }
 
@@ -429,11 +446,13 @@
         anim.setDuration(duration);
         anim.addListener(new AnimatorListenerAdapter() {
             public void onAnimationEnd(Animator animator) {
+                mSnappingChild = false;
                 updateSwipeProgressFromOffset(animView, canBeDismissed);
                 mCallback.onChildSnappedBack(animView, targetLeft);
             }
         });
         prepareSnapBackAnimation(animView, anim);
+        mSnappingChild = true;
         anim.start();
     }
 
@@ -466,6 +485,33 @@
         updateSwipeProgressFromOffset(animView, canBeDismissed);
     }
 
+    private void snapChildInstantly(final View view) {
+        final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
+        setTranslation(view, 0);
+        updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
+    }
+
+    public void snapChildIfNeeded(final View view, boolean animate) {
+        if ((mDragging && mCurrView == view) || mSnappingChild) {
+            return;
+        }
+        boolean needToSnap = false;
+        Animator dismissPendingAnim = mDismissPendingMap.get(view);
+        if (dismissPendingAnim != null) {
+            needToSnap = true;
+            dismissPendingAnim.cancel();
+        } else if (getTranslation(view) != 0) {
+            needToSnap = true;
+        }
+        if (needToSnap) {
+            if (animate) {
+                snapChild(view, 0 /* targetLeft */, 0.0f /* velocity */);
+            } else {
+                snapChildInstantly(view);
+            }
+        }
+    }
+
     public boolean onTouchEvent(MotionEvent ev) {
         if (mLongPressSent) {
             return true;
@@ -532,7 +578,9 @@
                         mCallback.onDragCancelled(mCurrView);
                         snapChild(mCurrView, 0 /* leftTarget */, velocity);
                     }
+                    mCurrView = null;
                 }
+                mDragging = false;
                 break;
         }
         return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1089ac7..2d2a08a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -2236,6 +2236,12 @@
         // swipe-dismissable)
         bindVetoButtonClickListener(entry.row, notification);
 
+        if (!notification.isClearable()) {
+            // The user may have performed a dismiss action on the notification, since it's
+            // not clearable we should snap it back.
+            mStackScroller.snapViewIfNeeded(entry.row);
+        }
+
         if (DEBUG) {
             // Is this for you?
             boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index bd5dcc6..bc276b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -957,6 +957,11 @@
         mSwipeHelper.dismissChild(child, 0, endRunnable, delay, true, duration);
     }
 
+    public void snapViewIfNeeded(View child) {
+        boolean animate = mIsExpanded || isPinnedHeadsUp(child);
+        mSwipeHelper.snapChildIfNeeded(child, animate);
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL