Merge "Adjustments to PIP heuristics to snapping along edges of screen"
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 6d13743..d7bd212 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -39,14 +39,20 @@
     private static final int SNAP_MODE_CORNERS_AND_SIDES = 1;
     // Allows snapping to anywhere along the edge of the screen
     private static final int SNAP_MODE_EDGE = 2;
+    // Allows snapping to four corners on a fling towards a corner or slow move near a corner
+    // snaps anywhere along the edge of screen otherwise
+    private static final int SNAP_MODE_CORNERS_AND_EDGES = 3;
 
     // The friction multiplier to control how slippery the PIP is when flung
     private static final float SCROLL_FRICTION_MULTIPLIER = 8f;
 
+    // Threshold to magnet to a corner
+    private static final float CORNER_MAGNET_THRESHOLD = 0.3f;
+
     private final Context mContext;
 
     private final ArrayList<Integer> mSnapGravities = new ArrayList<>();
-    private final int mDefaultSnapMode = SNAP_MODE_CORNERS_ONLY;
+    private final int mDefaultSnapMode = SNAP_MODE_CORNERS_AND_EDGES;
     private int mSnapMode = mDefaultSnapMode;
 
     private Scroller mScroller;
@@ -107,7 +113,24 @@
                 movementBounds.right + stackBounds.width(),
                 movementBounds.bottom + stackBounds.height());
         final Rect newBounds = new Rect(stackBounds);
-        if (mSnapMode == SNAP_MODE_EDGE) {
+        if (mSnapMode == SNAP_MODE_CORNERS_AND_EDGES) {
+            final Rect tmpBounds = new Rect();
+            final Point[] snapTargets = new Point[mSnapGravities.size()];
+            for (int i = 0; i < mSnapGravities.size(); i++) {
+                Gravity.apply(mSnapGravities.get(i), stackBounds.width(), stackBounds.height(),
+                        pipBounds, 0, 0, tmpBounds);
+                snapTargets[i] = new Point(tmpBounds.left, tmpBounds.top);
+            }
+            Point snapTarget = findClosestPoint(stackBounds.left, stackBounds.top, snapTargets);
+            float distance = distanceToPoint(snapTarget, stackBounds.left, stackBounds.top);
+            final float thresh = stackBounds.width() * CORNER_MAGNET_THRESHOLD;
+            if (distance < thresh) {
+                newBounds.offsetTo(snapTarget.x, snapTarget.y);
+            } else {
+                // Otherwise we snap to the edge
+                snapRectToClosestEdge(stackBounds, movementBounds, newBounds);
+            }
+        } else if (mSnapMode == SNAP_MODE_EDGE) {
             // Find the closest edge to the given stack bounds and snap to it
             snapRectToClosestEdge(stackBounds, movementBounds, newBounds);
         } else {
@@ -273,6 +296,7 @@
                 }
                 // Fall through
             case SNAP_MODE_CORNERS_ONLY:
+            case SNAP_MODE_CORNERS_AND_EDGES:
                 mSnapGravities.add(Gravity.TOP | Gravity.LEFT);
                 mSnapGravities.add(Gravity.TOP | Gravity.RIGHT);
                 mSnapGravities.add(Gravity.BOTTOM | Gravity.LEFT);