Divider tuning

- Make it harder to dismiss
- When dragging from the bottom, don't allow dismissing at the top

Change-Id: Ifd2de38abece7b996a813af41dcf777fa5cd1c18
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index 59a1e4a..5b40bc0 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.util.Log;
 
 import java.util.ArrayList;
 
@@ -30,6 +31,9 @@
  */
 public class DividerSnapAlgorithm {
 
+    private static final int MIN_FLING_VELOCITY_DP_PER_SECOND = 400;
+    private static final int MIN_DISMISS_VELOCITY_DP_PER_SECOND = 600;
+
     /**
      * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
      */
@@ -46,6 +50,7 @@
     private static final int SNAP_ONLY_1_1 = 2;
 
     private final float mMinFlingVelocityPxPerSecond;
+    private final float mMinDismissVelocityPxPerSecond;
     private final int mDisplayWidth;
     private final int mDisplayHeight;
     private final int mDividerSize;
@@ -64,10 +69,12 @@
     private final SnapTarget mDismissEndTarget;
     private final SnapTarget mMiddleTarget;
 
-    public DividerSnapAlgorithm(Resources res, float minFlingVelocityPxPerSecond,
-            int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
-            Rect insets) {
-        mMinFlingVelocityPxPerSecond = minFlingVelocityPxPerSecond;
+    public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
+            boolean isHorizontalDivision, Rect insets) {
+        mMinFlingVelocityPxPerSecond =
+                MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
+        mMinDismissVelocityPxPerSecond =
+                MIN_DISMISS_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
         mDividerSize = dividerSize;
         mDisplayWidth = displayWidth;
         mDisplayHeight = displayHeight;
@@ -85,15 +92,24 @@
     }
 
     public SnapTarget calculateSnapTarget(int position, float velocity) {
-        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
-            return snap(position);
-        }
-        if (position < mFirstSplitTarget.position && velocity < 0) {
+        return calculateSnapTarget(position, velocity, true /* hardDismiss */);
+    }
+
+    /**
+     * @param position the top/left position of the divider
+     * @param velocity current dragging velocity
+     * @param hardDismiss if set, make it a bit harder to get reach the dismiss targets
+     */
+    public SnapTarget calculateSnapTarget(int position, float velocity, boolean hardDismiss) {
+        if (position < mFirstSplitTarget.position && velocity < -mMinDismissVelocityPxPerSecond) {
             return mDismissStartTarget;
         }
-        if (position > mLastSplitTarget.position && velocity > 0) {
+        if (position > mLastSplitTarget.position && velocity > mMinDismissVelocityPxPerSecond) {
             return mDismissEndTarget;
         }
+        if (Math.abs(velocity) < mMinFlingVelocityPxPerSecond) {
+            return snap(position, hardDismiss);
+        }
         if (velocity < 0) {
             return mFirstSplitTarget;
         } else {
@@ -102,7 +118,7 @@
     }
 
     public SnapTarget calculateNonDismissingSnapTarget(int position) {
-        SnapTarget target = snap(position);
+        SnapTarget target = snap(position, false /* hardDismiss */);
         if (target == mDismissStartTarget) {
             return mFirstSplitTarget;
         } else if (target == mDismissEndTarget) {
@@ -146,12 +162,16 @@
         return mDismissEndTarget;
     }
 
-    private SnapTarget snap(int position) {
+    private SnapTarget snap(int position, boolean hardDismiss) {
         int minIndex = -1;
-        int minDistance = Integer.MAX_VALUE;
+        float minDistance = Float.MAX_VALUE;
         int size = mTargets.size();
         for (int i = 0; i < size; i++) {
-            int distance = Math.abs(position - mTargets.get(i).position);
+            SnapTarget target = mTargets.get(i);
+            float distance = Math.abs(position - target.position);
+            if (hardDismiss) {
+                distance /= target.distanceMultiplier;
+            }
             if (distance < minDistance) {
                 minIndex = i;
                 minDistance = distance;
@@ -165,7 +185,7 @@
         int dividerMax = isHorizontalDivision
                 ? mDisplayHeight
                 : mDisplayWidth;
-        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START, 0.35f));
         switch (mSnapMode) {
             case SNAP_MODE_16_9:
                 addRatio16_9Targets(isHorizontalDivision);
@@ -177,7 +197,7 @@
                 addMiddleTarget(isHorizontalDivision);
                 break;
         }
-        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END, 0.35f));
     }
 
     private void addFixedDivisionTargets(boolean isHorizontalDivision) {
@@ -232,9 +252,20 @@
         public final int position;
         public final int flag;
 
+        /**
+         * Multiplier used to calculate distance to snap position. The lower this value, the harder
+         * it's to snap on this target
+         */
+        private final float distanceMultiplier;
+
         public SnapTarget(int position, int flag) {
+            this(position, flag, 1f);
+        }
+
+        public SnapTarget(int position, int flag, float distanceMultiplier) {
             this.position = position;
             this.flag = flag;
+            this.distanceMultiplier = distanceMultiplier;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c16703e8..9e83dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -167,8 +167,7 @@
     public boolean startDragging(boolean animate) {
         mHandle.setTouching(true, animate);
         mDockSide = mWindowManagerProxy.getDockSide();
-        mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
-                mFlingAnimationUtils.getMinVelocityPxPerSecond(), mDisplayWidth,
+        mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
                 mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
         if (mDockSide != WindowManager.DOCKED_INVALID) {
             mWindowManagerProxy.setResizing(true);
@@ -180,9 +179,9 @@
         }
     }
 
-    public void stopDragging(int position, float velocity) {
+    public void stopDragging(int position, float velocity, boolean avoidDismissStart) {
         mHandle.setTouching(false, true /* animate */);
-        fling(position, velocity);
+        fling(position, velocity, avoidDismissStart);
         mWindowManager.setSlippery(true);
         releaseBackground();
     }
@@ -225,7 +224,7 @@
                 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
                     int position = calculatePosition(x, y);
                     SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
-                            0 /* velocity */);
+                            0 /* velocity */, false /* hardDismiss */);
                     resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
                 }
                 break;
@@ -239,7 +238,7 @@
                 mVelocityTracker.computeCurrentVelocity(1000);
                 int position = calculatePosition(x, y);
                 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
-                        : mVelocityTracker.getXVelocity());
+                        : mVelocityTracker.getXVelocity(), false /* avoidDismissStart */);
                 mMoving = false;
                 break;
         }
