diff options
| -rw-r--r-- | core/jni/android_view_InputEventReceiver.cpp | 93 |
1 files changed, 82 insertions, 11 deletions
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index c350521..8e1e04a 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -27,6 +27,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> #include <utils/Looper.h> +#include <utils/Vector.h> #include <utils/threads.h> #include <androidfw/InputTransport.h> #include "android_os_MessageQueue.h" @@ -61,11 +62,20 @@ protected: virtual ~NativeInputEventReceiver(); private: + struct Finish { + uint32_t seq; + bool handled; + }; + jobject mReceiverWeakGlobal; InputConsumer mInputConsumer; sp<MessageQueue> mMessageQueue; PreallocatedInputEventFactory mInputEventFactory; bool mBatchedInputEventPending; + int mFdEvents; + Vector<Finish> mFinishQueue; + + void setFdEvents(int events); const char* getInputChannelName() { return mInputConsumer.getChannel()->getName().string(); @@ -80,7 +90,7 @@ NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env, const sp<MessageQueue>& messageQueue) : mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), mInputConsumer(inputChannel), mMessageQueue(messageQueue), - mBatchedInputEventPending(false) { + mBatchedInputEventPending(false), mFdEvents(0) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName()); #endif @@ -92,8 +102,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() { } status_t NativeInputEventReceiver::initialize() { - int receiveFd = mInputConsumer.getChannel()->getFd(); - mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL); + setFdEvents(ALOOPER_EVENT_INPUT); return OK; } @@ -102,7 +111,7 @@ void NativeInputEventReceiver::dispose() { ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName()); #endif - mMessageQueue->getLooper()->removeFd(mInputConsumer.getChannel()->getFd()); + setFdEvents(0); } status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) { @@ -112,12 +121,38 @@ status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) status_t status = mInputConsumer.sendFinishedSignal(seq, handled); if (status) { + if (status == WOULD_BLOCK) { +#if DEBUG_DISPATCH_CYCLE + ALOGD("channel '%s' ~ Could not send finished signal immediately. " + "Enqueued for later.", getInputChannelName()); +#endif + Finish finish; + finish.seq = seq; + finish.handled = handled; + mFinishQueue.add(finish); + if (mFinishQueue.size() == 1) { + setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT); + } + return OK; + } ALOGW("Failed to send finished signal on channel '%s'. status=%d", getInputChannelName(), status); } return status; } +void NativeInputEventReceiver::setFdEvents(int events) { + if (mFdEvents != events) { + mFdEvents = events; + int fd = mInputConsumer.getChannel()->getFd(); + if (events) { + mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL); + } else { + mMessageQueue->getLooper()->removeFd(fd); + } + } +} + int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { #if DEBUG_DISPATCH_CYCLE @@ -130,16 +165,52 @@ int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) return 0; // remove the callback } - if (!(events & ALOOPER_EVENT_INPUT)) { - ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", getInputChannelName(), events); + if (events & ALOOPER_EVENT_INPUT) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + status_t status = consumeEvents(env, false /*consumeBatches*/, -1); + mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); + return status == OK || status == NO_MEMORY ? 1 : 0; + } + + if (events & ALOOPER_EVENT_OUTPUT) { + for (size_t i = 0; i < mFinishQueue.size(); i++) { + const Finish& finish = mFinishQueue.itemAt(i); + status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled); + if (status) { + mFinishQueue.removeItemsAt(0, i); + + if (status == WOULD_BLOCK) { +#if DEBUG_DISPATCH_CYCLE + ALOGD("channel '%s' ~ Sent %u queued finish events; %u left.", + getInputChannelName(), i, mFinishQueue.size()); +#endif + return 1; // keep the callback, try again later + } + + ALOGW("Failed to send finished signal on channel '%s'. status=%d", + getInputChannelName(), status); + if (status != DEAD_OBJECT) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + String8 message; + message.appendFormat("Failed to finish input event. status=%d", status); + jniThrowRuntimeException(env, message.string()); + mMessageQueue->raiseAndClearException(env, "finishInputEvent"); + } + return 0; // remove the callback + } + } +#if DEBUG_DISPATCH_CYCLE + ALOGD("channel '%s' ~ Sent %u queued finish events; none left.", + getInputChannelName(), mFinishQueue.size()); +#endif + mFinishQueue.clear(); + setFdEvents(ALOOPER_EVENT_INPUT); return 1; } - JNIEnv* env = AndroidRuntime::getJNIEnv(); - status_t status = consumeEvents(env, false /*consumeBatches*/, -1); - mMessageQueue->raiseAndClearException(env, "handleReceiveCallback"); - return status == OK || status == NO_MEMORY ? 1 : 0; + ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " + "events=0x%x", getInputChannelName(), events); + return 1; } status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, |
