Improve the falsing logic for unlock motion

Bug: 20563134
Change-Id: I628829915ad2cc7f1df5d0c971def44f6eacdae4
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 0a6d472..8343497 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -214,6 +214,10 @@
         return null;
     }
 
+    public boolean isOnAffordanceIcon(float x, float y) {
+        return isOnIcon(mLeftIcon, x, y) || isOnIcon(mRightIcon, x, y);
+    }
+
     private boolean isOnIcon(View icon, float x, float y) {
         float iconX = icon.getX() + icon.getWidth() / 2.0f;
         float iconY = icon.getY() + icon.getHeight() / 2.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 7d61099..b87c25b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -518,9 +518,9 @@
 
     @Override
     protected void flingToHeight(float vel, boolean expand, float target,
-            float collapseSpeedUpFactor) {
+            float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
         mHeadsUpTouchHelper.notifyFling(!expand);
-        super.flingToHeight(vel, expand, target, collapseSpeedUpFactor);
+        super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
     @Override
@@ -771,8 +771,8 @@
     }
 
     @Override
-    protected boolean flingExpands(float vel, float vectorVel) {
-        boolean expands = super.flingExpands(vel, vectorVel);
+    protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
+        boolean expands = super.flingExpands(vel, vectorVel, x, y);
 
         // If we are already running a QS expansion, make sure that we keep the panel open.
         if (mQsExpansionAnimator != null) {
@@ -786,6 +786,11 @@
         return mStatusBar.getBarState() != StatusBarState.SHADE;
     }
 
+    @Override
+    protected boolean shouldGestureIgnoreXTouchSlop(float x, float y) {
+        return !mAfforanceHelper.isOnAffordanceIcon(x, y);
+    }
+
     private void onQsTouch(MotionEvent event) {
         int pointerIndex = event.findPointerIndex(mTrackingPointer);
         if (pointerIndex < 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index b32cd9c..4452dd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -76,6 +76,7 @@
     private int mUnlockFalsingThreshold;
     private boolean mTouchStartedInEmptyArea;
     private boolean mMotionAborted;
+    private boolean mUpwardsWhenTresholdReached;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -109,6 +110,7 @@
 
     private boolean mExpanding;
     private boolean mGestureWaitForTouchSlop;
+    private boolean mIgnoreXTouchSlop;
     private Runnable mPeekRunnable = new Runnable() {
         @Override
         public void run() {
@@ -240,9 +242,9 @@
         final float y = event.getY(pointerIndex);
 
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mGestureWaitForTouchSlop = isShadeCollapsed();
+            mGestureWaitForTouchSlop = isShadeCollapsed() || hasConflictingGestures();
+            mIgnoreXTouchSlop = isShadeCollapsed() || shouldGestureIgnoreXTouchSlop(x, y);
         }
-        boolean waitForTouchSlop = hasConflictingGestures() || mGestureWaitForTouchSlop;
 
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
@@ -258,7 +260,7 @@
                     initVelocityTracker();
                 }
                 trackMovement(event);
-                if (!waitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) ||
+                if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) ||
                         mPeekPending || mPeekAnimator != null) {
                     cancelHeightAnimator();
                     cancelPeek();
@@ -296,9 +298,9 @@
                 // y-component of the gesture, as we have no conflicting horizontal gesture.
                 if (Math.abs(h) > mTouchSlop
                         && (Math.abs(h) > Math.abs(x - mInitialTouchX)
-                                || mInitialOffsetOnTouch == 0f)) {
+                                || mIgnoreXTouchSlop)) {
                     mTouchSlopExceeded = true;
-                    if (waitForTouchSlop && !mTracking) {
+                    if (mGestureWaitForTouchSlop && !mTracking) {
                         if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
                             startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
                             h = 0;
@@ -318,8 +320,9 @@
                 }
                 if (-h >= getFalsingThreshold()) {
                     mTouchAboveFalsingThreshold = true;
+                    mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
                 }
-                if (!mJustPeeked && (!waitForTouchSlop || mTracking) && !isTrackingBlocked()) {
+                if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
                     setExpandedHeightInternal(newHeight);
                 }
 
@@ -332,7 +335,20 @@
                 endMotionEvent(event, x, y, false /* forceCancel */);
                 break;
         }
-        return !waitForTouchSlop || mTracking;
+        return !mGestureWaitForTouchSlop || mTracking;
+    }
+
+    /**
+     * @return whether the swiping direction is upwards and above a 45 degree angle compared to the
+     * horizontal direction
+     */
+    private boolean isDirectionUpwards(float x, float y) {
+        float xDiff = x - mInitialTouchX;
+        float yDiff = y - mInitialTouchY;
+        if (yDiff >= 0) {
+            return false;
+        }
+        return Math.abs(yDiff) >= Math.abs(xDiff);
     }
 
     protected void startExpandMotion(float newX, float newY, boolean startTracking,
@@ -361,7 +377,7 @@
                 vectorVel = (float) Math.hypot(
                         mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
             }
-            boolean expand = flingExpands(vel, vectorVel)
+            boolean expand = flingExpands(vel, vectorVel, x, y)
                     || event.getActionMasked() == MotionEvent.ACTION_CANCEL
                     || forceCancel;
             onTrackingStopped(expand);
@@ -377,7 +393,7 @@
                                 EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK,
                                 heightDp, velocityDp);
                     }
-            fling(vel, expand);
+            fling(vel, expand, isFalseTouch(x, y));
             mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
             if (mUpdateFlingOnLayout) {
                 mUpdateFlingVelocity = vel;
@@ -401,6 +417,8 @@
 
     protected abstract boolean hasConflictingGestures();
 
+    protected abstract boolean shouldGestureIgnoreXTouchSlop(float x, float y);
+
     protected void onTrackingStopped(boolean expand) {
         mTracking = false;
         mBar.onTrackingStopped(PanelView.this, expand);
@@ -553,8 +571,8 @@
      * @param vectorVel the length of the vectorial velocity
      * @return whether a fling should expands the panel; contracts otherwise
      */
-    protected boolean flingExpands(float vel, float vectorVel) {
-        if (isBelowFalsingThreshold()) {
+    protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
+        if (isFalseTouch(x, y)) {
             return true;
         }
         if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -564,22 +582,41 @@
         }
     }
 
-    private boolean isBelowFalsingThreshold() {
-        return !mTouchAboveFalsingThreshold && mStatusBar.isFalsingThresholdNeeded();
+    /**
+     * @param x the final x-coordinate when the finger was lifted
+     * @param y the final y-coordinate when the finger was lifted
+     * @return whether this motion should be regarded as a false touch
+     */
+    private boolean isFalseTouch(float x, float y) {
+        if (!mStatusBar.isFalsingThresholdNeeded()) {
+            return false;
+        }
+        if (!mTouchAboveFalsingThreshold) {
+            return true;
+        }
+        if (mUpwardsWhenTresholdReached) {
+            return false;
+        }
+        return !isDirectionUpwards(x, y);
     }
 
     protected void fling(float vel, boolean expand) {
-        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */);
+        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, false);
     }
 
-    protected void fling(float vel, boolean expand, float collapseSpeedUpFactor) {
+    protected void fling(float vel, boolean expand, boolean expandBecauseOfFalsing) {
+        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, expandBecauseOfFalsing);
+    }
+
+    protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
+            boolean expandBecauseOfFalsing) {
         cancelPeek();
         float target = expand ? getMaxPanelHeight() : 0.0f;
-        flingToHeight(vel, expand, target, collapseSpeedUpFactor);
+        flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
     protected void flingToHeight(float vel, boolean expand, float target,
-            float collapseSpeedUpFactor) {
+            float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
         // Hack to make the expand transition look nice when clear all button is visible - we make
         // the animation only to the last notification, and then jump to the maximum panel height so
         // clear all just fades in and the decelerating motion is towards the last notification.
@@ -596,12 +633,11 @@
         mOverExpandedBeforeFling = getOverExpansionAmount() > 0f;
         ValueAnimator animator = createHeightAnimator(target);
         if (expand) {
-            boolean belowFalsingThreshold = isBelowFalsingThreshold();
-            if (belowFalsingThreshold) {
+            if (expandBecauseOfFalsing) {
                 vel = 0;
             }
             mFlingAnimationUtils.apply(animator, mExpandedHeight, target, vel, getHeight());
-            if (belowFalsingThreshold) {
+            if (expandBecauseOfFalsing) {
                 animator.setDuration(350);
             }
         } else {
@@ -776,7 +812,7 @@
                 mNextCollapseSpeedUpFactor = speedUpFactor;
                 postDelayed(mFlingCollapseRunnable, 120);
             } else {
-                fling(0, false /* expand */, speedUpFactor);
+                fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */);
             }
         }
     }
@@ -784,7 +820,8 @@
     private final Runnable mFlingCollapseRunnable = new Runnable() {
         @Override
         public void run() {
-            fling(0, false /* expand */, mNextCollapseSpeedUpFactor);
+            fling(0, false /* expand */, mNextCollapseSpeedUpFactor,
+                    false /* expandBecauseOfFalsing */);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b6dbfce..cf31d64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1798,9 +1798,7 @@
     }
 
     public boolean isFalsingThresholdNeeded() {
-        boolean onKeyguard = getBarState() == StatusBarState.KEYGUARD;
-        boolean isCurrentlyInsecure = mUnlockMethodCache.isCurrentlyInsecure();
-        return onKeyguard && (isCurrentlyInsecure || mDozing || mScreenOnComingFromTouch);
+        return getBarState() == StatusBarState.KEYGUARD;
     }
 
     public boolean isDozing() {