@@ -250,8 +249,12 @@
         event.setLocation(event.getRawX(), event.getRawY());
     }
 
-    private void fling(int position, float velocity) {
-        final SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
+    private void fling(int position, float velocity, boolean avoidDismissStart) {
+        SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
+        if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
+            snapTarget = mSnapAlgorithm.getFirstSplitTarget();
+        }
+        final SnapTarget finalTarget = snapTarget;
 
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(new AnimatorUpdateListener() {
@@ -260,13 +263,13 @@
                 resizeStack((Integer) animation.getAnimatedValue(),
                         animation.getAnimatedFraction() == 1f
                                 ? TASK_POSITION_SAME
-                                : snapTarget.position, snapTarget);
+                                : finalTarget.position, finalTarget);
             }
         });
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
-                commitSnapFlags(snapTarget);
+                commitSnapFlags(finalTarget);
                 mWindowManagerProxy.setResizing(false);
                 mDockSide = WindowManager.DOCKED_INVALID;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 2db0804..4ff11a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -218,7 +218,7 @@
             if (mDragMode == DRAG_MODE_DIVIDER) {
                 int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
                 SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
-                        .calculateSnapTarget(position, 0f /* velocity */);
+                        .calculateSnapTarget(position, 0f /* velocity */, false /* hardDismiss */);
                 mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecents(event.getRawY());
@@ -237,7 +237,8 @@
                                 : (int) event.getRawY(),
                         mIsVertical
                                 ? mVelocityTracker.getXVelocity()
-                                : mVelocityTracker.getYVelocity());
+                                : mVelocityTracker.getYVelocity(),
+                        true /* avoidDismissStart */);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecentsEnded(mVelocityTracker.getYVelocity());
             }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a75f2c9..2833b35 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -299,8 +299,7 @@
         final int orientation = mService.mCurConfiguration.orientation;
         mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
-                mService.mContext.getResources(),
-                0 /* minFlingVelocityPxPerSecond */, displayWidth, displayHeight,
+                mService.mContext.getResources(), displayWidth, displayHeight,
                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
 
@@ -552,7 +551,6 @@
             mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
                     mTmpRect2);
             final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
-                    0 /* minFlingVelocityPxPerSecond */,
                     di.logicalWidth,
                     di.logicalHeight,
                     dockDividerWidth,