Merge "Don't pull magnetized objects into the target unless they're dragged." into rvc-dev am: b2a2121b94

Change-Id: Ie7fd25820492e578f730a7583a70ef60360bfbe6
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 350ce29..79d2edd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -266,6 +266,10 @@
 
         mMagnetizedPip = mMotionHelper.getMagnetizedPip();
         mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0);
+
+        // Set the magnetic field radius equal to twice the size of the target.
+        mMagneticTarget.setMagneticFieldRadiusPx(targetSize * 2);
+
         mMagnetizedPip.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener);
         mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
             @Override
@@ -504,9 +508,6 @@
             mTargetView.setTranslationY(mTargetViewContainer.getHeight());
             mTargetViewContainer.setVisibility(View.VISIBLE);
 
-            // Set the magnetic field radius to half of PIP's width.
-            mMagneticTarget.setMagneticFieldRadiusPx(mMotionHelper.getBounds().width());
-
             // Cancel in case we were in the middle of animating it out.
             mMagneticTargetAnimator.cancel();
             mMagneticTargetAnimator
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index f27bdbf..e905e67 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -27,6 +27,7 @@
 import android.view.MotionEvent
 import android.view.VelocityTracker
 import android.view.View
+import android.view.ViewConfiguration
 import androidx.dynamicanimation.animation.DynamicAnimation
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringForce
@@ -146,6 +147,10 @@
     private val velocityTracker: VelocityTracker = VelocityTracker.obtain()
     private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
 
+    private var touchDown = PointF()
+    private var touchSlop = 0
+    private var movedBeyondSlop = false
+
     /** Whether touch events are presently occurring within the magnetic field area of a target. */
     val objectStuckToTarget: Boolean
         get() = targetObjectIsStuckTo != null
@@ -324,15 +329,32 @@
         // When a gesture begins, recalculate target views' positions on the screen in case they
         // have changed. Also, clear state.
         if (ev.action == MotionEvent.ACTION_DOWN) {
-            updateTargetViewLocations()
+            updateTargetViews()
 
-            // Clear the velocity tracker and assume we're not stuck to a target yet.
+            // Clear the velocity tracker and stuck target.
             velocityTracker.clear()
             targetObjectIsStuckTo = null
+
+            // Set the touch down coordinates and reset movedBeyondSlop.
+            touchDown.set(ev.rawX, ev.rawY)
+            movedBeyondSlop = false
         }
 
+        // Always pass events to the VelocityTracker.
         addMovement(ev)
 
+        // If we haven't yet moved beyond the slop distance, check if we have.
+        if (!movedBeyondSlop) {
+            val dragDistance = hypot(ev.rawX - touchDown.x, ev.rawY - touchDown.y)
+            if (dragDistance > touchSlop) {
+                // If we're beyond the slop distance, save that and continue.
+                movedBeyondSlop = true
+            } else {
+                // Otherwise, don't do anything yet.
+                return false
+            }
+        }
+
         val targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target ->
             val distanceFromTargetCenter = hypot(
                     ev.rawX - target.centerOnScreen.x,
@@ -559,8 +581,14 @@
     }
 
     /** Updates the locations on screen of all of the [associatedTargets]. */
-    internal fun updateTargetViewLocations() {
+    internal fun updateTargetViews() {
         associatedTargets.forEach { it.updateLocationOnScreen() }
+
+        // Update the touch slop, since the configuration may have changed.
+        if (associatedTargets.size > 0) {
+            touchSlop =
+                    ViewConfiguration.get(associatedTargets[0].targetView.context).scaledTouchSlop
+        }
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
index f6b7b74..251ca9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt
@@ -186,8 +186,8 @@
 
     @Test
     fun testMotionEventConsumption_downInMagneticField() {
-        // We should consume DOWN events if they occur in the field.
-        assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+        // We should not consume DOWN events even if they occur in the field.
+        assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
                 x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN)))
     }
 
@@ -342,10 +342,14 @@
         // Trigger the magnet animation, and block the test until it ends.
         PhysicsAnimatorTestUtils.setAllAnimationsBlock(true)
         magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
-                x = targetCenterX,
-                y = targetCenterY,
+                x = targetCenterX - 250,
+                y = targetCenterY - 250,
                 action = MotionEvent.ACTION_DOWN))
 
+        magnetizedObject.maybeConsumeMotionEvent(getMotionEvent(
+                x = targetCenterX,
+                y = targetCenterY))
+
         // The object's (top-left) position should now position it centered over the target.
         assertEquals(targetCenterX - objectSize / 2, objectX)
         assertEquals(targetCenterY - objectSize / 2, objectY)