Add ID to InputEvent.
The interaction between Java and native code for KeyEvent and
MotionEvent is different, so I used different arrangement to pass
sequence number across JNI that keeps the consistency with other
metadata.
Unfortunately this new ID doesn't have absolute uniqueness guarantee so
it can't replace InputEvent#getSequenceNumber() which is used with a
strict in-process uniqueness assumption. Therefore only convert systrace
related use to ID.
Also expose ID generator through a static function in InputEvent so that
everyone can use it. InputReader and InputDispatcher will use different
instances.
Bug: 144889238
Test: Build and run.
Test: atest FrameworksCoreTests:KeyEventTest
Test: atest FrameworksCoreTests:MotionEventTest
Change-Id: Icbdcaee1d98948c05484865a4e15e55161ecfa69
Merged-In: Icbdcaee1d98948c05484865a4e15e55161ecfa69
(cherry picked from 29d21d4062)
This commit is contained in:
@@ -233,6 +233,21 @@ public abstract class InputEvent implements Parcelable {
|
||||
return mSeq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of this event. This is generated when an event is created and preserved until its
|
||||
* last stage. It won't change just because the event crosses process boundary, but should
|
||||
* change when making a copy with modifications.
|
||||
* <p>
|
||||
* To avoid exposing app usage to other processes this ID is generated from a CSPRNG. Therefore
|
||||
* there isn't 100% guarantee on the uniqueness of this ID, though the chance of ID collisions
|
||||
* is considerably low. The rule of thumb is not to rely on the uniqueness for production logic,
|
||||
* but a good source for tracking an event (e.g. logging and profiling).
|
||||
*
|
||||
* @return The ID of this event.
|
||||
* @hide
|
||||
*/
|
||||
public abstract int getId();
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1265,6 +1265,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
|
||||
private KeyEvent mNext;
|
||||
|
||||
private int mId;
|
||||
@UnsupportedAppUsage
|
||||
private int mDeviceId;
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
@@ -1350,9 +1351,9 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
|
||||
private static native String nativeKeyCodeToString(int keyCode);
|
||||
private static native int nativeKeyCodeFromString(String keyCode);
|
||||
private static native int nativeNextId();
|
||||
|
||||
private KeyEvent() {
|
||||
}
|
||||
private KeyEvent() {}
|
||||
|
||||
/**
|
||||
* Create a new key event.
|
||||
@@ -1362,6 +1363,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
* @param code The key code.
|
||||
*/
|
||||
public KeyEvent(int action, int code) {
|
||||
mId = nativeNextId();
|
||||
mAction = action;
|
||||
mKeyCode = code;
|
||||
mRepeatCount = 0;
|
||||
@@ -1383,6 +1385,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
*/
|
||||
public KeyEvent(long downTime, long eventTime, int action,
|
||||
int code, int repeat) {
|
||||
mId = nativeNextId();
|
||||
mDownTime = downTime;
|
||||
mEventTime = eventTime;
|
||||
mAction = action;
|
||||
@@ -1407,6 +1410,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
*/
|
||||
public KeyEvent(long downTime, long eventTime, int action,
|
||||
int code, int repeat, int metaState) {
|
||||
mId = nativeNextId();
|
||||
mDownTime = downTime;
|
||||
mEventTime = eventTime;
|
||||
mAction = action;
|
||||
@@ -1435,6 +1439,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
public KeyEvent(long downTime, long eventTime, int action,
|
||||
int code, int repeat, int metaState,
|
||||
int deviceId, int scancode) {
|
||||
mId = nativeNextId();
|
||||
mDownTime = downTime;
|
||||
mEventTime = eventTime;
|
||||
mAction = action;
|
||||
@@ -1465,6 +1470,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
public KeyEvent(long downTime, long eventTime, int action,
|
||||
int code, int repeat, int metaState,
|
||||
int deviceId, int scancode, int flags) {
|
||||
mId = nativeNextId();
|
||||
mDownTime = downTime;
|
||||
mEventTime = eventTime;
|
||||
mAction = action;
|
||||
@@ -1497,6 +1503,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
public KeyEvent(long downTime, long eventTime, int action,
|
||||
int code, int repeat, int metaState,
|
||||
int deviceId, int scancode, int flags, int source) {
|
||||
mId = nativeNextId();
|
||||
mDownTime = downTime;
|
||||
mEventTime = eventTime;
|
||||
mAction = action;
|
||||
@@ -1523,6 +1530,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
* @param flags The flags for this key event
|
||||
*/
|
||||
public KeyEvent(long time, String characters, int deviceId, int flags) {
|
||||
mId = nativeNextId();
|
||||
mDownTime = time;
|
||||
mEventTime = time;
|
||||
mCharacters = characters;
|
||||
@@ -1539,6 +1547,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
* Make an exact copy of an existing key event.
|
||||
*/
|
||||
public KeyEvent(KeyEvent origEvent) {
|
||||
mId = origEvent.mId;
|
||||
mDownTime = origEvent.mDownTime;
|
||||
mEventTime = origEvent.mEventTime;
|
||||
mAction = origEvent.mAction;
|
||||
@@ -1567,6 +1576,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
*/
|
||||
@Deprecated
|
||||
public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
|
||||
mId = nativeNextId(); // Not an exact copy so assign a new ID.
|
||||
mDownTime = origEvent.mDownTime;
|
||||
mEventTime = eventTime;
|
||||
mAction = origEvent.mAction;
|
||||
@@ -1598,15 +1608,16 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a (potentially recycled) key event.
|
||||
* Obtains a (potentially recycled) key event. Used by native code to create a Java object.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static KeyEvent obtain(long downTime, long eventTime, int action,
|
||||
public static KeyEvent obtain(int id, long downTime, long eventTime, int action,
|
||||
int code, int repeat, int metaState,
|
||||
int deviceId, int scancode, int flags, int source, int displayId, @Nullable byte[] hmac,
|
||||
String characters) {
|
||||
KeyEvent ev = obtain();
|
||||
ev.mId = id;
|
||||
ev.mDownTime = downTime;
|
||||
ev.mEventTime = eventTime;
|
||||
ev.mAction = action;
|
||||
@@ -1623,6 +1634,18 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
return ev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a (potentially recycled) key event.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static KeyEvent obtain(long downTime, long eventTime, int action,
|
||||
int code, int repeat, int metaState,
|
||||
int deviceId, int scanCode, int flags, int source, int displayId, String characters) {
|
||||
return obtain(nativeNextId(), downTime, eventTime, action, code, repeat, metaState,
|
||||
deviceId, scanCode, flags, source, displayId, null /* hmac */, characters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a (potentially recycled) key event.
|
||||
*
|
||||
@@ -1633,7 +1656,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
int code, int repeat, int metaState,
|
||||
int deviceId, int scancode, int flags, int source, String characters) {
|
||||
return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode,
|
||||
flags, source, INVALID_DISPLAY, null /* hmac */, characters);
|
||||
flags, source, INVALID_DISPLAY, characters);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1645,6 +1668,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
*/
|
||||
public static KeyEvent obtain(KeyEvent other) {
|
||||
KeyEvent ev = obtain();
|
||||
ev.mId = other.mId;
|
||||
ev.mDownTime = other.mDownTime;
|
||||
ev.mEventTime = other.mEventTime;
|
||||
ev.mAction = other.mAction;
|
||||
@@ -1695,6 +1719,12 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new key event that is the same as the given one, but whose
|
||||
* event time and repeat count are replaced with the given value.
|
||||
@@ -1723,6 +1753,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
public static KeyEvent changeTimeRepeat(KeyEvent event, long eventTime,
|
||||
int newRepeat, int newFlags) {
|
||||
KeyEvent ret = new KeyEvent(event);
|
||||
ret.mId = nativeNextId(); // Not an exact copy so assign a new ID.
|
||||
ret.mEventTime = eventTime;
|
||||
ret.mRepeatCount = newRepeat;
|
||||
ret.mFlags = newFlags;
|
||||
@@ -1736,6 +1767,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
* @param action The new action code of the event.
|
||||
*/
|
||||
private KeyEvent(KeyEvent origEvent, int action) {
|
||||
mId = nativeNextId(); // Not an exact copy so assign a new ID.
|
||||
mDownTime = origEvent.mDownTime;
|
||||
mEventTime = origEvent.mEventTime;
|
||||
mAction = action;
|
||||
@@ -1772,6 +1804,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
*/
|
||||
public static KeyEvent changeFlags(KeyEvent event, int flags) {
|
||||
event = new KeyEvent(event);
|
||||
event.mId = nativeNextId(); // Not an exact copy so assign a new ID.
|
||||
event.mFlags = flags;
|
||||
return event;
|
||||
}
|
||||
@@ -3096,6 +3129,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
}
|
||||
|
||||
private KeyEvent(Parcel in) {
|
||||
mId = in.readInt();
|
||||
mDeviceId = in.readInt();
|
||||
mSource = in.readInt();
|
||||
mDisplayId = in.readInt();
|
||||
@@ -3115,6 +3149,7 @@ public class KeyEvent extends InputEvent implements Parcelable {
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(PARCEL_TOKEN_KEY_EVENT);
|
||||
|
||||
out.writeInt(mId);
|
||||
out.writeInt(mDeviceId);
|
||||
out.writeInt(mSource);
|
||||
out.writeInt(mDisplayId);
|
||||
|
||||
@@ -1550,6 +1550,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
private static native long nativeCopy(long destNativePtr, long sourceNativePtr,
|
||||
boolean keepHistory);
|
||||
@CriticalNative
|
||||
private static native int nativeGetId(long nativePtr);
|
||||
@CriticalNative
|
||||
private static native int nativeGetDeviceId(long nativePtr);
|
||||
@CriticalNative
|
||||
private static native int nativeGetSource(long nativePtr);
|
||||
@@ -2024,6 +2026,12 @@ public final class MotionEvent extends InputEvent implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public int getId() {
|
||||
return nativeGetId(mNativePtr);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final int getDeviceId() {
|
||||
|
||||
@@ -5379,7 +5379,8 @@ public final class ViewRootImpl implements ViewParent,
|
||||
if (mTracePrefix == null) {
|
||||
mTracePrefix = getClass().getSimpleName();
|
||||
}
|
||||
Trace.traceBegin(traceTag, mTracePrefix + " seq#=" + q.mEvent.getSequenceNumber());
|
||||
Trace.traceBegin(traceTag, mTracePrefix + " id=0x"
|
||||
+ Integer.toHexString(q.mEvent.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7986,12 +7987,13 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
private void deliverInputEvent(QueuedInputEvent q) {
|
||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
|
||||
q.mEvent.getSequenceNumber());
|
||||
q.mEvent.getId());
|
||||
|
||||
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
|
||||
+ Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
|
||||
+ q.mEvent.getEventTimeNano() + " seq#=" + q.mEvent.getSequenceNumber());
|
||||
+ q.mEvent.getEventTimeNano() + " id=0x"
|
||||
+ Integer.toHexString(q.mEvent.getId()));
|
||||
}
|
||||
try {
|
||||
if (mInputEventConsistencyVerifier != null) {
|
||||
@@ -8032,7 +8034,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
private void finishInputEvent(QueuedInputEvent q) {
|
||||
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
|
||||
q.mEvent.getSequenceNumber());
|
||||
q.mEvent.getId());
|
||||
|
||||
if (q.mReceiver != null) {
|
||||
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
|
||||
|
||||
@@ -75,6 +75,7 @@ static struct {
|
||||
jmethodID obtain;
|
||||
jmethodID recycle;
|
||||
|
||||
jfieldID mId;
|
||||
jfieldID mDeviceId;
|
||||
jfieldID mSource;
|
||||
jfieldID mDisplayId;
|
||||
@@ -96,6 +97,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
|
||||
ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
|
||||
jobject eventObj =
|
||||
env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
|
||||
event->getId(),
|
||||
nanoseconds_to_milliseconds(event->getDownTime()),
|
||||
nanoseconds_to_milliseconds(event->getEventTime()),
|
||||
event->getAction(), event->getKeyCode(),
|
||||
@@ -114,6 +116,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
|
||||
|
||||
status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
|
||||
KeyEvent* event) {
|
||||
jint id = env->GetIntField(eventObj, gKeyEventClassInfo.mId);
|
||||
jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
|
||||
jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
|
||||
jint displayId = env->GetIntField(eventObj, gKeyEventClassInfo.mDisplayId);
|
||||
@@ -131,7 +134,7 @@ status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
|
||||
jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime);
|
||||
jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
|
||||
|
||||
event->initialize(deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
|
||||
event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
|
||||
metaState, repeatCount, milliseconds_to_nanoseconds(downTime),
|
||||
milliseconds_to_nanoseconds(eventTime));
|
||||
return OK;
|
||||
@@ -159,14 +162,18 @@ static jint android_view_KeyEvent_nativeKeyCodeFromString(JNIEnv* env, jobject c
|
||||
return KeyEvent::getKeyCodeFromLabel(keyLabel.c_str());
|
||||
}
|
||||
|
||||
static jint android_view_KeyEvent_nativeNextId() {
|
||||
return static_cast<jint>(InputEvent::nextId());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static const JNINativeMethod g_methods[] = {
|
||||
{ "nativeKeyCodeToString", "(I)Ljava/lang/String;",
|
||||
(void*)android_view_KeyEvent_nativeKeyCodeToString},
|
||||
{ "nativeKeyCodeFromString", "(Ljava/lang/String;)I",
|
||||
(void*)android_view_KeyEvent_nativeKeyCodeFromString},
|
||||
{"nativeKeyCodeToString", "(I)Ljava/lang/String;",
|
||||
(void*)android_view_KeyEvent_nativeKeyCodeToString},
|
||||
{"nativeKeyCodeFromString", "(Ljava/lang/String;)I",
|
||||
(void*)android_view_KeyEvent_nativeKeyCodeFromString},
|
||||
{"nativeNextId", "()I", (void*)android_view_KeyEvent_nativeNextId},
|
||||
};
|
||||
|
||||
int register_android_view_KeyEvent(JNIEnv* env) {
|
||||
@@ -175,10 +182,11 @@ int register_android_view_KeyEvent(JNIEnv* env) {
|
||||
|
||||
gKeyEventClassInfo.obtain =
|
||||
GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz, "obtain",
|
||||
"(JJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;");
|
||||
"(IJJIIIIIIIII[BLjava/lang/String;)Landroid/view/KeyEvent;");
|
||||
gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz,
|
||||
"recycle", "()V");
|
||||
|
||||
gKeyEventClassInfo.mId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mId", "I");
|
||||
gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I");
|
||||
gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I");
|
||||
gKeyEventClassInfo.mDisplayId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDisplayId",
|
||||
|
||||
@@ -369,9 +369,10 @@ static jlong android_view_MotionEvent_nativeInitialize(
|
||||
env->DeleteLocalRef(pointerCoordsObj);
|
||||
}
|
||||
|
||||
event->initialize(deviceId, source, displayId, INVALID_HMAC, action, 0, flags, edgeFlags,
|
||||
metaState, buttonState, static_cast<MotionClassification>(classification),
|
||||
1 /*xScale*/, 1 /*yScale*/, xOffset, yOffset, xPrecision, yPrecision,
|
||||
event->initialize(InputEvent::nextId(), deviceId, source, displayId, INVALID_HMAC, action, 0,
|
||||
flags, edgeFlags, metaState, buttonState,
|
||||
static_cast<MotionClassification>(classification), 1 /*xScale*/, 1 /*yScale*/,
|
||||
xOffset, yOffset, xPrecision, yPrecision,
|
||||
AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
|
||||
downTimeNanos, eventTimeNanos, pointerCount, pointerProperties,
|
||||
rawPointerCoords);
|
||||
@@ -592,6 +593,11 @@ static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sour
|
||||
return reinterpret_cast<jlong>(destEvent);
|
||||
}
|
||||
|
||||
static jint android_view_MotionEvent_nativeGetId(jlong nativePtr) {
|
||||
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
|
||||
return event->getId();
|
||||
}
|
||||
|
||||
static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) {
|
||||
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
|
||||
return event->getDeviceId();
|
||||
@@ -790,6 +796,7 @@ static const JNINativeMethod gMotionEventMethods[] = {
|
||||
// --------------- @CriticalNative ------------------
|
||||
|
||||
{"nativeCopy", "(JJZ)J", (void*)android_view_MotionEvent_nativeCopy},
|
||||
{"nativeGetId", "(J)I", (void*)android_view_MotionEvent_nativeGetId},
|
||||
{"nativeGetDeviceId", "(J)I", (void*)android_view_MotionEvent_nativeGetDeviceId},
|
||||
{"nativeGetSource", "(J)I", (void*)android_view_MotionEvent_nativeGetSource},
|
||||
{"nativeSetSource", "(JI)V", (void*)android_view_MotionEvent_nativeSetSource},
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.view;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
@@ -28,10 +29,14 @@ import androidx.test.filters.SmallTest;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class KeyEventTest {
|
||||
|
||||
private static final int ID = 0xabcdef;
|
||||
private static final int DOWN_TIME = 50;
|
||||
private static final long EVENT_TIME = 100;
|
||||
private static final int ACTION = KeyEvent.ACTION_DOWN;
|
||||
@@ -45,6 +50,8 @@ public class KeyEventTest {
|
||||
private static final byte[] HMAC = null;
|
||||
private static final String CHARACTERS = null;
|
||||
|
||||
private static final int ID_SOURCE_MASK = 0x3 << 30;
|
||||
|
||||
@Test
|
||||
public void testObtain() {
|
||||
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
|
||||
@@ -75,8 +82,7 @@ public class KeyEventTest {
|
||||
public void testObtainWithDisplayId() {
|
||||
final int displayId = 5;
|
||||
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
|
||||
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, null /* hmac*/,
|
||||
CHARACTERS);
|
||||
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS);
|
||||
assertEquals(DOWN_TIME, keyEvent.getDownTime());
|
||||
assertEquals(EVENT_TIME, keyEvent.getEventTime());
|
||||
assertEquals(ACTION, keyEvent.getAction());
|
||||
@@ -91,6 +97,52 @@ public class KeyEventTest {
|
||||
assertEquals(CHARACTERS, keyEvent.getCharacters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test
|
||||
* but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough.
|
||||
* Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for
|
||||
* this test.
|
||||
*/
|
||||
@Test
|
||||
public void testObtainGeneratesUniqueId() {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
|
||||
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
|
||||
assertFalse("Found duplicate ID in round " + i,
|
||||
set.contains(keyEvent.getId()));
|
||||
set.add(keyEvent.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorGeneratesUniqueId() {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
|
||||
assertFalse("Found duplicate sequence number in round " + i,
|
||||
set.contains(keyEvent.getId()));
|
||||
set.add(keyEvent.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObtainGeneratesIdWithRightSource() {
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
|
||||
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS);
|
||||
assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructorGeneratesIdWithRightSource() {
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
KeyEvent keyEvent = new KeyEvent(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT);
|
||||
assertEquals(0x3 << 30, ID_SOURCE_MASK & keyEvent.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParcelUnparcel() {
|
||||
KeyEvent key1 = createKey();
|
||||
@@ -112,11 +164,12 @@ public class KeyEventTest {
|
||||
}
|
||||
|
||||
private static KeyEvent createKey() {
|
||||
return KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT,
|
||||
METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
|
||||
return KeyEvent.obtain(ID, DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, METASTATE,
|
||||
DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, INVALID_DISPLAY, HMAC, CHARACTERS);
|
||||
}
|
||||
|
||||
private static void compareKeys(KeyEvent key1, KeyEvent key2) {
|
||||
assertEquals(key1.getId(), key2.getId());
|
||||
assertEquals(key1.getDownTime(), key2.getDownTime());
|
||||
assertEquals(key1.getEventTime(), key2.getEventTime());
|
||||
assertEquals(key1.getAction(), key2.getAction());
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.TOOL_TYPE_FINGER;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import android.view.MotionEvent.PointerCoords;
|
||||
@@ -34,9 +35,13 @@ import androidx.test.runner.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class MotionEventTest {
|
||||
private static final int ID_SOURCE_MASK = 0x3 << 30;
|
||||
|
||||
@Test
|
||||
public void testObtainWithDisplayId() {
|
||||
@@ -138,4 +143,30 @@ public class MotionEventTest {
|
||||
assertEquals(30, event.getXCursorPosition(), 0.1);
|
||||
assertEquals(50, event.getYCursorPosition(), 0.1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that it can generate 500 consecutive distinct numbers. This is a non-deterministic test
|
||||
* but with 30 bits randomness the failure rate is roughly 4.52e-5, which is negligible enough.
|
||||
* Probability formula: N * (N - 1) * ... * (N - n + 1) / N^n, where N = 2^30 and n = 500 for
|
||||
* this test.
|
||||
*/
|
||||
@Test
|
||||
public void testObtainGeneratesUniqueId() {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
|
||||
ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
|
||||
assertFalse("Found duplicate ID in round " + i, set.contains(event.getId()));
|
||||
set.add(event.getSequenceNumber());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObtainGeneratesIdWithRightSource() {
|
||||
for (int i = 0; i < 500; ++i) {
|
||||
final MotionEvent event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
|
||||
ACTION_DOWN, 30 /* x */, 50 /* y */, 0 /* metaState */);
|
||||
assertEquals(0x3 << 30, ID_SOURCE_MASK & event.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3085,7 +3085,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
event.getAction(), fallbackAction.keyCode,
|
||||
event.getRepeatCount(), fallbackAction.metaState,
|
||||
event.getDeviceId(), event.getScanCode(),
|
||||
flags, event.getSource(), event.getDisplayId(), null /* hmac */, null);
|
||||
flags, event.getSource(), event.getDisplayId(), null);
|
||||
|
||||
if (!interceptFallback(focusedToken, fallbackEvent, policyFlags)) {
|
||||
fallbackEvent.recycle();
|
||||
|
||||
Reference in New Issue
Block a user