Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6329b349 authored by Mady Mellor's avatar Mady Mellor
Browse files

Pass the magnetized object instead of using member variable

Wasn't able to repro this, but a couple of reports of this have come
in.

There can be a bit of time between the drag event and
dismissMagentizedObject being called (it gets called after the
bubble in the dismiss target animates out). So it could be possible
that the mMagnetizedObject has changed in that time. This CL passes
the object to the MagnetListener methods & uses that directly.

Additionally does the actions in the individual bubble / stack
listeners rather than a separate method that's only used in those
2 call sites and does something different for each one.

Flag: None; bug fix
Test: atest MagnetizedObjectTest MenuViewLayerTest DragToInteractAnimationControllerTest
Test: manual - drag and dismiss bubbles while stack is expanded
             - drag and dismiss the stack
Bug: 315127709

Change-Id: I362c824f3434e0b8296af5cb93684ed61c99378a
parent 9a9bb380
Loading
Loading
Loading
Loading
+29 −41
Original line number Diff line number Diff line
@@ -441,43 +441,42 @@ public class BubbleStackView extends FrameLayout
    /** Magnet listener that handles animating and dismissing individual dragged-out bubbles. */
    private final MagnetizedObject.MagnetListener mIndividualBubbleMagnetListener =
            new MagnetizedObject.MagnetListener() {

                @Override
                public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
                    if (mExpandedAnimationController.getDraggedOutBubble() == null) {
                        return;
                public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target,
                        @NonNull MagnetizedObject draggedObject) {
                    if (draggedObject.getUnderlyingObject() instanceof View view) {
                        animateDismissBubble(view, true);
                    }
                    animateDismissBubble(
                            mExpandedAnimationController.getDraggedOutBubble(), true);
                }

                @Override
                public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
                        @NonNull MagnetizedObject draggedObject,
                        float velX, float velY, boolean wasFlungOut) {
                    if (mExpandedAnimationController.getDraggedOutBubble() == null) {
                        return;
                    }
                    animateDismissBubble(
                            mExpandedAnimationController.getDraggedOutBubble(), false);
                    if (draggedObject.getUnderlyingObject() instanceof View view) {
                        animateDismissBubble(view, false);

                        if (wasFlungOut) {
                        mExpandedAnimationController.snapBubbleBack(
                                mExpandedAnimationController.getDraggedOutBubble(), velX, velY);
                            mExpandedAnimationController.snapBubbleBack(view, velX, velY);
                            mDismissView.hide();
                        } else {
                            mExpandedAnimationController.onUnstuckFromTarget();
                        }
                    }

                @Override
                public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
                    if (mExpandedAnimationController.getDraggedOutBubble() == null) {
                        return;
                }

                @Override
                public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target,
                        @NonNull MagnetizedObject<?> draggedObject) {
                    if (draggedObject.getUnderlyingObject() instanceof View view) {
                        mExpandedAnimationController.dismissDraggedOutBubble(
                            mExpandedAnimationController.getDraggedOutBubble() /* bubble */,
                                view /* bubble */,
                                mDismissView.getHeight() /* translationYBy */,
                            BubbleStackView.this::dismissMagnetizedObject /* after */);
                                () -> dismissBubbleIfExists(
                                        mBubbleData.getBubbleWithView(view)) /* after */);
                    }

                    mDismissView.hide();
                }
            };
@@ -487,12 +486,14 @@ public class BubbleStackView extends FrameLayout
            new MagnetizedObject.MagnetListener() {
                @Override
                public void onStuckToTarget(
                        @NonNull MagnetizedObject.MagneticTarget target) {
                        @NonNull MagnetizedObject.MagneticTarget target,
                        @NonNull MagnetizedObject<?> draggedObject) {
                    animateDismissBubble(mBubbleContainer, true);
                }

                @Override
                public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
                        @NonNull MagnetizedObject<?> draggedObject,
                        float velX, float velY, boolean wasFlungOut) {
                    animateDismissBubble(mBubbleContainer, false);
                    if (wasFlungOut) {
@@ -505,14 +506,14 @@ public class BubbleStackView extends FrameLayout
                }

                @Override
                public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
                public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target,
                        @NonNull MagnetizedObject<?> draggedObject) {
                    mStackAnimationController.animateStackDismissal(
                            mDismissView.getHeight() /* translationYBy */,
                            () -> {
                                mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
                                resetDismissAnimator();
                                dismissMagnetizedObject();
                            }
                    );
                            } /*after */);
                    mDismissView.hide();
                }
            };
