Ensure the ShortcutManager uses the correct key character map.
The ShortcutManager used to only receive the key code of the key event
that triggered the shortcut. This change now provides the shortcut
manager with the whole key event so it can look up the associated
character using the correct key character map.
To make this more efficient, added a mechanism for recycling
key events. At the moment it is only used by key events owned by the
system process, since clients of the existing API (such as Views)
might continue to hold on to key events after dispatch has finished so
they would break if the key event were recycled by the framework.
Deprecated KeyCharacterMap.BUILT_IN_KEYBOARD.
Change-Id: I4313725dd63f2be01c350c005a41c7fde9bc67e8
diff --git a/api/current.xml b/api/current.xml
index a98c8b6..87394ce 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -196675,7 +196675,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index fbd9eac..d330cca 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -31,7 +31,19 @@
public class KeyCharacterMap {
/**
* The id of the device's primary built in keyboard is always 0.
+ *
+ * @deprecated This constant should no longer be used because there is no
+ * guarantee that a device has a built-in keyboard that can be used for
+ * typing text. There might not be a built-in keyboard, the built-in keyboard
+ * might be a {@link #NUMERIC} or {@link #SPECIAL_FUNCTION} keyboard, or there
+ * might be multiple keyboards installed including external keyboards.
+ * When interpreting key presses received from the framework, applications should
+ * use the device id specified in the {@link #KeyEvent} received.
+ * When synthesizing key presses for delivery elsewhere or when translating key presses
+ * from unknown keyboards, applications should use the special {@link #VIRTUAL_KEYBOARD}
+ * device id.
*/
+ @Deprecated
public static final int BUILT_IN_KEYBOARD = 0;
/**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index b3277e4..03407a3 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1081,7 +1081,15 @@
static final boolean DEBUG = false;
static final String TAG = "KeyEvent";
-
+
+ private static final int MAX_RECYCLED = 10;
+ private static final Object gRecyclerLock = new Object();
+ private static int gRecyclerUsed;
+ private static KeyEvent gRecyclerTop;
+
+ private KeyEvent mNext;
+ private boolean mRecycled;
+
private int mMetaState;
private int mAction;
private int mKeyCode;
@@ -1160,6 +1168,9 @@
}
}
+ private KeyEvent() {
+ }
+
/**
* Create a new key event.
*
@@ -1382,6 +1393,67 @@
mCharacters = origEvent.mCharacters;
}
+ private static KeyEvent obtain() {
+ final KeyEvent ev;
+ synchronized (gRecyclerLock) {
+ ev = gRecyclerTop;
+ if (ev == null) {
+ return new KeyEvent();
+ }
+ gRecyclerTop = ev.mNext;
+ gRecyclerUsed -= 1;
+ }
+ ev.mRecycled = false;
+ ev.mNext = null;
+ 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, String characters) {
+ KeyEvent ev = obtain();
+ ev.mDownTime = downTime;
+ ev.mEventTime = eventTime;
+ ev.mAction = action;
+ ev.mKeyCode = code;
+ ev.mRepeatCount = repeat;
+ ev.mMetaState = metaState;
+ ev.mDeviceId = deviceId;
+ ev.mScanCode = scancode;
+ ev.mFlags = flags;
+ ev.mSource = source;
+ ev.mCharacters = characters;
+ return ev;
+ }
+
+ /**
+ * Recycles a key event.
+ * Key events should only be recycled if they are owned by the system since user
+ * code expects them to be essentially immutable, "tracking" notwithstanding.
+ *
+ * @hide
+ */
+ public final void recycle() {
+ if (mRecycled) {
+ throw new RuntimeException(toString() + " recycled twice!");
+ }
+ mRecycled = true;
+ mCharacters = null;
+
+ synchronized (gRecyclerLock) {
+ if (gRecyclerUsed < MAX_RECYCLED) {
+ gRecyclerUsed++;
+ mNext = gRecyclerTop;
+ gRecyclerTop = this;
+ }
+ }
+ }
+
/**
* 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.
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 195d689..e81aa98 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -314,10 +314,10 @@
*/
static private final int BASE_AVAIL_SAMPLES = 8;
- static private final int MAX_RECYCLED = 10;
- static private Object gRecyclerLock = new Object();
- static private int gRecyclerUsed = 0;
- static private MotionEvent gRecyclerTop = null;
+ private static final int MAX_RECYCLED = 10;
+ private static final Object gRecyclerLock = new Object();
+ private static int gRecyclerUsed;
+ private static MotionEvent gRecyclerTop;
private long mDownTimeNano;
private int mAction;
@@ -361,7 +361,8 @@
static private MotionEvent obtain(int pointerCount, int sampleCount) {
final MotionEvent ev;
synchronized (gRecyclerLock) {
- if (gRecyclerTop == null) {
+ ev = gRecyclerTop;
+ if (ev == null) {
if (pointerCount < BASE_AVAIL_POINTERS) {
pointerCount = BASE_AVAIL_POINTERS;
}
@@ -370,7 +371,6 @@
}
return new MotionEvent(pointerCount, sampleCount);
}
- ev = gRecyclerTop;
gRecyclerTop = ev.mNext;
gRecyclerUsed -= 1;
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 5a9cd97..af36d80 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -551,19 +551,14 @@
* affect the power state of the device, for example, the power keys.
* Generally, it's best to keep as little as possible in the queue thread
* because it's the most fragile.
- * @param whenNanos The event time in uptime nanoseconds.
- * @param action The key event action.
- * @param flags The key event flags.
- * @param keyCode The key code.
- * @param scanCode The key's scan code.
+ * @param event The key event.
* @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on
*
* @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
* {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
*/
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
@@ -574,18 +569,12 @@
*
* @param win The window that currently has focus. This is where the key
* event will normally go.
- * @param action The key event action.
- * @param flags The key event flags.
- * @param keyCode The key code.
- * @param scanCode The key's scan code.
- * @param metaState bit mask of meta keys that are held.
- * @param repeatCount Number of times a key down has repeated.
+ * @param event The key event.
* @param policyFlags The policy flags associated with the key.
* @return Returns true if the policy consumed the event and it should
* not be further dispatched.
*/
- public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
+ public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags);
/**
* Called from the input dispatcher thread when an application did not handle
@@ -596,17 +585,11 @@
*
* @param win The window that currently has focus. This is where the key
* event will normally go.
- * @param action The key event action.
- * @param flags The key event flags.
- * @param keyCode The key code.
- * @param scanCode The key's scan code.
- * @param metaState bit mask of meta keys that are held.
- * @param repeatCount Number of times a key down has repeated.
+ * @param event The key event.
* @param policyFlags The policy flags associated with the key.
* @return Returns true if the policy consumed the event.
*/
- public boolean dispatchUnhandledKey(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
+ public boolean dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags);
/**
* Called when layout of the windows is about to start.
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 695d50a4..b033878 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -579,20 +579,30 @@
while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
jobject inputEventObj = android_view_KeyEvent_fromNative(
code->env, keyEvent);
- jboolean handled = code->env->CallBooleanMethod(code->clazz,
- gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
- checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
- code->env->DeleteLocalRef(inputEventObj);
+ jboolean handled;
+ if (inputEventObj) {
+ handled = code->env->CallBooleanMethod(code->clazz,
+ gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
+ checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
+ code->env->DeleteLocalRef(inputEventObj);
+ } else {
+ LOGE("Failed to obtain key event for dispatchUnhandledKeyEvent.");
+ handled = false;
+ }
code->nativeInputQueue->finishEvent(keyEvent, handled, true);
}
int seq;
while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) {
jobject inputEventObj = android_view_KeyEvent_fromNative(
code->env, keyEvent);
- code->env->CallVoidMethod(code->clazz,
- gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
- checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
- code->env->DeleteLocalRef(inputEventObj);
+ if (inputEventObj) {
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
+ checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
+ code->env->DeleteLocalRef(inputEventObj);
+ } else {
+ LOGE("Failed to obtain key event for preDispatchKeyEvent.");
+ }
}
} break;
case CMD_FINISH: {
@@ -987,7 +997,12 @@
NativeCode* code = (NativeCode*)handle;
if (code->nativeInputQueue != NULL) {
KeyEvent* event = code->nativeInputQueue->createKeyEvent();
- android_view_KeyEvent_toNative(env, eventObj, event);
+ status_t status = android_view_KeyEvent_toNative(env, eventObj, event);
+ if (status) {
+ delete event;
+ jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
+ return;
+ }
code->nativeInputQueue->dispatchEvent(event);
}
}
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 7e7583c..4b04b8b 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -30,7 +30,8 @@
static struct {
jclass clazz;
- jmethodID ctor;
+ jmethodID obtain;
+ jmethodID recycle;
jfieldID mDeviceId;
jfieldID mSource;
@@ -48,7 +49,8 @@
// ----------------------------------------------------------------------------
jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
- return env->NewObject(gKeyEventClassInfo.clazz, gKeyEventClassInfo.ctor,
+ jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz,
+ gKeyEventClassInfo.obtain,
nanoseconds_to_milliseconds(event->getDownTime()),
nanoseconds_to_milliseconds(event->getEventTime()),
event->getAction(),
@@ -58,10 +60,18 @@
event->getDeviceId(),
event->getScanCode(),
event->getFlags(),
- event->getSource());
+ event->getSource(),
+ NULL);
+ if (env->ExceptionCheck()) {
+ LOGE("An exception occurred while obtaining a key event.");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ return NULL;
+ }
+ return eventObj;
}
-void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
+status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
KeyEvent* event) {
jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
@@ -77,6 +87,18 @@
event->initialize(deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
milliseconds_to_nanoseconds(downTime),
milliseconds_to_nanoseconds(eventTime));
+ return OK;
+}
+
+status_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj) {
+ env->CallVoidMethod(eventObj, gKeyEventClassInfo.recycle);
+ if (env->ExceptionCheck()) {
+ LOGW("An exception occurred while recycling a key event.");
+ LOGW_EX(env);
+ env->ExceptionClear();
+ return UNKNOWN_ERROR;
+ }
+ return OK;
}
static jboolean native_isSystemKey(JNIEnv* env, jobject clazz, jint keyCode) {
@@ -87,6 +109,7 @@
return KeyEvent::hasDefaultAction(keyCode);
}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod g_methods[] = {
@@ -99,6 +122,10 @@
LOG_FATAL_IF(! var, "Unable to find class " className); \
var = jclass(env->NewGlobalRef(var));
+#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method" methodName);
+
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method" methodName);
@@ -109,9 +136,11 @@
int register_android_view_KeyEvent(JNIEnv* env) {
FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
-
- GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz,
- "<init>", "(JJIIIIIIII)V");
+
+ GET_STATIC_METHOD_ID(gKeyEventClassInfo.obtain, gKeyEventClassInfo.clazz,
+ "obtain", "(JJIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;");
+ GET_METHOD_ID(gKeyEventClassInfo.recycle, gKeyEventClassInfo.clazz,
+ "recycle", "()V");
GET_FIELD_ID(gKeyEventClassInfo.mDeviceId, gKeyEventClassInfo.clazz,
"mDeviceId", "I");
diff --git a/core/jni/android_view_KeyEvent.h b/core/jni/android_view_KeyEvent.h
index 0bd410c..586eb2f 100644
--- a/core/jni/android_view_KeyEvent.h
+++ b/core/jni/android_view_KeyEvent.h
@@ -18,18 +18,28 @@
#define _ANDROID_VIEW_KEYEVENT_H
#include "jni.h"
+#include <utils/Errors.h>
+#include <utils/threads.h>
namespace android {
class KeyEvent;
-/* Obtains an instance of a DVM KeyEvent object as a copy of a native KeyEvent instance. */
+/* Obtains an instance of a DVM KeyEvent object as a copy of a native KeyEvent instance.
+ * Returns NULL on error. */
extern jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event);
-/* Copies the contents of a DVM KeyEvent object to a native KeyEvent instance. */
-extern void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
+/* Copies the contents of a DVM KeyEvent object to a native KeyEvent instance.
+ * Returns non-zero on error. */
+extern status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
KeyEvent* event);
+/* Recycles a DVM KeyEvent object.
+ * Key events should only be recycled if they are owned by the system since user
+ * code expects them to be essentially immutable, "tracking" notwithstanding.
+ * Returns non-zero on error. */
+extern status_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj);
+
} // namespace android
#endif // _ANDROID_OS_KEYEVENT_H
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 537ac72..f32f0ff 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -169,7 +169,7 @@
return eventObj;
}
-void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
+status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
MotionEvent* event) {
jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId);
jint source = env->GetIntField(eventObj, gMotionEventClassInfo.mSource);
@@ -184,6 +184,16 @@
jint flags = env->GetIntField(eventObj, gMotionEventClassInfo.mFlags);
jint numPointers = env->GetIntField(eventObj, gMotionEventClassInfo.mNumPointers);
jint numSamples = env->GetIntField(eventObj, gMotionEventClassInfo.mNumSamples);
+
+ if (numPointers == 0) {
+ LOGE("Malformed MotionEvent: mNumPointers was zero");
+ return BAD_VALUE;
+ }
+ if (numSamples == 0) {
+ LOGE("Malformed MotionEvent: mNumSamples was zero");
+ return BAD_VALUE;
+ }
+
jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mPointerIdentifiers));
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
@@ -191,9 +201,6 @@
jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mEventTimeNanoSamples));
- LOG_FATAL_IF(numPointers == 0, "numPointers was zero");
- LOG_FATAL_IF(numSamples == 0, "numSamples was zero");
-
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL);
jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL);
jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical(
@@ -236,22 +243,25 @@
event->addSample(sampleEventTime, samplePointerCoords);
}
- env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT);
- env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT);
env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT);
- env->DeleteLocalRef(pointerIdentifierArray);
- env->DeleteLocalRef(dataSampleArray);
env->DeleteLocalRef(eventTimeNanoSampleArray);
+ env->DeleteLocalRef(dataSampleArray);
+ env->DeleteLocalRef(pointerIdentifierArray);
+ return OK;
}
-void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
+status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
if (env->ExceptionCheck()) {
LOGW("An exception occurred while recycling a motion event.");
LOGW_EX(env);
env->ExceptionClear();
+ return UNKNOWN_ERROR;
}
+ return OK;
}
static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
diff --git a/core/jni/android_view_MotionEvent.h b/core/jni/android_view_MotionEvent.h
index 86e4bde..80dc861 100644
--- a/core/jni/android_view_MotionEvent.h
+++ b/core/jni/android_view_MotionEvent.h
@@ -18,20 +18,24 @@
#define _ANDROID_VIEW_MOTIONEVENT_H
#include "jni.h"
+#include <utils/Errors.h>
namespace android {
class MotionEvent;
-/* Obtains an instance of a DVM MotionEvent object as a copy of a native MotionEvent instance. */
+/* Obtains an instance of a DVM MotionEvent object as a copy of a native MotionEvent instance.
+ * Returns NULL on error. */
extern jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event);
-/* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance. */
-extern void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
+/* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance.
+ * Returns non-zero on error. */
+extern status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
MotionEvent* event);
-/* Recycles a DVM MotionEvent object. */
-extern void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj);
+/* Recycles a DVM MotionEvent object.
+ * Returns non-zero on error. */
+extern status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj);
} // namespace android
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 11b798f..4dc8f2a 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -507,10 +507,8 @@
/*
* Get the path of an input device configuration file, if one is available.
* Spaces in the name are replaced with underscores.
+ * Considers both system provided and user installed configuration files.
*
- * Looks in: <system-root>/usr/<type-specific-directory>/<name><extension>.
- *
- * TODO Also look in a user installable location.
* Returns an empty string if not found.
*/
extern String8 getInputDeviceConfigurationFilePath(
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index d0812de..b621680 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -291,9 +291,7 @@
* This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
* should be dispatched to applications.
*/
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags) = 0;
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0;
/* Intercepts a generic touch, trackball or other event before queueing it.
* The policy can use this method as an opportunity to perform power management functions
@@ -894,9 +892,6 @@
// Input channels that will receive a copy of all input events.
Vector<sp<InputChannel> > mMonitoringChannels;
- // Preallocated key event object used for policy inquiries.
- KeyEvent mReusableKeyEvent;
-
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index f831086..b312cda 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -146,12 +146,12 @@
}
void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
- outConfiguration->clear();
-
AutoMutex _l(mLock);
device_t* device = getDeviceLocked(deviceId);
if (device && device->configuration) {
*outConfiguration = *device->configuration;
+ } else {
+ outConfiguration->clear();
}
}
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index db7d448..0708223 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -2081,9 +2081,22 @@
return;
}
+ if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ }
+
policyFlags |= POLICY_FLAG_TRUSTED;
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
+
+ KeyEvent event;
+ event.initialize(deviceId, source, action, flags, keyCode, scanCode,
+ metaState, 0, downTime, eventTime);
+
+ mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
+
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
bool needWake;
{ // acquire lock
@@ -2289,17 +2302,22 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- nsecs_t eventTime = keyEvent->getEventTime();
- int32_t deviceId = keyEvent->getDeviceId();
int32_t flags = keyEvent->getFlags();
- int32_t keyCode = keyEvent->getKeyCode();
- int32_t scanCode = keyEvent->getScanCode();
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
+ if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ }
+
+ mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
mLock.lock();
- injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
- policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(),
+ injectedEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
+ keyEvent->getDeviceId(), keyEvent->getSource(),
+ policyFlags, action, flags,
+ keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), keyEvent->getDownTime());
break;
}
@@ -2999,12 +3017,14 @@
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
- initializeKeyEvent(&mReusableKeyEvent, entry);
+
+ KeyEvent event;
+ initializeKeyEvent(&event, entry);
mLock.unlock();
bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel,
- & mReusableKeyEvent, entry->policyFlags);
+ &event, entry->policyFlags);
mLock.lock();
@@ -3025,12 +3045,13 @@
&& dispatchEntry->hasForegroundTarget()
&& dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- initializeKeyEvent(&mReusableKeyEvent, keyEntry);
+ KeyEvent event;
+ initializeKeyEvent(&event, keyEntry);
mLock.unlock();
mPolicy->dispatchUnhandledKey(connection->inputChannel,
- & mReusableKeyEvent, keyEntry->policyFlags);
+ &event, keyEntry->policyFlags);
mLock.lock();
}
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index dc9085b..aa690e5 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -2007,7 +2007,7 @@
}
if (mCalibration.haveToolSizeIsSummed) {
- dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %d\n",
+ dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %s\n",
toString(mCalibration.toolSizeIsSummed));
}
diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp
index f352dbf..68f9037 100644
--- a/libs/ui/tests/InputDispatcher_test.cpp
+++ b/libs/ui/tests/InputDispatcher_test.cpp
@@ -54,9 +54,7 @@
return 60;
}
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags) {
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
}
virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1373627..c528745 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1215,11 +1215,13 @@
/** {@inheritDoc} */
@Override
- public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
+ public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
final boolean keyguardOn = keyguardOn();
- final boolean down = (action == KeyEvent.ACTION_DOWN);
- final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
+ final int keyCode = event.getKeyCode();
+ final int repeatCount = event.getRepeatCount();
+ final int metaState = event.getMetaState();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
if (false) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -1348,7 +1350,7 @@
// Shortcuts are invoked through Search+key, so intercept those here
if (mSearchKeyPressed) {
if (down && repeatCount == 0 && !keyguardOn) {
- Intent shortcutIntent = mShortcutManager.getIntent(keyCode, metaState);
+ Intent shortcutIntent = mShortcutManager.getIntent(event);
if (shortcutIntent != null) {
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(shortcutIntent);
@@ -1368,13 +1370,15 @@
/** {@inheritDoc} */
@Override
- public boolean dispatchUnhandledKey(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
+ public boolean dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
if (false) {
- Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + action
- + ", flags=" + flags + ", keyCode=" + keyCode
- + ", scanCode=" + scanCode + ", metaState=" + metaState
- + ", repeatCount=" + repeatCount + ", policyFlags=" + policyFlags);
+ Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
+ + ", flags=" + event.getFlags()
+ + ", keyCode=" + event.getKeyCode()
+ + ", scanCode=" + event.getScanCode()
+ + ", metaState=" + event.getMetaState()
+ + ", repeatCount=" + event.getRepeatCount()
+ + ", policyFlags=" + policyFlags);
}
return false;
}
@@ -1970,10 +1974,10 @@
/** {@inheritDoc} */
@Override
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
- final boolean down = action == KeyEvent.ACTION_DOWN;
- final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
+ final int keyCode = event.getKeyCode();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -2164,12 +2168,8 @@
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
// only do it if the showing app doesn't process the key on its own.
- long when = whenNanos / 1000000;
- KeyEvent keyEvent = new KeyEvent(when, when, action, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, scanCode, flags,
- InputDevice.SOURCE_KEYBOARD);
mBroadcastWakeLock.acquire();
- mHandler.post(new PassHeadsetKey(keyEvent));
+ mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
}
break;
}
diff --git a/policy/src/com/android/internal/policy/impl/ShortcutManager.java b/policy/src/com/android/internal/policy/impl/ShortcutManager.java
index 51377d8..fc66a20 100644
--- a/policy/src/com/android/internal/policy/impl/ShortcutManager.java
+++ b/policy/src/com/android/internal/policy/impl/ShortcutManager.java
@@ -25,6 +25,7 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import java.net.URISyntaxException;
@@ -100,20 +101,17 @@
* This will first try an exact match (with modifiers), and then try a
* match without modifiers (primary character on a key).
*
- * @param keyCode The keycode of the key pushed.
- * @param modifiers The modifiers without any that are used for chording
- * to invoke a shortcut.
+ * @param event The key event of the key that was pressed.
* @return The intent that matches the shortcut, or null if not found.
*/
- public Intent getIntent(int keyCode, int modifiers) {
- KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ public Intent getIntent(KeyEvent event) {
// First try the exact keycode (with modifiers)
- int shortcut = kcm.get(keyCode, modifiers);
+ int shortcut = event.getUnicodeChar();
Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
if (intent != null) return intent;
-
+
// Next try the keycode without modifiers (the primary character on that key)
- shortcut = Character.toLowerCase(kcm.get(keyCode, 0));
+ shortcut = Character.toLowerCase(event.getUnicodeChar(0));
return shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
}
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 30b49d3..9078811 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -30,6 +30,7 @@
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
+import android.view.KeyEvent;
import android.view.Surface;
import java.io.BufferedReader;
@@ -398,26 +399,23 @@
}
@SuppressWarnings("unused")
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
- whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
+ event, policyFlags, isScreenOn);
}
@SuppressWarnings("unused")
- public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
- int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
- return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
- action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
+ public boolean interceptKeyBeforeDispatching(InputChannel focus,
+ KeyEvent event, int policyFlags) {
+ return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(
+ focus, event, policyFlags);
}
@SuppressWarnings("unused")
- public boolean dispatchUnhandledKey(InputChannel focus, int action,
- int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
- return mWindowManagerService.mInputMonitor.dispatchUnhandledKey(focus,
- action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
+ public boolean dispatchUnhandledKey(InputChannel focus,
+ KeyEvent event, int policyFlags) {
+ return mWindowManagerService.mInputMonitor.dispatchUnhandledKey(
+ focus, event, policyFlags);
}
@SuppressWarnings("unused")
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index cbb35c6..5e49404 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5829,30 +5829,25 @@
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
- return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
- keyCode, scanCode, policyFlags, isScreenOn);
+ public int interceptKeyBeforeQueueing(
+ KeyEvent event, int policyFlags, boolean isScreenOn) {
+ return mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
}
/* Provides an opportunity for the window manager policy to process a key before
* ordinary dispatch. */
- public boolean interceptKeyBeforeDispatching(InputChannel focus,
- int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
+ public boolean interceptKeyBeforeDispatching(
+ InputChannel focus, KeyEvent event, int policyFlags) {
WindowState windowState = getWindowStateForInputChannel(focus);
- return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
- keyCode, scanCode, metaState, repeatCount, policyFlags);
+ return mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}
/* Provides an opportunity for the window manager policy to process a key that
* the application did not handle. */
- public boolean dispatchUnhandledKey(InputChannel focus,
- int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
+ public boolean dispatchUnhandledKey(
+ InputChannel focus, KeyEvent event, int policyFlags) {
WindowState windowState = getWindowStateForInputChannel(focus);
- return mPolicy.dispatchUnhandledKey(windowState, action, flags,
- keyCode, scanCode, metaState, repeatCount, policyFlags);
+ return mPolicy.dispatchUnhandledKey(windowState, event, policyFlags);
}
/* Called when the current input focus changes.
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index d0760c0..aa84db5 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -191,9 +191,7 @@
virtual nsecs_t getKeyRepeatTimeout();
virtual nsecs_t getKeyRepeatDelay();
virtual int32_t getMaxEventsPerSecond();
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags);
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags);
@@ -718,6 +716,7 @@
outWindow.ownerUid = ownerUid;
env->ReleaseStringUTFChars(name, nameStr);
+ env->DeleteLocalRef(name);
valid = true;
} else {
LOGW("Dropping input target because its input channel is not initialized.");
@@ -779,20 +778,8 @@
return android_server_PowerManagerService_isScreenBright();
}
-void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
- int32_t deviceId, int32_t action, int32_t &flags,
- int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, "
- "keyCode=%d, scanCode=%d, policyFlags=0x%x",
- when, deviceId, action, flags, keyCode, scanCode, policyFlags);
-#endif
-
- if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
- policyFlags |= POLICY_FLAG_VIRTUAL;
- flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
- }
-
+void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
+ uint32_t& policyFlags) {
// Policy:
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
@@ -802,21 +789,30 @@
const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
const int32_t WM_ACTION_GO_TO_SLEEP = 4;
+ nsecs_t when = keyEvent->getEventTime();
bool isScreenOn = this->isScreenOn();
bool isScreenBright = this->isScreenBright();
JNIEnv* env = jniEnv();
- jint wmActions = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.interceptKeyBeforeQueueing,
- when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
- if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ jint wmActions;
+ if (keyEventObj) {
+ wmActions = env->CallIntMethod(mCallbacksObj,
+ gCallbacksClassInfo.interceptKeyBeforeQueueing,
+ keyEventObj, policyFlags, isScreenOn);
+ if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+ wmActions = 0;
+ }
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ } else {
+ LOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
- if (!(flags & POLICY_FLAG_INJECTED)) {
+ if (!(policyFlags & POLICY_FLAG_INJECTED)) {
if (!isScreenOn) {
policyFlags |= POLICY_FLAG_WOKE_HERE;
- flags |= AKEY_EVENT_FLAG_WOKE_HERE;
}
if (!isScreenBright) {
@@ -841,10 +837,6 @@
}
void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags);
-#endif
-
// Policy:
// - Ignore untrusted events and pass them along.
// - No special filtering for injected events required at this time.
@@ -869,46 +861,62 @@
// - Ignore untrusted events and pass them along.
// - Filter normal events and trusted injected events through the window manager policy to
// handle the HOME key and the like.
+ bool result;
if (policyFlags & POLICY_FLAG_TRUSTED) {
JNIEnv* env = jniEnv();
// Note: inputChannel may be null.
jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
- jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
- gCallbacksClassInfo.interceptKeyBeforeDispatching,
- inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), policyFlags);
- bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ if (keyEventObj) {
+ jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
+ gCallbacksClassInfo.interceptKeyBeforeDispatching,
+ inputChannelObj, keyEventObj, policyFlags);
+ bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ result = consumed && !error;
+ } else {
+ LOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
+ result = false;
+ }
env->DeleteLocalRef(inputChannelObj);
- return consumed && ! error;
} else {
- return false;
+ result = false;
}
+ return result;
}
bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) {
// Policy:
// - Ignore untrusted events and do not perform default handling.
+ bool result;
if (policyFlags & POLICY_FLAG_TRUSTED) {
JNIEnv* env = jniEnv();
// Note: inputChannel may be null.
jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
- jboolean handled = env->CallBooleanMethod(mCallbacksObj,
- gCallbacksClassInfo.dispatchUnhandledKey,
- inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), policyFlags);
- bool error = checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ if (keyEventObj) {
+ jboolean handled = env->CallBooleanMethod(mCallbacksObj,
+ gCallbacksClassInfo.dispatchUnhandledKey,
+ inputChannelObj, keyEventObj, policyFlags);
+ bool error = checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ result = handled && !error;
+ } else {
+ LOGE("Failed to obtain key event object for dispatchUnhandledKey.");
+ result = false;
+ }
env->DeleteLocalRef(inputChannelObj);
- return handled && ! error;
} else {
- return false;
+ result = false;
}
+ return result;
}
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
@@ -1107,13 +1115,21 @@
if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
KeyEvent keyEvent;
- android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
+ status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
+ if (status) {
+ jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
& keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
MotionEvent motionEvent;
- android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
+ status_t status = android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
+ if (status) {
+ jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
& motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
@@ -1332,13 +1348,14 @@
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
- "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
+ "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
- "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIIII)Z");
+ "interceptKeyBeforeDispatching",
+ "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z");
GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz,
- "dispatchUnhandledKey", "(Landroid/view/InputChannel;IIIIIII)Z");
+ "dispatchUnhandledKey", "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z");
GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
"checkInjectEventsPermission", "(II)Z");