Merge "Don't rotate inputflinger's display" into sc-dev

This commit is contained in:
Evan Rosky
2021-02-20 01:46:25 +00:00
committed by Android (Google) Code Review
8 changed files with 169 additions and 9 deletions

View File

@@ -3768,6 +3768,41 @@ public final class MotionEvent extends InputEvent implements Parcelable {
return (getButtonState() & button) == button;
}
/**
* Gets a rotation matrix that (when applied to a motionevent) will rotate that motion event
* such that the result coordinates end up in the same physical location on a display whose
* coordinates are rotated by `rotation`.
*
* For example, rotating 0,0 by 90 degrees will move a point from the physical top-left to
* the bottom-left of the 90-degree-rotated display.
*
* @hide
*/
public static Matrix createRotateMatrix(
@Surface.Rotation int rotation, int displayW, int displayH) {
if (rotation == Surface.ROTATION_0) {
return new Matrix(Matrix.IDENTITY_MATRIX);
}
// values is row-major
float[] values = null;
if (rotation == Surface.ROTATION_90) {
values = new float[]{0, 1, 0,
-1, 0, displayH,
0, 0, 1};
} else if (rotation == Surface.ROTATION_180) {
values = new float[]{-1, 0, displayW,
0, -1, displayH,
0, 0, 1};
} else if (rotation == Surface.ROTATION_270) {
values = new float[]{0, -1, displayW,
1, 0, 0,
0, 0, 1};
}
Matrix toOrient = new Matrix();
toOrient.setValues(values);
return toOrient;
}
public static final @android.annotation.NonNull Parcelable.Creator<MotionEvent> CREATOR
= new Parcelable.Creator<MotionEvent>() {
public MotionEvent createFromParcel(Parcel in) {

View File

@@ -36,6 +36,7 @@ import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
@@ -59,6 +60,9 @@ public class PointerLocationView extends View implements InputDeviceListener,
*/
private static final String GESTURE_EXCLUSION_PROP = "debug.pointerlocation.showexclusion";
private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
public static class PointerState {
// Trace of previous points.
private float[] mTraceX = new float[32];
@@ -352,6 +356,21 @@ public class PointerLocationView extends View implements InputDeviceListener,
.toString(), 1 + itemW * 6, base, mTextPaint);
}
int saveId = canvas.save();
if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
// Rotate negative (since we're rotating the drawing canvas vs the output).
canvas.rotate(-90.0f * mContext.getDisplay().getRotation());
switch (mContext.getDisplay().getRotation()) {
case Surface.ROTATION_90:
canvas.translate(-canvas.getHeight(), 0);
break;
case Surface.ROTATION_180:
canvas.translate(-canvas.getWidth(), -canvas.getHeight());
break;
case Surface.ROTATION_270:
canvas.translate(0, -canvas.getWidth());
}
}
// Pointer trace.
for (int p = 0; p < NP; p++) {
final PointerState ps = mPointers.get(p);
@@ -399,7 +418,10 @@ public class PointerLocationView extends View implements InputDeviceListener,
if (mCurDown && ps.mCurDown) {
// Draw crosshairs.
canvas.drawLine(0, ps.mCoords.y, getWidth(), ps.mCoords.y, mTargetPaint);
canvas.drawLine(ps.mCoords.x, 0, ps.mCoords.x, getHeight(), mTargetPaint);
// Extend crosshairs to cover screen regardless of rotation (ie. since the rotated
// canvas can "expose" content past 0 and up-to the largest screen dimension).
canvas.drawLine(ps.mCoords.x, -getHeight(), ps.mCoords.x,
Math.max(getHeight(), getWidth()), mTargetPaint);
// Draw current point.
int pressureLevel = (int)(ps.mCoords.pressure * 255);
@@ -458,6 +480,7 @@ public class PointerLocationView extends View implements InputDeviceListener,
}
}
}
canvas.restoreToCount(saveId);
}
private void logMotionEvent(String type, MotionEvent event) {

View File

@@ -169,4 +169,24 @@ public class MotionEventTest {
assertEquals(0x3 << 30, ID_SOURCE_MASK & event.getId());
}
}
@Test
public void testEventRotation() {
final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
MotionEvent rot90 = MotionEvent.obtain(event);
rot90.transform(MotionEvent.createRotateMatrix(/* 90 deg */1, 1000, 600));
assertEquals(50, (int) rot90.getX());
assertEquals(570, (int) rot90.getY());
MotionEvent rot180 = MotionEvent.obtain(event);
rot180.transform(MotionEvent.createRotateMatrix(/* 180 deg */2, 1000, 600));
assertEquals(970, (int) rot180.getX());
assertEquals(550, (int) rot180.getY());
MotionEvent rot270 = MotionEvent.obtain(event);
rot270.transform(MotionEvent.createRotateMatrix(/* 270 deg */3, 1000, 600));
assertEquals(950, (int) rot270.getX());
assertEquals(30, (int) rot270.getY());
}
}

View File

@@ -16,13 +16,12 @@
package com.android.systemui.shared.system;
import android.os.Bundle;
import android.graphics.Matrix;
import android.os.Looper;
import android.view.BatchedInputEventReceiver;
import android.view.Choreographer;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventSender;
import android.view.MotionEvent;
/**
@@ -53,6 +52,12 @@ public class InputChannelCompat {
return target.addBatch(src);
}
/** @see MotionEvent#createRotateMatrix */
public static Matrix createRotationMatrix(
/*@Surface.Rotation*/ int rotation, int displayW, int displayH) {
return MotionEvent.createRotateMatrix(rotation, displayW, displayH);
}
/**
* @see BatchedInputEventReceiver
*/