@@ -2759,19 +2760,6 @@ public class BubbleStackView extends FrameLayout
        return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event);
    }

    /**
     * Dismisses the magnetized object - either an individual bubble, if we're expanded, or the
     * stack, if we're collapsed.
     */
    private void dismissMagnetizedObject() {
        if (mIsExpanded) {
            final View draggedOutBubbleView = (View) mMagnetizedObject.getUnderlyingObject();
            dismissBubbleIfExists(mBubbleData.getBubbleWithView(draggedOutBubbleView));
        } else {
            mBubbleData.dismissAll(Bubbles.DISMISS_USER_GESTURE);
        }
    }

    private void dismissBubbleIfExists(@Nullable BubbleViewProvider bubble) {
        if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
            if (mIsExpanded && mBubbleData.getBubbles().size() > 1
+13 −6
Original line number Diff line number Diff line
@@ -126,12 +126,16 @@ class BubbleBarExpandedViewDragController(
    }

    private inner class MagnetListener : MagnetizedObject.MagnetListener {
        override fun onStuckToTarget(target: MagnetizedObject.MagneticTarget) {
        override fun onStuckToTarget(
                target: MagnetizedObject.MagneticTarget,
                draggedObject: MagnetizedObject<*>
        ) {
            isStuckToDismiss = true
        }

        override fun onUnstuckFromTarget(
                target: MagnetizedObject.MagneticTarget,
                draggedObject: MagnetizedObject<*>,
                velX: Float,
                velY: Float,
                wasFlungOut: Boolean
@@ -140,7 +144,10 @@ class BubbleBarExpandedViewDragController(
            animationHelper.animateUnstuckFromDismissView()
        }

        override fun onReleasedInTarget(target: MagnetizedObject.MagneticTarget) {
        override fun onReleasedInTarget(
                target: MagnetizedObject.MagneticTarget,
                draggedObject: MagnetizedObject<*>
        ) {
            onDismissed()
            dismissView.hide()
        }
+14 −8
Original line number Diff line number Diff line
@@ -91,8 +91,9 @@ abstract class MagnetizedObject<T : Any>(
         * to [onUnstuckFromTarget] or [onReleasedInTarget].
         *
         * @param target The target that the object is now stuck to.
         * @param draggedObject The object that is stuck to the target.
         */
        fun onStuckToTarget(target: MagneticTarget)
        fun onStuckToTarget(target: MagneticTarget, draggedObject: MagnetizedObject<*>)

        /**
         * Called when the object is no longer stuck to a target. This means that either touch
@@ -110,6 +111,7 @@ abstract class MagnetizedObject<T : Any>(
         * and [maybeConsumeMotionEvent] is now returning false.
         *
         * @param target The target that this object was just unstuck from.
         * @param draggedObject The object being unstuck from the target.
         * @param velX The X velocity of the touch gesture when it exited the magnetic field.
         * @param velY The Y velocity of the touch gesture when it exited the magnetic field.
         * @param wasFlungOut Whether the object was unstuck via a fling gesture. This means that
@@ -119,6 +121,7 @@ abstract class MagnetizedObject<T : Any>(
         */
        fun onUnstuckFromTarget(
            target: MagneticTarget,
            draggedObject: MagnetizedObject<*>,
            velX: Float,
            velY: Float,
            wasFlungOut: Boolean
@@ -129,8 +132,9 @@ abstract class MagnetizedObject<T : Any>(
         * velocity to reach it.
         *
         * @param target The target that the object was released in.
         * @param draggedObject The object released in the target.
         */
        fun onReleasedInTarget(target: MagneticTarget)
        fun onReleasedInTarget(target: MagneticTarget, draggedObject: MagnetizedObject<*>)
    }

    private val animator: PhysicsAnimator<T> = PhysicsAnimator.getInstance(underlyingObject)
@@ -386,7 +390,7 @@ abstract class MagnetizedObject<T : Any>(
            // animate sticking to the magnet.
            targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
            cancelAnimations()
            magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
            magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!, this)
            animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false, null)

            vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
@@ -397,7 +401,8 @@ abstract class MagnetizedObject<T : Any>(
            // move the object out of the target using its own movement logic.
            cancelAnimations()
            magnetListener.onUnstuckFromTarget(
                    targetObjectIsStuckTo!!, velocityTracker.xVelocity, velocityTracker.yVelocity,
                    targetObjectIsStuckTo!!, this,
                    velocityTracker.xVelocity, velocityTracker.yVelocity,
                    wasFlungOut = false)
            targetObjectIsStuckTo = null

@@ -420,10 +425,11 @@ abstract class MagnetizedObject<T : Any>(
                    // the upward direction, tell the listener so the object can be animated out of
                    // the target.
                    magnetListener.onUnstuckFromTarget(
                            targetObjectIsStuckTo!!, velX, velY, wasFlungOut = true)
                            targetObjectIsStuckTo!!, this,
                            velX, velY, wasFlungOut = true)
                } else {
                    // If the object is stuck and not flung away, it was released inside the target.
                    magnetListener.onReleasedInTarget(targetObjectIsStuckTo!!)
                    magnetListener.onReleasedInTarget(targetObjectIsStuckTo!!, this)
                    vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
                }

@@ -440,11 +446,11 @@ abstract class MagnetizedObject<T : Any>(
            if (flungToTarget != null) {
                // If this is a fling-to-target, animate the object to the magnet and then release
                // it.
                magnetListener.onStuckToTarget(flungToTarget)
                magnetListener.onStuckToTarget(flungToTarget, this)
                targetObjectIsStuckTo = flungToTarget

                animateStuckToTarget(flungToTarget, velX, velY, true) {
                    magnetListener.onReleasedInTarget(flungToTarget)
                    magnetListener.onReleasedInTarget(flungToTarget, this)
                    targetObjectIsStuckTo = null
                    vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
                }
+5 −2
Original line number Diff line number Diff line
@@ -131,7 +131,8 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
                });
        mMagnetizedPip.setMagnetListener(new MagnetizedObject.MagnetListener() {
            @Override
            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target,
                    @NonNull MagnetizedObject<?> draggedObject) {
                // Show the dismiss target, in case the initial touch event occurred within
                // the magnetic field radius.
                if (mEnableDismissDragToEdge) {
@@ -141,6 +142,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen

            @Override
            public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
                    @NonNull MagnetizedObject<?> draggedObject,
                    float velX, float velY, boolean wasFlungOut) {
                if (wasFlungOut) {
                    mMotionHelper.flingToSnapTarget(velX, velY, null /* endAction */);
@@ -151,7 +153,8 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen
            }

            @Override
            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target,
                    @NonNull MagnetizedObject<?> draggedObject) {
                if (mEnableDismissDragToEdge) {
                    mMainExecutor.executeDelayed(() -> {
                        mMotionHelper.notifyDismissalPending();
+32 −24
Original line number Diff line number Diff line
@@ -201,9 +201,11 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(x = 200, y = 200))

        // You can't become unstuck if you were never stuck in the first place.
        verify(magnetListener, never()).onStuckToTarget(magneticTarget)
        verify(magnetListener, never()).onStuckToTarget(magneticTarget,
                magnetizedObject)
        verify(magnetListener, never()).onUnstuckFromTarget(
                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(magneticTarget), eq(magnetizedObject),
                ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(false))

        // Move into and then around inside the magnetic field.
@@ -213,9 +215,10 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(x = targetCenterX + 100, y = targetCenterY + 100))

        // We should only have received one call to onStuckToTarget and none to unstuck.
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget, magnetizedObject)
        verify(magnetListener, never()).onUnstuckFromTarget(
                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(magneticTarget), eq(magnetizedObject),
                ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(false))

        // Move out of the field and then release.
@@ -226,7 +229,8 @@ class MagnetizedObjectTest : ShellTestCase() {
        // We should have received one unstuck call and no more stuck calls. We also should never
        // have received an onReleasedInTarget call.
        verify(magnetListener, times(1)).onUnstuckFromTarget(
                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(magneticTarget), eq(magnetizedObject),
                ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(false))
        verifyNoMoreInteractions(magnetListener)
    }
@@ -242,8 +246,8 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(
                        x = targetCenterX, y = targetCenterY))

        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
        verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget, magnetizedObject)
        verify(magnetListener, never()).onReleasedInTarget(magneticTarget, magnetizedObject)

        // Move back out.
        dispatchMotionEvents(
@@ -252,9 +256,11 @@ class MagnetizedObjectTest : ShellTestCase() {
                        y = targetCenterY - magneticFieldRadius))

        verify(magnetListener, times(1)).onUnstuckFromTarget(
                eq(magneticTarget), ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(magneticTarget),
                eq(magnetizedObject),
                ArgumentMatchers.anyFloat(), ArgumentMatchers.anyFloat(),
                eq(false))
        verify(magnetListener, never()).onReleasedInTarget(magneticTarget)
        verify(magnetListener, never()).onReleasedInTarget(magneticTarget, magnetizedObject)

        // Move in again and release in the magnetic field.
        dispatchMotionEvents(
@@ -264,8 +270,8 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(
                        x = targetCenterX, y = targetCenterY, action = MotionEvent.ACTION_UP))

        verify(magnetListener, times(2)).onStuckToTarget(magneticTarget)
        verify(magnetListener).onReleasedInTarget(magneticTarget)
        verify(magnetListener, times(2)).onStuckToTarget(magneticTarget, magnetizedObject)
        verify(magnetListener).onReleasedInTarget(magneticTarget, magnetizedObject)
        verifyNoMoreInteractions(magnetListener)
    }

@@ -288,7 +294,7 @@ class MagnetizedObjectTest : ShellTestCase() {
                        action = MotionEvent.ACTION_UP))

        // Nevertheless it should have ended up stuck to the target.
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget, magnetizedObject)
    }

    @Test
@@ -366,7 +372,7 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(x = 100, y = 900))

        // Verify that we received an onStuck for the second target, and no others.
        verify(magnetListener).onStuckToTarget(secondMagneticTarget)
        verify(magnetListener).onStuckToTarget(secondMagneticTarget, magnetizedObject)
        verifyNoMoreInteractions(magnetListener)

        // Drag into the original target.
@@ -376,8 +382,9 @@ class MagnetizedObjectTest : ShellTestCase() {

        // We should have unstuck from the second one and stuck into the original one.
        verify(magnetListener).onUnstuckFromTarget(
                eq(secondMagneticTarget), anyFloat(), anyFloat(), eq(false))
        verify(magnetListener).onStuckToTarget(magneticTarget)
                eq(secondMagneticTarget), eq(magnetizedObject),
                anyFloat(), anyFloat(), eq(false))
        verify(magnetListener).onStuckToTarget(magneticTarget, magnetizedObject)
        verifyNoMoreInteractions(magnetListener)
    }

@@ -394,7 +401,7 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(x = 100, y = 650, action = MotionEvent.ACTION_UP))

        // Verify that we received an onStuck for the second target.
        verify(magnetListener).onStuckToTarget(secondMagneticTarget)
        verify(magnetListener).onStuckToTarget(secondMagneticTarget, magnetizedObject)

        // Fling towards the first target.
        dispatchMotionEvents(
@@ -403,7 +410,7 @@ class MagnetizedObjectTest : ShellTestCase() {
                getMotionEvent(x = 500, y = 650, action = MotionEvent.ACTION_UP))

        // Verify that we received onStuck for the original target.
        verify(magnetListener).onStuckToTarget(magneticTarget)
        verify(magnetListener).onStuckToTarget(magneticTarget, magnetizedObject)
    }

    @Test
@@ -413,10 +420,10 @@ class MagnetizedObjectTest : ShellTestCase() {
        dispatchMotionEvents(getMotionEvent(x = targetCenterX, y = targetCenterY))
        // Moved into the target location, but it should be shifted due to screen offset.
        // Should not get stuck.
        verify(magnetListener, never()).onStuckToTarget(magneticTarget)
        verify(magnetListener, never()).onStuckToTarget(magneticTarget, magnetizedObject)

        dispatchMotionEvents(getMotionEvent(x = targetCenterX, y = targetCenterY + 500))
        verify(magnetListener).onStuckToTarget(magneticTarget)
        verify(magnetListener).onStuckToTarget(magneticTarget, magnetizedObject)

        dispatchMotionEvents(
            getMotionEvent(
@@ -426,7 +433,7 @@ class MagnetizedObjectTest : ShellTestCase() {
            )
        )

        verify(magnetListener).onReleasedInTarget(magneticTarget)
        verify(magnetListener).onReleasedInTarget(magneticTarget, magnetizedObject)
        verifyNoMoreInteractions(magnetListener)
    }

@@ -437,14 +444,15 @@ class MagnetizedObjectTest : ShellTestCase() {

        dispatchMotionEvents(getMotionEvent(x = targetCenterX, y = adjustedTargetCenter))
        dispatchMotionEvents(getMotionEvent(x = 0, y = 0))
        verify(magnetListener).onStuckToTarget(magneticTarget)
        verify(magnetListener).onStuckToTarget(magneticTarget, magnetizedObject)
        verify(magnetListener)
                .onUnstuckFromTarget(eq(magneticTarget), anyFloat(), anyFloat(), anyBoolean())
                .onUnstuckFromTarget(eq(magneticTarget), eq(magnetizedObject),
                        anyFloat(), anyFloat(), anyBoolean())

        // Offset if removed, we should now get stuck at the target location
        magneticTarget.screenVerticalOffset = 0
        dispatchMotionEvents(getMotionEvent(x = targetCenterX, y = targetCenterY))
        verify(magnetListener, times(2)).onStuckToTarget(magneticTarget)
        verify(magnetListener, times(2)).onStuckToTarget(magneticTarget, magnetizedObject)
    }

    @Test
@@ -466,7 +474,7 @@ class MagnetizedObjectTest : ShellTestCase() {
        )

        // Nevertheless it should have ended up stuck to the target.
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget)
        verify(magnetListener, times(1)).onStuckToTarget(magneticTarget, magnetizedObject)
    }

    private fun getSecondMagneticTarget(): MagnetizedObject.MagneticTarget {
Loading