From 32a52d9177e1b4182d012ecbfe4a79d3363c3d9d Mon Sep 17 00:00:00 2001 From: Chris Ye Date: Sun, 15 Nov 2020 13:48:41 -0800 Subject: [PATCH] Add coretest for android.view.InputDevice. Add coretest cases for android.view.InputDevice, for parcel/unparcel input device object. Bug: 173326051 Test: atest InputDeviceTest Change-Id: I5dea2783b11a195dc2eb8337aad77368b98cf068 --- core/java/android/view/KeyCharacterMap.java | 29 ++++++ core/jni/android_view_KeyCharacterMap.cpp | 55 ++++++----- tests/Input/Android.bp | 15 +-- .../android/test/input/InputDeviceTest.java | 98 +++++++++++++++++++ 4 files changed, 168 insertions(+), 29 deletions(-) create mode 100644 tests/Input/src/com/android/test/input/InputDeviceTest.java diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java index 02a97888cffd3..aa1acc1217df7 100644 --- a/core/java/android/view/KeyCharacterMap.java +++ b/core/java/android/view/KeyCharacterMap.java @@ -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; @@ -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; /** @@ -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) { @@ -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. * @@ -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. */ diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp index ebc507a8381e2..469e577829d8d 100644 --- a/core/jni/android_view_KeyCharacterMap.cpp +++ b/core/jni/android_view_KeyCharacterMap.cpp @@ -16,9 +16,10 @@ #include -#include -#include #include +#include +#include +#include #include #include @@ -75,6 +76,10 @@ jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId, reinterpret_cast(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) { @@ -224,33 +229,37 @@ 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& map1 = + (reinterpret_cast(ptr1))->getMap(); + const std::shared_ptr& map2 = + (reinterpret_cast(ptr2))->getMap(); + if (map1 == nullptr || map2 == nullptr) { + return map1 == map2; + } + return static_cast(*map1 == *map2); +} /* * JNI registration. */ 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 }, - { "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 }, + /* 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}, + {"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}, + {"nativeObtainEmptyKeyCharacterMap", "(I)Landroid/view/KeyCharacterMap;", + (void*)nativeObtainEmptyKeyCharacterMap}, + {"nativeEquals", "(JJ)Z", (void*)nativeEquals}, }; int register_android_view_KeyCharacterMap(JNIEnv* env) diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp index 335c8d0127ebb..eacf5b287a2ee 100644 --- a/tests/Input/Android.bp +++ b/tests/Input/Android.bp @@ -9,14 +9,17 @@ package { android_test { name: "InputTests", - srcs: ["src/**/*.kt"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], platform_apis: true, certificate: "platform", static_libs: [ - "androidx.test.ext.junit", - "androidx.test.rules", - "truth-prebuilt", - "ub-uiautomator", - ], + "androidx.test.ext.junit", + "androidx.test.rules", + "truth-prebuilt", + "ub-uiautomator", + ], test_suites: ["device-tests"], } diff --git a/tests/Input/src/com/android/test/input/InputDeviceTest.java b/tests/Input/src/com/android/test/input/InputDeviceTest.java new file mode 100644 index 0000000000000..63500774816a3 --- /dev/null +++ b/tests/Input/src/com/android/test/input/InputDeviceTest.java @@ -0,0 +1,98 @@ +/* + * 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); + } +}