summaryrefslogtreecommitdiffstats
path: root/core/jni/android_view_InputEventReceiver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/jni/android_view_InputEventReceiver.cpp')
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp192
1 files changed, 112 insertions, 80 deletions
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 23e1590..4b737ed 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -40,6 +40,7 @@ static struct {
jclass clazz;
jmethodID dispatchInputEvent;
+ jmethodID dispatchBatchedInputEventPending;
} gInputEventReceiverClassInfo;
@@ -50,7 +51,8 @@ public:
const sp<Looper>& looper);
status_t initialize();
- status_t finishInputEvent(bool handled);
+ status_t finishInputEvent(uint32_t seq, bool handled);
+ status_t consumeEvents(bool consumeBatches);
static int handleReceiveCallback(int receiveFd, int events, void* data);
protected:
@@ -60,8 +62,8 @@ private:
jobject mReceiverObjGlobal;
InputConsumer mInputConsumer;
sp<Looper> mLooper;
- bool mEventInProgress;
PreallocatedInputEventFactory mInputEventFactory;
+ bool mBatchedInputEventPending;
const char* getInputChannelName() {
return mInputConsumer.getChannel()->getName().string();
@@ -72,7 +74,8 @@ private:
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mInputConsumer(inputChannel), mLooper(looper), mEventInProgress(false) {
+ mInputConsumer(inputChannel), mLooper(looper),
+ mBatchedInputEventPending(false) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
#endif
@@ -84,9 +87,6 @@ NativeInputEventReceiver::~NativeInputEventReceiver() {
#endif
mLooper->removeFd(mInputConsumer.getChannel()->getFd());
- if (mEventInProgress) {
- mInputConsumer.sendFinishedSignal(false); // ignoring result
- }
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mReceiverObjGlobal);
@@ -98,23 +98,17 @@ status_t NativeInputEventReceiver::initialize() {
return OK;
}
-status_t NativeInputEventReceiver::finishInputEvent(bool handled) {
- if (mEventInProgress) {
+status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
+ ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
#endif
- mEventInProgress = false;
- status_t status = mInputConsumer.sendFinishedSignal(handled);
- if (status) {
- ALOGW("Failed to send finished signal on channel '%s'. status=%d",
- getInputChannelName(), status);
- }
- return status;
- } else {
- ALOGW("Ignoring attempt to finish input event while no event is in progress.");
- return OK;
+ status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
+ if (status) {
+ ALOGW("Failed to send finished signal on channel '%s'. status=%d",
+ getInputChannelName(), status);
}
+ return status;
}
int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -132,79 +126,101 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v
return 1;
}
- if (r->mEventInProgress) {
- ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
- r->getInputChannelName());
- return 1;
- }
+ status_t status = r->consumeEvents(false /*consumeBatches*/);
+ return status == OK || status == NO_MEMORY ? 1 : 0;
+}
- InputEvent* inputEvent;
- status_t status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent);
- if (status) {
- ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
- r->getInputChannelName(), status);
- r->mInputConsumer.sendFinishedSignal(false);
- return 1;
+status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) {
+#if DEBUG_DISPATCH_CYCLE
+ ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s.", getInputChannelName(),
+ consumeBatches ? "true" : "false");
+#endif
+
+ if (consumeBatches) {
+ mBatchedInputEventPending = false;
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject inputEventObj;
- switch (inputEvent->getType()) {
- case AINPUT_EVENT_TYPE_KEY:
+ for (;;) {
+ uint32_t seq;
+ InputEvent* inputEvent;
+ status_t status = mInputConsumer.consume(&mInputEventFactory,
+ consumeBatches, &seq, &inputEvent);
+ if (status) {
+ if (status == WOULD_BLOCK) {
+ if (mInputConsumer.hasPendingBatch() && !mBatchedInputEventPending) {
+ // There is a pending batch. Come back later.
+ mBatchedInputEventPending = true;
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Received key event.",
- r->getInputChannelName());
+ ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
+ getInputChannelName());
#endif
- inputEventObj = android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- break;
+ env->CallVoidMethod(mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
+
+ if (env->ExceptionCheck()) {
+ ALOGE("channel '%s' ~ An exception occurred while dispatching that "
+ "batched input events are pending.", getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
+ mBatchedInputEventPending = false; // try again later
+ }
+ }
+ return OK;
+ }
+ ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
+ getInputChannelName(), status);
+ return status;
+ }
+ assert(inputEvent);
- case AINPUT_EVENT_TYPE_MOTION:
+ jobject inputEventObj;
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY:
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Received motion event.",
- r->getInputChannelName());
+ ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
#endif
- inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
- static_cast<MotionEvent*>(inputEvent));
- break;
+ inputEventObj = android_view_KeyEvent_fromNative(env,
+ static_cast<KeyEvent*>(inputEvent));
+ break;
- default:
- assert(false); // InputConsumer should prevent this from ever happening
- inputEventObj = NULL;
- }
+ case AINPUT_EVENT_TYPE_MOTION:
+#if DEBUG_DISPATCH_CYCLE
+ ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
+#endif
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<MotionEvent*>(inputEvent));
+ break;
- if (!inputEventObj) {
- ALOGW("channel '%s' ~ Failed to obtain event object.",
- r->getInputChannelName());
- r->mInputConsumer.sendFinishedSignal(false);
- return 1;
- }
+ default:
+ assert(false); // InputConsumer should prevent this from ever happening
+ inputEventObj = NULL;
+ }
- r->mEventInProgress = true;
+ if (!inputEventObj) {
+ ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
+ mInputConsumer.sendFinishedSignal(seq, false);
+ return NO_MEMORY;
+ }
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Invoking input handler.", r->getInputChannelName());
-#endif
- env->CallVoidMethod(r->mReceiverObjGlobal,
- gInputEventReceiverClassInfo.dispatchInputEvent, inputEventObj);
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Returned from input handler.", r->getInputChannelName());
+ ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
#endif
+ env->CallVoidMethod(mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
- if (env->ExceptionCheck()) {
- ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
- r->getInputChannelName());
- LOGE_EX(env);
- env->ExceptionClear();
+ env->DeleteLocalRef(inputEventObj);
- if (r->mEventInProgress) {
- r->mInputConsumer.sendFinishedSignal(false);
- r->mEventInProgress = false;
+ if (env->ExceptionCheck()) {
+ ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
+ getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
+
+ mInputConsumer.sendFinishedSignal(seq, false);
+ return OK;
}
}
-
- env->DeleteLocalRef(inputEventObj);
- return 1;
}
@@ -243,10 +259,11 @@ static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
}
-static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, jboolean handled) {
+static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
+ jint seq, jboolean handled) {
sp<NativeInputEventReceiver> receiver =
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
- status_t status = receiver->finishInputEvent(handled);
+ status_t status = receiver->finishInputEvent(seq, handled);
if (status) {
String8 message;
message.appendFormat("Failed to finish input event. status=%d", status);
@@ -254,17 +271,29 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
}
}
+static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ status_t status = receiver->consumeEvents(true /*consumeBatches*/);
+ if (status) {
+ String8 message;
+ message.appendFormat("Failed to consume batched input event. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ }
+}
+
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
(void*)nativeInit },
- { "nativeDispose",
- "(I)V",
+ { "nativeDispose", "(I)V",
(void*)nativeDispose },
- { "nativeFinishInputEvent", "(IZ)V",
- (void*)nativeFinishInputEvent }
+ { "nativeFinishInputEvent", "(IIZ)V",
+ (void*)nativeFinishInputEvent },
+ { "nativeConsumeBatchedInputEvents", "(I)V",
+ (void*)nativeConsumeBatchedInputEvents },
};
#define FIND_CLASS(var, className) \
@@ -285,7 +314,10 @@ int register_android_view_InputEventReceiver(JNIEnv* env) {
GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
gInputEventReceiverClassInfo.clazz,
- "dispatchInputEvent", "(Landroid/view/InputEvent;)V");
+ "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
+ GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchBatchedInputEventPending,
+ gInputEventReceiverClassInfo.clazz,
+ "dispatchBatchedInputEventPending", "()V");
return 0;
}