Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +4 −3 Original line number Original line Diff line number Diff line Loading @@ -266,6 +266,10 @@ public class PipTouchHandler { mMagnetizedPip = mMotionHelper.getMagnetizedPip(); mMagnetizedPip = mMotionHelper.getMagnetizedPip(); mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0); 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.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener); mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { @Override @Override Loading Loading @@ -504,9 +508,6 @@ public class PipTouchHandler { mTargetView.setTranslationY(mTargetViewContainer.getHeight()); mTargetView.setTranslationY(mTargetViewContainer.getHeight()); mTargetViewContainer.setVisibility(View.VISIBLE); 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. // Cancel in case we were in the middle of animating it out. mMagneticTargetAnimator.cancel(); mMagneticTargetAnimator.cancel(); mMagneticTargetAnimator mMagneticTargetAnimator Loading packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt +31 −3 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.provider.Settings import android.view.MotionEvent import android.view.MotionEvent import android.view.VelocityTracker import android.view.VelocityTracker import android.view.View import android.view.View import android.view.ViewConfiguration import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.SpringForce import androidx.dynamicanimation.animation.SpringForce Loading Loading @@ -146,6 +147,10 @@ abstract class MagnetizedObject<T : Any>( private val velocityTracker: VelocityTracker = VelocityTracker.obtain() private val velocityTracker: VelocityTracker = VelocityTracker.obtain() private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator 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. */ /** Whether touch events are presently occurring within the magnetic field area of a target. */ val objectStuckToTarget: Boolean val objectStuckToTarget: Boolean get() = targetObjectIsStuckTo != null get() = targetObjectIsStuckTo != null Loading Loading @@ -324,15 +329,32 @@ abstract class MagnetizedObject<T : Any>( // When a gesture begins, recalculate target views' positions on the screen in case they // When a gesture begins, recalculate target views' positions on the screen in case they // have changed. Also, clear state. // have changed. Also, clear state. if (ev.action == MotionEvent.ACTION_DOWN) { 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() velocityTracker.clear() targetObjectIsStuckTo = null 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) 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 targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target -> val distanceFromTargetCenter = hypot( val distanceFromTargetCenter = hypot( ev.rawX - target.centerOnScreen.x, ev.rawX - target.centerOnScreen.x, Loading Loading @@ -559,8 +581,14 @@ abstract class MagnetizedObject<T : Any>( } } /** Updates the locations on screen of all of the [associatedTargets]. */ /** Updates the locations on screen of all of the [associatedTargets]. */ internal fun updateTargetViewLocations() { internal fun updateTargetViews() { associatedTargets.forEach { it.updateLocationOnScreen() } 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 } } } /** /** Loading packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt +8 −4 Original line number Original line Diff line number Diff line Loading @@ -186,8 +186,8 @@ class MagnetizedObjectTest : SysuiTestCase() { @Test @Test fun testMotionEventConsumption_downInMagneticField() { fun testMotionEventConsumption_downInMagneticField() { // We should consume DOWN events if they occur in the field. // We should not consume DOWN events even if they occur in the field. assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN))) x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN))) } } Loading Loading @@ -342,10 +342,14 @@ class MagnetizedObjectTest : SysuiTestCase() { // Trigger the magnet animation, and block the test until it ends. // Trigger the magnet animation, and block the test until it ends. PhysicsAnimatorTestUtils.setAllAnimationsBlock(true) PhysicsAnimatorTestUtils.setAllAnimationsBlock(true) magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( x = targetCenterX, x = targetCenterX - 250, y = targetCenterY, y = targetCenterY - 250, action = MotionEvent.ACTION_DOWN)) 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. // The object's (top-left) position should now position it centered over the target. assertEquals(targetCenterX - objectSize / 2, objectX) assertEquals(targetCenterX - objectSize / 2, objectX) assertEquals(targetCenterY - objectSize / 2, objectY) assertEquals(targetCenterY - objectSize / 2, objectY) Loading Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +4 −3 Original line number Original line Diff line number Diff line Loading @@ -266,6 +266,10 @@ public class PipTouchHandler { mMagnetizedPip = mMotionHelper.getMagnetizedPip(); mMagnetizedPip = mMotionHelper.getMagnetizedPip(); mMagneticTarget = mMagnetizedPip.addTarget(mTargetView, 0); 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.setPhysicsAnimatorUpdateListener(mMotionHelper.mResizePipUpdateListener); mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() { @Override @Override Loading Loading @@ -504,9 +508,6 @@ public class PipTouchHandler { mTargetView.setTranslationY(mTargetViewContainer.getHeight()); mTargetView.setTranslationY(mTargetViewContainer.getHeight()); mTargetViewContainer.setVisibility(View.VISIBLE); 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. // Cancel in case we were in the middle of animating it out. mMagneticTargetAnimator.cancel(); mMagneticTargetAnimator.cancel(); mMagneticTargetAnimator mMagneticTargetAnimator Loading
packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt +31 −3 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.provider.Settings import android.view.MotionEvent import android.view.MotionEvent import android.view.VelocityTracker import android.view.VelocityTracker import android.view.View import android.view.View import android.view.ViewConfiguration import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.SpringForce import androidx.dynamicanimation.animation.SpringForce Loading Loading @@ -146,6 +147,10 @@ abstract class MagnetizedObject<T : Any>( private val velocityTracker: VelocityTracker = VelocityTracker.obtain() private val velocityTracker: VelocityTracker = VelocityTracker.obtain() private val vibrator: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator 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. */ /** Whether touch events are presently occurring within the magnetic field area of a target. */ val objectStuckToTarget: Boolean val objectStuckToTarget: Boolean get() = targetObjectIsStuckTo != null get() = targetObjectIsStuckTo != null Loading Loading @@ -324,15 +329,32 @@ abstract class MagnetizedObject<T : Any>( // When a gesture begins, recalculate target views' positions on the screen in case they // When a gesture begins, recalculate target views' positions on the screen in case they // have changed. Also, clear state. // have changed. Also, clear state. if (ev.action == MotionEvent.ACTION_DOWN) { 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() velocityTracker.clear() targetObjectIsStuckTo = null 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) 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 targetObjectIsInMagneticFieldOf = associatedTargets.firstOrNull { target -> val distanceFromTargetCenter = hypot( val distanceFromTargetCenter = hypot( ev.rawX - target.centerOnScreen.x, ev.rawX - target.centerOnScreen.x, Loading Loading @@ -559,8 +581,14 @@ abstract class MagnetizedObject<T : Any>( } } /** Updates the locations on screen of all of the [associatedTargets]. */ /** Updates the locations on screen of all of the [associatedTargets]. */ internal fun updateTargetViewLocations() { internal fun updateTargetViews() { associatedTargets.forEach { it.updateLocationOnScreen() } 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 } } } /** /** Loading
packages/SystemUI/tests/src/com/android/systemui/util/magnetictarget/MagnetizedObjectTest.kt +8 −4 Original line number Original line Diff line number Diff line Loading @@ -186,8 +186,8 @@ class MagnetizedObjectTest : SysuiTestCase() { @Test @Test fun testMotionEventConsumption_downInMagneticField() { fun testMotionEventConsumption_downInMagneticField() { // We should consume DOWN events if they occur in the field. // We should not consume DOWN events even if they occur in the field. assertTrue(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( assertFalse(magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN))) x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_DOWN))) } } Loading Loading @@ -342,10 +342,14 @@ class MagnetizedObjectTest : SysuiTestCase() { // Trigger the magnet animation, and block the test until it ends. // Trigger the magnet animation, and block the test until it ends. PhysicsAnimatorTestUtils.setAllAnimationsBlock(true) PhysicsAnimatorTestUtils.setAllAnimationsBlock(true) magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( magnetizedObject.maybeConsumeMotionEvent(getMotionEvent( x = targetCenterX, x = targetCenterX - 250, y = targetCenterY, y = targetCenterY - 250, action = MotionEvent.ACTION_DOWN)) 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. // The object's (top-left) position should now position it centered over the target. assertEquals(targetCenterX - objectSize / 2, objectX) assertEquals(targetCenterX - objectSize / 2, objectX) assertEquals(targetCenterY - objectSize / 2, objectY) assertEquals(targetCenterY - objectSize / 2, objectY) Loading