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

Commit cbc84d96 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Avoid changing transform when touching in progress

After swiping from a landscape app to portrait home, the touch
orientation may be changed if there the touch event comes in a
short time (e.g. click app icon immediately):
 DOWN
 MOVE...
 SimpleOrientationTouchTransformer#onDisplayInfoChanged
 MOVE... (start to transform with inconsistent orientation)
 UP

That could disturb the gesture detection:
OverviewInputConsumer#onMotionEvent
 > BaseDragLayer#proxyTouchEvent
  onInterceptTouchEvent, findControllerToHandleTouch
  > PortraitStatesTouchController#onControllerInterceptTouchEvent
   > BaseSwipeDetector#onTouchEvent
which may show the app drawer unexpectedly.

http://recall/-/b2qm27pJZxFIWQccA9qE9Q/ggLXlE5kf7AWMOjUc0FCUU

Bug: 351755391
Flag: EXEMPT bugfix
Test: atest NexusLauncherTests: \
            com.android.quickstep.OrientationTouchTransformerTest# \
            testSimpleOrientationTouchTransformer
Change-Id: Ic0e9d8292606837feb4775663abb60229c90e9c5
parent 103191c5
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -67,13 +67,15 @@ public class OrientationRectF extends RectF {
    }

    public boolean applyTransform(MotionEvent event, int deltaRotation, boolean forceTransform) {
        if (deltaRotation == 0) {
            return contains(event.getX(), event.getY());
        }
        mTmpMatrix.reset();
        postDisplayRotation(deltaRotation, mHeight, mWidth, mTmpMatrix);
        if (forceTransform) {
            if (DEBUG) {
                Log.d(TAG, "Transforming rotation due to forceTransform, "
                        + "deltaRotation: " + deltaRotation
                        + "mRotation: " + mRotation
                        + " this: " + this);
            }
            event.applyTransform(mTmpMatrix);
+31 −3
Original line number Diff line number Diff line
@@ -34,12 +34,18 @@ public class SimpleOrientationTouchTransformer implements

    private final Context mContext;
    private OrientationRectF mOrientationRectF;
    private OrientationRectF mTouchingOrientationRectF;
    private int mViewRotation;

    public SimpleOrientationTouchTransformer(Context context) {
        this(context, DisplayController.INSTANCE.get(context));
    }

    @androidx.annotation.VisibleForTesting
    public SimpleOrientationTouchTransformer(Context context, DisplayController displayController) {
        mContext = context;
        DisplayController.INSTANCE.get(context).addChangeListener(this);
        onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
                CHANGE_ALL);
        displayController.addChangeListener(this);
        onDisplayInfoChanged(context, displayController.getInfo(), CHANGE_ALL);
    }

    @Override
@@ -56,7 +62,29 @@ public class SimpleOrientationTouchTransformer implements
                info.rotation);
    }

    /**
     * Called when the touch is started. This preserves the touching orientation until the touch is
     * done (i.e. ACTION_CANCEL or ACTION_UP). So the transform won't produce inconsistent position
     * if display is changed during the touch.
     */
    public void updateTouchingOrientation(int viewRotation) {
        mViewRotation = viewRotation;
        mTouchingOrientationRectF = new OrientationRectF(mOrientationRectF.left,
                mOrientationRectF.top, mOrientationRectF.right, mOrientationRectF.bottom,
                mOrientationRectF.getRotation());
    }

    /** Called when the touch is finished. */
    public void clearTouchingOrientation() {
        mTouchingOrientationRectF = null;
    }

    public void transform(MotionEvent ev, int rotation) {
        if (mTouchingOrientationRectF != null) {
            mTouchingOrientationRectF.applyTransformToRotation(ev, mViewRotation,
                    true /* forceTransform */);
            return;
        }
        mOrientationRectF.applyTransformToRotation(ev, rotation, true /* forceTransform */);
    }
}
+11 −2
Original line number Diff line number Diff line
@@ -108,19 +108,28 @@ public class InputConsumerProxy {
            return false;
        }

        final SimpleOrientationTouchTransformer touchTransformer =
                SimpleOrientationTouchTransformer.INSTANCE.get(mContext);
        final int viewRotation = mRotationSupplier.get();
        final boolean needTransform = viewRotation != ev.getSurfaceRotation();
        if (action == ACTION_DOWN) {
            mTouchInProgress = true;
            if (needTransform) {
                touchTransformer.updateTouchingOrientation(viewRotation);
            }
            initInputConsumerIfNeeded(/* isFromTouchDown= */ true);
        } else if (action == ACTION_CANCEL || action == ACTION_UP) {
            // Finish any pending actions
            mTouchInProgress = false;
            touchTransformer.clearTouchingOrientation();
            if (mDestroyPending) {
                destroy();
            }
        }
        if (mInputConsumer != null) {
            SimpleOrientationTouchTransformer.INSTANCE.get(mContext).transform(ev,
                    mRotationSupplier.get());
            if (needTransform) {
                touchTransformer.transform(ev, viewRotation);
            }
            mInputConsumer.onMotionEvent(ev);
        }

+29 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext;

import static com.android.launcher3.util.NavigationMode.NO_BUTTON;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -288,6 +289,34 @@ public class OrientationTouchTransformerTest {
        assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
    }

    @Test
    public void testSimpleOrientationTouchTransformer() {
        final DisplayController displayController = mock(DisplayController.class);
        doReturn(mInfo).when(displayController).getInfo();
        final SimpleOrientationTouchTransformer transformer =
                new SimpleOrientationTouchTransformer(getApplicationContext(), displayController);
        final MotionEvent move1 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
        transformer.transform(move1, Surface.ROTATION_90);
        // The position is transformed to 90 degree.
        assertEquals(10, move1.getX(), 0f /* delta */);
        assertEquals(NORMAL_SCREEN_SIZE.getWidth() - 100, move1.getY(), 0f /* delta */);

        // If the touching state is specified, the position is still transformed to 90 degree even
        // if the given rotation is changed.
        final MotionEvent move2 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
        transformer.updateTouchingOrientation(Surface.ROTATION_90);
        transformer.transform(move2, Surface.ROTATION_0);
        assertEquals(move1.getX(), move2.getX(), 0f /* delta */);
        assertEquals(move1.getY(), move2.getY(), 0f /* delta */);

        // If the touching state is cleared, it restores to use the given rotation.
        final MotionEvent move3 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
        transformer.clearTouchingOrientation();
        transformer.transform(move3, Surface.ROTATION_0);
        assertEquals(100, move3.getX(), 0f /* delta */);
        assertEquals(10, move3.getY(), 0f /* delta */);
    }

    private DisplayController.Info createDisplayInfo(Size screenSize, int rotation) {
        Point displaySize = new Point(screenSize.getWidth(), screenSize.getHeight());
        RotationUtils.rotateSize(displaySize, rotation);