Loading core/java/android/view/KeyCharacterMap.java +29 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.input.InputManager; import android.os.Build; Loading @@ -25,6 +26,8 @@ import android.text.method.MetaKeyKeyListener; import android.util.AndroidRuntimeException; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import java.text.Normalizer; /** Loading Loading @@ -297,6 +300,8 @@ public class KeyCharacterMap implements Parcelable { private static native char nativeGetDisplayLabel(long ptr, int keyCode); private static native int nativeGetKeyboardType(long ptr); private static native KeyEvent[] nativeGetEvents(long ptr, char[] chars); private static native KeyCharacterMap nativeObtainEmptyKeyCharacterMap(int deviceId); private static native boolean nativeEquals(long ptr1, long ptr2); private KeyCharacterMap(Parcel in) { if (in == null) { Loading @@ -322,6 +327,18 @@ public class KeyCharacterMap implements Parcelable { } } /** * Obtain empty key character map * @param deviceId The input device ID * @return The KeyCharacterMap object * @hide */ @VisibleForTesting @Nullable public static KeyCharacterMap obtainEmptyMap(int deviceId) { return nativeObtainEmptyKeyCharacterMap(deviceId); } /** * Loads the key character maps for the keyboard with the specified device id. * Loading Loading @@ -729,6 +746,18 @@ public class KeyCharacterMap implements Parcelable { return 0; } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof KeyCharacterMap)) { return false; } KeyCharacterMap peer = (KeyCharacterMap) obj; if (mPtr == 0 || peer.mPtr == 0) { return mPtr == peer.mPtr; } return nativeEquals(mPtr, peer.mPtr); } /** * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded. */ Loading core/jni/android_view_KeyCharacterMap.cpp +32 −23 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ #include <android_runtime/AndroidRuntime.h> #include <input/KeyCharacterMap.h> #include <input/Input.h> #include <binder/Parcel.h> #include <input/Input.h> #include <input/InputDevice.h> #include <input/KeyCharacterMap.h> #include <jni.h> #include <nativehelper/JNIHelp.h> Loading Loading @@ -75,6 +76,10 @@ jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, reinterpret_cast<jlong>(nativeMap)); } static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) { return android_view_KeyCharacterMap_create(env, deviceId, nullptr); } static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (!parcel) { Loading Loading @@ -224,6 +229,16 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, return result; } static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) { const std::shared_ptr<KeyCharacterMap>& map1 = (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap(); const std::shared_ptr<KeyCharacterMap>& map2 = (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap(); if (map1 == nullptr || map2 == nullptr) { return map1 == map2; } return static_cast<jboolean>(*map1 == *map2); } /* * JNI registration. Loading @@ -231,26 +246,20 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, static const JNINativeMethod g_methods[] = { /* name, signature, funcPtr */ { "nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel }, { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel }, { "nativeDispose", "(J)V", (void*)nativeDispose }, { "nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter }, {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel}, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, {"nativeDispose", "(J)V", (void*)nativeDispose}, {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter}, {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", (void*)nativeGetFallbackAction}, { "nativeGetNumber", "(JI)C", (void*)nativeGetNumber }, { "nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch }, { "nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel }, { "nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType }, { "nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents }, {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber}, {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch}, {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel}, {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType}, {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents}, {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;", (void*)nativeObtainEmptyKeyCharacterMap}, {"nativeEquals", "(JJ)Z", (void*)nativeEquals}, }; int register_android_view_KeyCharacterMap(JNIEnv* env) Loading tests/Input/Android.bp +9 −6 Original line number Diff line number Diff line Loading @@ -9,7 +9,10 @@ package { android_test { name: "InputTests", srcs: ["src/**/*.kt"], srcs: [ "src/**/*.java", "src/**/*.kt", ], platform_apis: true, certificate: "platform", static_libs: [ Loading tests/Input/src/com/android/test/input/InputDeviceTest.java 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.os.Parcel; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class InputDeviceTest { private static final float DELTA = 0.01f; private static final int DEVICE_ID = 1000; private void assertMotionRangeEquals(InputDevice.MotionRange range, InputDevice.MotionRange outRange) { assertEquals(range.getAxis(), outRange.getAxis()); assertEquals(range.getSource(), outRange.getSource()); assertEquals(range.getMin(), outRange.getMin(), DELTA); assertEquals(range.getMax(), outRange.getMax(), DELTA); assertEquals(range.getFlat(), outRange.getFlat(), DELTA); assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA); assertEquals(range.getResolution(), outRange.getResolution(), DELTA); } private void assertDeviceEquals(InputDevice device, InputDevice outDevice) { assertEquals(device.getId(), outDevice.getId()); assertEquals(device.getGeneration(), outDevice.getGeneration()); assertEquals(device.getControllerNumber(), outDevice.getControllerNumber()); assertEquals(device.getName(), outDevice.getName()); assertEquals(device.getVendorId(), outDevice.getVendorId()); assertEquals(device.getProductId(), outDevice.getProductId()); assertEquals(device.getDescriptor(), outDevice.getDescriptor()); assertEquals(device.isExternal(), outDevice.isExternal()); assertEquals(device.getSources(), outDevice.getSources()); assertEquals(device.getKeyboardType(), outDevice.getKeyboardType()); assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size()); KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap(); KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap(); assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap)); for (int j = 0; j < device.getMotionRanges().size(); j++) { assertMotionRangeEquals(device.getMotionRanges().get(j), outDevice.getMotionRanges().get(j)); } } private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) { final InputDevice device = new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name", 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, 0 /* sources */, 0 /* keyboardType */, keyCharacterMap, false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, true /* hasSensor */, false /* hasBattery */); Parcel parcel = Parcel.obtain(); device.writeToParcel(parcel, 0); parcel.setDataPosition(0); InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel); assertDeviceEquals(device, outDevice); } @Test public void testParcelUnparcelInputDevice_VirtualCharacterMap() { final KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); assertInputDeviceParcelUnparcel(keyCharacterMap); } @Test public void testParcelUnparcelInputDevice_EmptyCharacterMap() { final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID); assertInputDeviceParcelUnparcel(keyCharacterMap); } } Loading
core/java/android/view/KeyCharacterMap.java +29 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.input.InputManager; import android.os.Build; Loading @@ -25,6 +26,8 @@ import android.text.method.MetaKeyKeyListener; import android.util.AndroidRuntimeException; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import java.text.Normalizer; /** Loading Loading @@ -297,6 +300,8 @@ public class KeyCharacterMap implements Parcelable { private static native char nativeGetDisplayLabel(long ptr, int keyCode); private static native int nativeGetKeyboardType(long ptr); private static native KeyEvent[] nativeGetEvents(long ptr, char[] chars); private static native KeyCharacterMap nativeObtainEmptyKeyCharacterMap(int deviceId); private static native boolean nativeEquals(long ptr1, long ptr2); private KeyCharacterMap(Parcel in) { if (in == null) { Loading @@ -322,6 +327,18 @@ public class KeyCharacterMap implements Parcelable { } } /** * Obtain empty key character map * @param deviceId The input device ID * @return The KeyCharacterMap object * @hide */ @VisibleForTesting @Nullable public static KeyCharacterMap obtainEmptyMap(int deviceId) { return nativeObtainEmptyKeyCharacterMap(deviceId); } /** * Loads the key character maps for the keyboard with the specified device id. * Loading Loading @@ -729,6 +746,18 @@ public class KeyCharacterMap implements Parcelable { return 0; } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof KeyCharacterMap)) { return false; } KeyCharacterMap peer = (KeyCharacterMap) obj; if (mPtr == 0 || peer.mPtr == 0) { return mPtr == peer.mPtr; } return nativeEquals(mPtr, peer.mPtr); } /** * Thrown by {@link KeyCharacterMap#load} when a key character map could not be loaded. */ Loading
core/jni/android_view_KeyCharacterMap.cpp +32 −23 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ #include <android_runtime/AndroidRuntime.h> #include <input/KeyCharacterMap.h> #include <input/Input.h> #include <binder/Parcel.h> #include <input/Input.h> #include <input/InputDevice.h> #include <input/KeyCharacterMap.h> #include <jni.h> #include <nativehelper/JNIHelp.h> Loading Loading @@ -75,6 +76,10 @@ jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, reinterpret_cast<jlong>(nativeMap)); } static jobject nativeObtainEmptyKeyCharacterMap(JNIEnv* env, jobject /* clazz */, jint deviceId) { return android_view_KeyCharacterMap_create(env, deviceId, nullptr); } static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); if (!parcel) { Loading Loading @@ -224,6 +229,16 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, return result; } static jboolean nativeEquals(JNIEnv* env, jobject clazz, jlong ptr1, jlong ptr2) { const std::shared_ptr<KeyCharacterMap>& map1 = (reinterpret_cast<NativeKeyCharacterMap*>(ptr1))->getMap(); const std::shared_ptr<KeyCharacterMap>& map2 = (reinterpret_cast<NativeKeyCharacterMap*>(ptr2))->getMap(); if (map1 == nullptr || map2 == nullptr) { return map1 == map2; } return static_cast<jboolean>(*map1 == *map2); } /* * JNI registration. Loading @@ -231,26 +246,20 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr, static const JNINativeMethod g_methods[] = { /* name, signature, funcPtr */ { "nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel }, { "nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel }, { "nativeDispose", "(J)V", (void*)nativeDispose }, { "nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter }, {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", (void*)nativeReadFromParcel}, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, {"nativeDispose", "(J)V", (void*)nativeDispose}, {"nativeGetCharacter", "(JII)C", (void*)nativeGetCharacter}, {"nativeGetFallbackAction", "(JIILandroid/view/KeyCharacterMap$FallbackAction;)Z", (void*)nativeGetFallbackAction}, { "nativeGetNumber", "(JI)C", (void*)nativeGetNumber }, { "nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch }, { "nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel }, { "nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType }, { "nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents }, {"nativeGetNumber", "(JI)C", (void*)nativeGetNumber}, {"nativeGetMatch", "(JI[CI)C", (void*)nativeGetMatch}, {"nativeGetDisplayLabel", "(JI)C", (void*)nativeGetDisplayLabel}, {"nativeGetKeyboardType", "(J)I", (void*)nativeGetKeyboardType}, {"nativeGetEvents", "(J[C)[Landroid/view/KeyEvent;", (void*)nativeGetEvents}, {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;", (void*)nativeObtainEmptyKeyCharacterMap}, {"nativeEquals", "(JJ)Z", (void*)nativeEquals}, }; int register_android_view_KeyCharacterMap(JNIEnv* env) Loading
tests/Input/Android.bp +9 −6 Original line number Diff line number Diff line Loading @@ -9,7 +9,10 @@ package { android_test { name: "InputTests", srcs: ["src/**/*.kt"], srcs: [ "src/**/*.java", "src/**/*.kt", ], platform_apis: true, certificate: "platform", static_libs: [ Loading
tests/Input/src/com/android/test/input/InputDeviceTest.java 0 → 100644 +98 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.os.Parcel; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class InputDeviceTest { private static final float DELTA = 0.01f; private static final int DEVICE_ID = 1000; private void assertMotionRangeEquals(InputDevice.MotionRange range, InputDevice.MotionRange outRange) { assertEquals(range.getAxis(), outRange.getAxis()); assertEquals(range.getSource(), outRange.getSource()); assertEquals(range.getMin(), outRange.getMin(), DELTA); assertEquals(range.getMax(), outRange.getMax(), DELTA); assertEquals(range.getFlat(), outRange.getFlat(), DELTA); assertEquals(range.getFuzz(), outRange.getFuzz(), DELTA); assertEquals(range.getResolution(), outRange.getResolution(), DELTA); } private void assertDeviceEquals(InputDevice device, InputDevice outDevice) { assertEquals(device.getId(), outDevice.getId()); assertEquals(device.getGeneration(), outDevice.getGeneration()); assertEquals(device.getControllerNumber(), outDevice.getControllerNumber()); assertEquals(device.getName(), outDevice.getName()); assertEquals(device.getVendorId(), outDevice.getVendorId()); assertEquals(device.getProductId(), outDevice.getProductId()); assertEquals(device.getDescriptor(), outDevice.getDescriptor()); assertEquals(device.isExternal(), outDevice.isExternal()); assertEquals(device.getSources(), outDevice.getSources()); assertEquals(device.getKeyboardType(), outDevice.getKeyboardType()); assertEquals(device.getMotionRanges().size(), outDevice.getMotionRanges().size()); KeyCharacterMap keyCharacterMap = device.getKeyCharacterMap(); KeyCharacterMap outKeyCharacterMap = outDevice.getKeyCharacterMap(); assertTrue("keyCharacterMap not equal", keyCharacterMap.equals(outKeyCharacterMap)); for (int j = 0; j < device.getMotionRanges().size(); j++) { assertMotionRangeEquals(device.getMotionRanges().get(j), outDevice.getMotionRanges().get(j)); } } private void assertInputDeviceParcelUnparcel(KeyCharacterMap keyCharacterMap) { final InputDevice device = new InputDevice(DEVICE_ID, 0 /* generation */, 0 /* controllerNumber */, "name", 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, 0 /* sources */, 0 /* keyboardType */, keyCharacterMap, false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, true /* hasSensor */, false /* hasBattery */); Parcel parcel = Parcel.obtain(); device.writeToParcel(parcel, 0); parcel.setDataPosition(0); InputDevice outDevice = InputDevice.CREATOR.createFromParcel(parcel); assertDeviceEquals(device, outDevice); } @Test public void testParcelUnparcelInputDevice_VirtualCharacterMap() { final KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); assertInputDeviceParcelUnparcel(keyCharacterMap); } @Test public void testParcelUnparcelInputDevice_EmptyCharacterMap() { final KeyCharacterMap keyCharacterMap = KeyCharacterMap.obtainEmptyMap(DEVICE_ID); assertInputDeviceParcelUnparcel(keyCharacterMap); } }