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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user