diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 31ca8e124f9e7..c23678a0b0681 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1569,6 +1569,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { int axis, int pointerIndex, int historyPos); @FastNative private static native void nativeTransform(long nativePtr, Matrix matrix); + @FastNative + private static native void nativeApplyTransform(long nativePtr, Matrix matrix); // -------------- @CriticalNative ---------------------- @@ -3265,6 +3267,21 @@ public final class MotionEvent extends InputEvent implements Parcelable { nativeTransform(mNativePtr, matrix); } + /** + * Transforms all of the points in the event directly instead of modifying the event's + * internal transform. + * + * @param matrix The transformation matrix to apply. + * @hide + */ + public void applyTransform(Matrix matrix) { + if (matrix == null) { + throw new IllegalArgumentException("matrix must not be null"); + } + + nativeApplyTransform(mNativePtr, matrix); + } + /** * Add a new movement to the batch of movements in this event. The event's * current location, position and size is updated to the new values. diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 5acbd98822e16..6971301cec32d 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -578,6 +578,15 @@ static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz, event->transform(matrix); } +static void android_view_MotionEvent_nativeApplyTransform(JNIEnv* env, jclass clazz, + jlong nativePtr, jobject matrixObj) { + MotionEvent* event = reinterpret_cast(nativePtr); + + std::array matrix; + AMatrix_getContents(env, matrixObj, matrix.data()); + event->applyTransform(matrix); +} + // ----------------- @CriticalNative ------------------------------ static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sourceNativePtr, @@ -790,6 +799,8 @@ static const JNINativeMethod gMotionEventMethods[] = { {"nativeGetAxisValue", "(JIII)F", (void*)android_view_MotionEvent_nativeGetAxisValue}, {"nativeTransform", "(JLandroid/graphics/Matrix;)V", (void*)android_view_MotionEvent_nativeTransform}, + {"nativeApplyTransform", "(JLandroid/graphics/Matrix;)V", + (void*)android_view_MotionEvent_nativeApplyTransform}, // --------------- @CriticalNative ------------------ diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index c51571a20bb1f..1c27c6539b17b 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -16,6 +16,8 @@ package com.android.server.input; +import static android.view.Surface.ROTATION_0; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; @@ -38,6 +40,7 @@ import android.content.res.Resources.NotFoundException; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.database.ContentObserver; +import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayViewport; @@ -97,6 +100,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputMonitor; import android.view.KeyEvent; +import android.view.MotionEvent; import android.view.PointerIcon; import android.view.Surface; import android.view.VerifiedInputEvent; @@ -820,6 +824,28 @@ public class InputManagerService extends IInputManager.Stub && mode != InputEventInjectionSync.WAIT_FOR_RESULT) { throw new IllegalArgumentException("mode is invalid"); } + if (ENABLE_PER_WINDOW_INPUT_ROTATION) { + if (event instanceof MotionEvent) { + final Context dispCtx = getContextForDisplay(event.getDisplayId()); + final Display display = dispCtx.getDisplay(); + final int rotation = display.getRotation(); + if (rotation != ROTATION_0) { + final MotionEvent motion = (MotionEvent) event; + // Injections are currently expected to be in the space of the injector (ie. + // usually assumed to be post-rotated). Thus we need to unrotate into raw + // input coordinates for dispatch. + final Point sz = new Point(); + display.getRealSize(sz); + if ((rotation % 2) != 0) { + final int tmpX = sz.x; + sz.x = sz.y; + sz.y = tmpX; + } + motion.applyTransform(MotionEvent.createRotateMatrix( + (4 - rotation), sz.x, sz.y)); + } + } + } final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid();