Loading core/java/android/view/MotionPredictor.java 0 → 100644 +116 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.annotation.NonNull; import android.content.Context; import libcore.util.NativeAllocationRegistry; import java.util.Arrays; import java.util.List; /** * Calculates motion predictions. * * Add motions here to get predicted events! * @hide */ // Acts as a pass-through to the native MotionPredictor object. // Do not store any state in this Java layer, or add any business logic here. All of the // implementation details should go into the native MotionPredictor. // The context / resource access must be here rather than in native layer due to the lack of the // corresponding native API surface. public final class MotionPredictor { private static class RegistryHolder { public static final NativeAllocationRegistry REGISTRY = NativeAllocationRegistry.createMalloced( MotionPredictor.class.getClassLoader(), nativeGetNativeMotionPredictorFinalizer()); } // Pointer to the native object. private final long mPtr; private final Context mContext; /** * Create a new MotionPredictor for the provided {@link Context}. * @param context The context for the predictions */ public MotionPredictor(@NonNull Context context) { mContext = context; final int offsetNanos = mContext.getResources().getInteger( com.android.internal.R.integer.config_motionPredictionOffsetNanos); mPtr = nativeInitialize(offsetNanos); RegistryHolder.REGISTRY.registerNativeAllocation(this, mPtr); } /** * Record a movement so that in the future, a prediction for the current gesture can be * generated. Ensure to add all motions from the gesture of interest to generate the correct * prediction. * @param event The received event */ public void record(@NonNull MotionEvent event) { nativeRecord(mPtr, event); } /** * Get predicted events for all gestures that have been provided to the 'record' function. * If events from multiple devices were sent to 'record', this will produce a separate * {@link MotionEvent} for each device id. The returned list may be empty if no predictions for * any of the added events are available. * Predictions may not reach the requested timestamp if the confidence in the prediction results * is low. * * @param predictionTimeNanos The time that the prediction should target, in the * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds. * * @return the list of predicted motion events, for each device id. Ensure to check the * historical data in addition to the latest ({@link MotionEvent#getX getX()}, * {@link MotionEvent#getY getY()}) coordinates for smoothest prediction curves. Empty list is * returned if predictions are not supported, or not possible for the current set of gestures. */ @NonNull public List<MotionEvent> predict(long predictionTimeNanos) { return Arrays.asList(nativePredict(mPtr, predictionTimeNanos)); } /** * Check whether this device supports motion predictions for the given source type. * * @param deviceId The input device id * @param source The source of input events * @return True if the current device supports predictions, false otherwise. */ public boolean isPredictionAvailable(int deviceId, int source) { // Device-specific override if (!mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableMotionPrediction)) { return false; } return nativeIsPredictionAvailable(mPtr, deviceId, source); } private static native long nativeInitialize(int offsetNanos); private static native void nativeRecord(long nativePtr, MotionEvent event); private static native MotionEvent[] nativePredict(long nativePtr, long predictionTimeNanos); private static native boolean nativeIsPredictionAvailable(long nativePtr, int deviceId, int source); private static native long nativeGetNativeMotionPredictorFinalizer(); } core/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ cc_library_shared { "android_view_KeyCharacterMap.cpp", "android_view_KeyEvent.cpp", "android_view_MotionEvent.cpp", "android_view_MotionPredictor.cpp", "android_view_PointerIcon.cpp", "android_view_Surface.cpp", "android_view_SurfaceControl.cpp", Loading Loading @@ -283,6 +284,7 @@ cc_library_shared { "libhwui", "libmediandk", "libpermission", "libPlatformProperties", "libsensor", "libinput", "libcamera_client", Loading core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ extern int register_android_view_InputQueue(JNIEnv* env); extern int register_android_view_KeyCharacterMap(JNIEnv *env); extern int register_android_view_KeyEvent(JNIEnv* env); extern int register_android_view_MotionEvent(JNIEnv* env); extern int register_android_view_MotionPredictor(JNIEnv* env); extern int register_android_view_PointerIcon(JNIEnv* env); extern int register_android_view_VelocityTracker(JNIEnv* env); extern int register_android_view_VerifiedKeyEvent(JNIEnv* env); Loading Loading @@ -1643,6 +1644,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_InputQueue), REG_JNI(register_android_view_KeyEvent), REG_JNI(register_android_view_MotionEvent), REG_JNI(register_android_view_MotionPredictor), REG_JNI(register_android_view_PointerIcon), REG_JNI(register_android_view_VelocityTracker), REG_JNI(register_android_view_VerifiedKeyEvent), Loading core/jni/android_view_InputDevice.cpp +2 −4 Original line number Diff line number Diff line Loading @@ -97,7 +97,6 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi return env->NewLocalRef(inputDeviceObj.get()); } int register_android_view_InputDevice(JNIEnv* env) { gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice"); Loading @@ -108,9 +107,8 @@ int register_android_view_InputDevice(JNIEnv* env) "String;ZIILandroid/view/KeyCharacterMap;Ljava/" "lang/String;Ljava/lang/String;ZZZZZZ)V"); gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); return 0; } Loading core/jni/android_view_MotionEvent.cpp +14 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,20 @@ jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent& ev return eventObj; } jobject android_view_MotionEvent_obtainFromNative(JNIEnv* env, std::unique_ptr<MotionEvent> event) { if (event == nullptr) { return nullptr; } jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz, gMotionEventClassInfo.obtain); if (env->ExceptionCheck() || !eventObj) { LOGE_EX(env); LOG_ALWAYS_FATAL("An exception occurred while obtaining a Java motion event."); } android_view_MotionEvent_setNativePtr(env, eventObj, event.release()); return eventObj; } status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle); if (env->ExceptionCheck()) { Loading Loading
core/java/android/view/MotionPredictor.java 0 → 100644 +116 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.annotation.NonNull; import android.content.Context; import libcore.util.NativeAllocationRegistry; import java.util.Arrays; import java.util.List; /** * Calculates motion predictions. * * Add motions here to get predicted events! * @hide */ // Acts as a pass-through to the native MotionPredictor object. // Do not store any state in this Java layer, or add any business logic here. All of the // implementation details should go into the native MotionPredictor. // The context / resource access must be here rather than in native layer due to the lack of the // corresponding native API surface. public final class MotionPredictor { private static class RegistryHolder { public static final NativeAllocationRegistry REGISTRY = NativeAllocationRegistry.createMalloced( MotionPredictor.class.getClassLoader(), nativeGetNativeMotionPredictorFinalizer()); } // Pointer to the native object. private final long mPtr; private final Context mContext; /** * Create a new MotionPredictor for the provided {@link Context}. * @param context The context for the predictions */ public MotionPredictor(@NonNull Context context) { mContext = context; final int offsetNanos = mContext.getResources().getInteger( com.android.internal.R.integer.config_motionPredictionOffsetNanos); mPtr = nativeInitialize(offsetNanos); RegistryHolder.REGISTRY.registerNativeAllocation(this, mPtr); } /** * Record a movement so that in the future, a prediction for the current gesture can be * generated. Ensure to add all motions from the gesture of interest to generate the correct * prediction. * @param event The received event */ public void record(@NonNull MotionEvent event) { nativeRecord(mPtr, event); } /** * Get predicted events for all gestures that have been provided to the 'record' function. * If events from multiple devices were sent to 'record', this will produce a separate * {@link MotionEvent} for each device id. The returned list may be empty if no predictions for * any of the added events are available. * Predictions may not reach the requested timestamp if the confidence in the prediction results * is low. * * @param predictionTimeNanos The time that the prediction should target, in the * {@link android.os.SystemClock#uptimeMillis} time base, but in nanoseconds. * * @return the list of predicted motion events, for each device id. Ensure to check the * historical data in addition to the latest ({@link MotionEvent#getX getX()}, * {@link MotionEvent#getY getY()}) coordinates for smoothest prediction curves. Empty list is * returned if predictions are not supported, or not possible for the current set of gestures. */ @NonNull public List<MotionEvent> predict(long predictionTimeNanos) { return Arrays.asList(nativePredict(mPtr, predictionTimeNanos)); } /** * Check whether this device supports motion predictions for the given source type. * * @param deviceId The input device id * @param source The source of input events * @return True if the current device supports predictions, false otherwise. */ public boolean isPredictionAvailable(int deviceId, int source) { // Device-specific override if (!mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableMotionPrediction)) { return false; } return nativeIsPredictionAvailable(mPtr, deviceId, source); } private static native long nativeInitialize(int offsetNanos); private static native void nativeRecord(long nativePtr, MotionEvent event); private static native MotionEvent[] nativePredict(long nativePtr, long predictionTimeNanos); private static native boolean nativeIsPredictionAvailable(long nativePtr, int deviceId, int source); private static native long nativeGetNativeMotionPredictorFinalizer(); }
core/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,7 @@ cc_library_shared { "android_view_KeyCharacterMap.cpp", "android_view_KeyEvent.cpp", "android_view_MotionEvent.cpp", "android_view_MotionPredictor.cpp", "android_view_PointerIcon.cpp", "android_view_Surface.cpp", "android_view_SurfaceControl.cpp", Loading Loading @@ -283,6 +284,7 @@ cc_library_shared { "libhwui", "libmediandk", "libpermission", "libPlatformProperties", "libsensor", "libinput", "libcamera_client", Loading
core/jni/AndroidRuntime.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -187,6 +187,7 @@ extern int register_android_view_InputQueue(JNIEnv* env); extern int register_android_view_KeyCharacterMap(JNIEnv *env); extern int register_android_view_KeyEvent(JNIEnv* env); extern int register_android_view_MotionEvent(JNIEnv* env); extern int register_android_view_MotionPredictor(JNIEnv* env); extern int register_android_view_PointerIcon(JNIEnv* env); extern int register_android_view_VelocityTracker(JNIEnv* env); extern int register_android_view_VerifiedKeyEvent(JNIEnv* env); Loading Loading @@ -1643,6 +1644,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_view_InputQueue), REG_JNI(register_android_view_KeyEvent), REG_JNI(register_android_view_MotionEvent), REG_JNI(register_android_view_MotionPredictor), REG_JNI(register_android_view_PointerIcon), REG_JNI(register_android_view_VelocityTracker), REG_JNI(register_android_view_VerifiedKeyEvent), Loading
core/jni/android_view_InputDevice.cpp +2 −4 Original line number Diff line number Diff line Loading @@ -97,7 +97,6 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi return env->NewLocalRef(inputDeviceObj.get()); } int register_android_view_InputDevice(JNIEnv* env) { gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice"); Loading @@ -108,9 +107,8 @@ int register_android_view_InputDevice(JNIEnv* env) "String;ZIILandroid/view/KeyCharacterMap;Ljava/" "lang/String;Ljava/lang/String;ZZZZZZ)V"); gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); return 0; } Loading
core/jni/android_view_MotionEvent.cpp +14 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,20 @@ jobject android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent& ev return eventObj; } jobject android_view_MotionEvent_obtainFromNative(JNIEnv* env, std::unique_ptr<MotionEvent> event) { if (event == nullptr) { return nullptr; } jobject eventObj = env->CallStaticObjectMethod(gMotionEventClassInfo.clazz, gMotionEventClassInfo.obtain); if (env->ExceptionCheck() || !eventObj) { LOGE_EX(env); LOG_ALWAYS_FATAL("An exception occurred while obtaining a Java motion event."); } android_view_MotionEvent_setNativePtr(env, eventObj, event.release()); return eventObj; } status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) { env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle); if (env->ExceptionCheck()) { Loading