View File

@@ -38,6 +38,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Choreographer;
import android.view.Display;
import android.view.ISystemGestureExclusionListener;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -96,6 +97,9 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
static final boolean DEBUG_MISSING_GESTURE = true;
static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
private ISystemGestureExclusionListener mGestureExclusionListener =
new ISystemGestureExclusionListener.Stub() {
@Override
@@ -505,9 +509,19 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
}
private void onInputEvent(InputEvent ev) {
if (ev instanceof MotionEvent) {
onMotionEvent((MotionEvent) ev);
if (!(ev instanceof MotionEvent)) return;
MotionEvent event = (MotionEvent) ev;
if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
final Display display = mContext.getDisplay();
int rotation = display.getRotation();
if (rotation != Surface.ROTATION_0) {
Point sz = new Point();
display.getRealSize(sz);
event = MotionEvent.obtain(event);
event.transform(MotionEvent.createRotateMatrix(rotation, sz.x, sz.y));
}
}
onMotionEvent(event);
}
private void updateMLModelState() {

View File

@@ -37,6 +37,7 @@ import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayViewport;
import android.hardware.input.IInputDevicesChangedListener;
@@ -69,6 +70,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.provider.DeviceConfig;
@@ -168,6 +170,9 @@ public class InputManagerService extends IInputManager.Stub
/** TODO(b/169067926): Remove this. */
private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
public static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
// Pointer to native input manager service object.
private final long mPtr;
@@ -518,8 +523,51 @@ public class InputManagerService extends IInputManager.Stub
nativeReloadDeviceAliases(mPtr);
}
/** Rotates CCW by `delta` 90-degree increments. */
private static void rotateBounds(Rect inOutBounds, int parentW, int parentH, int delta) {
int rdelta = ((delta % 4) + 4) % 4;
int origLeft = inOutBounds.left;
switch (rdelta) {
case 0:
return;
case 1:
inOutBounds.left = inOutBounds.top;
inOutBounds.top = parentW - inOutBounds.right;
inOutBounds.right = inOutBounds.bottom;
inOutBounds.bottom = parentW - origLeft;
return;
case 2:
inOutBounds.left = parentW - inOutBounds.right;
inOutBounds.right = parentW - origLeft;
return;
case 3:
inOutBounds.left = parentH - inOutBounds.bottom;
inOutBounds.bottom = inOutBounds.right;
inOutBounds.right = parentH - inOutBounds.top;
inOutBounds.top = origLeft;
return;
}
}
private void setDisplayViewportsInternal(List<DisplayViewport> viewports) {
nativeSetDisplayViewports(mPtr, viewports.toArray(new DisplayViewport[0]));
final DisplayViewport[] vArray = new DisplayViewport[viewports.size()];
if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
// Remove all viewport operations. They will be built-into the window transforms.
for (int i = viewports.size() - 1; i >= 0; --i) {
final DisplayViewport v = vArray[i] = viewports.get(i).makeCopy();
// deviceWidth/Height are apparently in "rotated" space, so flip them if needed.
int dw = (v.orientation % 2) == 0 ? v.deviceWidth : v.deviceHeight;
int dh = (v.orientation % 2) == 0 ? v.deviceHeight : v.deviceWidth;
v.logicalFrame.set(0, 0, dw, dh);
v.physicalFrame.set(0, 0, dw, dh);
v.orientation = 0;
}
} else {
for (int i = viewports.size() - 1; i >= 0; --i) {
vArray[i] = viewports.get(i);
}
}
nativeSetDisplayViewports(mPtr, vArray);
}
/**

View File

@@ -1002,7 +1002,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
"PointerEventDispatcher" + mDisplayId, mDisplayId);
mPointerEventDispatcher = new PointerEventDispatcher(inputChannel);
mPointerEventDispatcher = new PointerEventDispatcher(inputChannel, this);
// Tap Listeners are supported for:
// 1. All physical displays (multi-display).

View File

@@ -16,11 +16,14 @@
package com.android.server.wm;
import static com.android.server.input.InputManagerService.ENABLE_PER_WINDOW_INPUT_ROTATION;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.server.UiThread;
@@ -31,8 +34,11 @@ public class PointerEventDispatcher extends InputEventReceiver {
private final ArrayList<PointerEventListener> mListeners = new ArrayList<>();
private PointerEventListener[] mListenersArray = new PointerEventListener[0];
public PointerEventDispatcher(InputChannel inputChannel) {
private final DisplayContent mDisplayContent;
public PointerEventDispatcher(InputChannel inputChannel, DisplayContent dc) {
super(inputChannel, UiThread.getHandler().getLooper());
mDisplayContent = dc;
}
@Override
@@ -40,7 +46,16 @@ public class PointerEventDispatcher extends InputEventReceiver {
try {
if (event instanceof MotionEvent
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
final MotionEvent motionEvent = (MotionEvent) event;
MotionEvent motionEvent = (MotionEvent) event;
if (ENABLE_PER_WINDOW_INPUT_ROTATION) {
int rotation = mDisplayContent.getRotation();
if (rotation != Surface.ROTATION_0) {
motionEvent = MotionEvent.obtain(motionEvent);
motionEvent.transform(MotionEvent.createRotateMatrix(rotation,
mDisplayContent.getDisplayMetrics().widthPixels,
mDisplayContent.getDisplayMetrics().heightPixels));
}
}
PointerEventListener[] listeners;
synchronized (mListeners) {
if (mListenersArray == null) {