Loading core/jni/android_app_NativeActivity.cpp +32 −56 Original line number Diff line number Diff line Loading @@ -162,12 +162,12 @@ int32_t AInputQueue::hasEvents() { int32_t AInputQueue::getEvent(AInputEvent** outEvent) { *outEvent = NULL; bool finishNow = false; char byteread; ssize_t nRead = read(mDispatchKeyRead, &byteread, 1); Mutex::Autolock _l(mLock); if (nRead == 1) { mLock.lock(); if (mDispatchingKeys.size() > 0) { KeyEvent* kevent = mDispatchingKeys[0]; *outEvent = kevent; Loading @@ -178,6 +178,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { inflight.finishSeq = 0; mInFlightEvents.push(inflight); } bool finishNow = false; if (mFinishPreDispatches.size() > 0) { finish_pre_dispatch finish(mFinishPreDispatches[0]); mFinishPreDispatches.removeAt(0); Loading @@ -193,7 +195,6 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { ALOGW("getEvent couldn't find inflight for seq %d", finish.seq); } } mLock.unlock(); if (finishNow) { finishEvent(*outEvent, true, false); Loading @@ -206,7 +207,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { uint32_t consumerSeq; InputEvent* myEvent = NULL; status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent); status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/, &consumerSeq, &myEvent); if (res != android::OK) { if (res != android::WOULD_BLOCK) { ALOGW("channel '%s' ~ Failed to consume input event. status=%d", Loading @@ -215,6 +217,10 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { return -1; } if (mConsumer.hasDeferredEvent()) { wakeupDispatchLocked(); } in_flight_event inflight; inflight.event = myEvent; inflight.seq = -1; Loading Loading @@ -255,7 +261,8 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH return; } mLock.lock(); Mutex::Autolock _l(mLock); const size_t N = mInFlightEvents.size(); for (size_t i=0; i<N; i++) { const in_flight_event& inflight(mInFlightEvents[i]); Loading @@ -267,111 +274,82 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH mConsumer.getChannel()->getName().string(), res); } } if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) { mAvailKeyEvents.push(static_cast<KeyEvent*>(event)); } else { mAvailMotionEvents.push(static_cast<MotionEvent*>(event)); } mPooledInputEventFactory.recycle(static_cast<InputEvent*>(event)); mInFlightEvents.removeAt(i); mLock.unlock(); return; } } mLock.unlock(); ALOGW("finishEvent called for unknown event: %p", event); } void AInputQueue::dispatchEvent(android::KeyEvent* event) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(), mDispatchKeyWrite); mDispatchingKeys.add(event); wakeupDispatch(); mLock.unlock(); wakeupDispatchLocked(); } void AInputQueue::finishPreDispatch(int seq, bool handled) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0); finish_pre_dispatch finish; finish.seq = seq; finish.handled = handled; mFinishPreDispatches.add(finish); wakeupDispatch(); mLock.unlock(); wakeupDispatchLocked(); } KeyEvent* AInputQueue::consumeUnhandledEvent() { KeyEvent* event = NULL; Mutex::Autolock _l(mLock); mLock.lock(); KeyEvent* event = NULL; if (mUnhandledKeys.size() > 0) { event = mUnhandledKeys[0]; mUnhandledKeys.removeAt(0); } mLock.unlock(); LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event); return event; } KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) { KeyEvent* event = NULL; Mutex::Autolock _l(mLock); mLock.lock(); KeyEvent* event = NULL; if (mPreDispatchingKeys.size() > 0) { const in_flight_event& inflight(mPreDispatchingKeys[0]); event = static_cast<KeyEvent*>(inflight.event); *outSeq = inflight.seq; mPreDispatchingKeys.removeAt(0); } mLock.unlock(); LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event); return event; } KeyEvent* AInputQueue::createKeyEvent() { mLock.lock(); KeyEvent* event; if (mAvailKeyEvents.size() <= 0) { event = new KeyEvent(); } else { event = mAvailKeyEvents.top(); mAvailKeyEvents.pop(); } mLock.unlock(); return event; } Mutex::Autolock _l(mLock); MotionEvent* AInputQueue::createMotionEvent() { mLock.lock(); MotionEvent* event; if (mAvailMotionEvents.size() <= 0) { event = new MotionEvent(); } else { event = mAvailMotionEvents.top(); mAvailMotionEvents.pop(); } mLock.unlock(); return event; return mPooledInputEventFactory.createKeyEvent(); } void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite); if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) { write_work(mWorkWrite, CMD_DEF_KEY); } mUnhandledKeys.add(keyEvent); mLock.unlock(); } bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite); const size_t N = mInFlightEvents.size(); for (size_t i=0; i<N; i++) { Loading @@ -380,7 +358,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { if (inflight.seq >= 0) { // This event has already been pre-dispatched! LOG_TRACE("Event already pre-dispatched!"); mLock.unlock(); return false; } mSeq++; Loading @@ -391,7 +368,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { write_work(mWorkWrite, CMD_DEF_KEY); } mPreDispatchingKeys.add(inflight); mLock.unlock(); return true; } } Loading @@ -400,7 +376,7 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { return false; } void AInputQueue::wakeupDispatch() { void AInputQueue::wakeupDispatchLocked() { restart: char dummy = 0; int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy)); Loading include/android_runtime/android_app_NativeActivity.h +4 −9 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ extern void android_NativeActivity_hideSoftInput( * b. Java sends event through default key handler. * c. event is finished. */ struct AInputQueue : public android::InputEventFactoryInterface { struct AInputQueue { public: /* Creates a consumer associated with an input channel. */ explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite); Loading Loading @@ -96,16 +96,16 @@ public: android::KeyEvent* consumeUnhandledEvent(); android::KeyEvent* consumePreDispatchingEvent(int* outSeq); virtual android::KeyEvent* createKeyEvent(); virtual android::MotionEvent* createMotionEvent(); android::KeyEvent* createKeyEvent(); int mWorkWrite; private: void doUnhandledKey(android::KeyEvent* keyEvent); bool preDispatchKey(android::KeyEvent* keyEvent); void wakeupDispatch(); void wakeupDispatchLocked(); android::PooledInputEventFactory mPooledInputEventFactory; android::InputConsumer mConsumer; android::sp<android::Looper> mLooper; Loading @@ -127,11 +127,6 @@ private: int mSeq; // Cache of previously allocated key events. android::Vector<android::KeyEvent*> mAvailKeyEvents; // Cache of previously allocated motion events. android::Vector<android::MotionEvent*> mAvailMotionEvents; // All input events that are actively being processed. android::Vector<in_flight_event> mInFlightEvents; Loading include/androidfw/Input.h +20 −0 Original line number Diff line number Diff line Loading @@ -615,6 +615,26 @@ private: MotionEvent mMotionEvent; }; /* * An input event factory implementation that maintains a pool of input events. */ class PooledInputEventFactory : public InputEventFactoryInterface { public: PooledInputEventFactory(size_t maxPoolSize = 20); virtual ~PooledInputEventFactory(); virtual KeyEvent* createKeyEvent(); virtual MotionEvent* createMotionEvent(); void recycle(InputEvent* event); private: const size_t mMaxPoolSize; Vector<KeyEvent*> mKeyEventPool; Vector<MotionEvent*> mMotionEventPool; }; /* * Calculates the velocity of pointer movements over time. */ Loading include/androidfw/InputTransport.h +23 −1 Original line number Diff line number Diff line Loading @@ -292,7 +292,29 @@ public: */ status_t sendFinishedSignal(uint32_t seq, bool handled); /* Returns true if there is a pending batch. */ /* Returns true if there is a deferred event waiting. * * Should be called after calling consume() to determine whether the consumer * has a deferred event to be processed. Deferred events are somewhat special in * that they have already been removed from the input channel. If the input channel * becomes empty, the client may need to do extra work to ensure that it processes * the deferred event despite the fact that the inptu channel's file descriptor * is not readable. * * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. * This guarantees that all deferred events will be processed. * * Alternately, the caller can call hasDeferredEvent() to determine whether there is * a deferred event waiting and then ensure that its event loop wakes up at least * one more time to consume the deferred event. */ bool hasDeferredEvent() const; /* Returns true if there is a pending batch. * * Should be called after calling consume() with consumeBatches == false to determine * whether consume() should be called again later on with consumeBatches == true. */ bool hasPendingBatch() const; private: Loading libs/androidfw/Input.cpp +52 −0 Original line number Diff line number Diff line Loading @@ -683,6 +683,58 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { } // --- PooledInputEventFactory --- PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : mMaxPoolSize(maxPoolSize) { } PooledInputEventFactory::~PooledInputEventFactory() { for (size_t i = 0; i < mKeyEventPool.size(); i++) { delete mKeyEventPool.itemAt(i); } for (size_t i = 0; i < mMotionEventPool.size(); i++) { delete mMotionEventPool.itemAt(i); } } KeyEvent* PooledInputEventFactory::createKeyEvent() { if (!mKeyEventPool.isEmpty()) { KeyEvent* event = mKeyEventPool.top(); mKeyEventPool.pop(); return event; } return new KeyEvent(); } MotionEvent* PooledInputEventFactory::createMotionEvent() { if (!mMotionEventPool.isEmpty()) { MotionEvent* event = mMotionEventPool.top(); mMotionEventPool.pop(); return event; } return new MotionEvent(); } void PooledInputEventFactory::recycle(InputEvent* event) { switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: if (mKeyEventPool.size() < mMaxPoolSize) { mKeyEventPool.push(static_cast<KeyEvent*>(event)); return; } break; case AINPUT_EVENT_TYPE_MOTION: if (mMotionEventPool.size() < mMaxPoolSize) { mMotionEventPool.push(static_cast<MotionEvent*>(event)); return; } break; } delete event; } // --- VelocityTracker --- const uint32_t VelocityTracker::DEFAULT_DEGREE; Loading Loading
core/jni/android_app_NativeActivity.cpp +32 −56 Original line number Diff line number Diff line Loading @@ -162,12 +162,12 @@ int32_t AInputQueue::hasEvents() { int32_t AInputQueue::getEvent(AInputEvent** outEvent) { *outEvent = NULL; bool finishNow = false; char byteread; ssize_t nRead = read(mDispatchKeyRead, &byteread, 1); Mutex::Autolock _l(mLock); if (nRead == 1) { mLock.lock(); if (mDispatchingKeys.size() > 0) { KeyEvent* kevent = mDispatchingKeys[0]; *outEvent = kevent; Loading @@ -178,6 +178,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { inflight.finishSeq = 0; mInFlightEvents.push(inflight); } bool finishNow = false; if (mFinishPreDispatches.size() > 0) { finish_pre_dispatch finish(mFinishPreDispatches[0]); mFinishPreDispatches.removeAt(0); Loading @@ -193,7 +195,6 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { ALOGW("getEvent couldn't find inflight for seq %d", finish.seq); } } mLock.unlock(); if (finishNow) { finishEvent(*outEvent, true, false); Loading @@ -206,7 +207,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { uint32_t consumerSeq; InputEvent* myEvent = NULL; status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent); status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/, &consumerSeq, &myEvent); if (res != android::OK) { if (res != android::WOULD_BLOCK) { ALOGW("channel '%s' ~ Failed to consume input event. status=%d", Loading @@ -215,6 +217,10 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) { return -1; } if (mConsumer.hasDeferredEvent()) { wakeupDispatchLocked(); } in_flight_event inflight; inflight.event = myEvent; inflight.seq = -1; Loading Loading @@ -255,7 +261,8 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH return; } mLock.lock(); Mutex::Autolock _l(mLock); const size_t N = mInFlightEvents.size(); for (size_t i=0; i<N; i++) { const in_flight_event& inflight(mInFlightEvents[i]); Loading @@ -267,111 +274,82 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH mConsumer.getChannel()->getName().string(), res); } } if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) { mAvailKeyEvents.push(static_cast<KeyEvent*>(event)); } else { mAvailMotionEvents.push(static_cast<MotionEvent*>(event)); } mPooledInputEventFactory.recycle(static_cast<InputEvent*>(event)); mInFlightEvents.removeAt(i); mLock.unlock(); return; } } mLock.unlock(); ALOGW("finishEvent called for unknown event: %p", event); } void AInputQueue::dispatchEvent(android::KeyEvent* event) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(), mDispatchKeyWrite); mDispatchingKeys.add(event); wakeupDispatch(); mLock.unlock(); wakeupDispatchLocked(); } void AInputQueue::finishPreDispatch(int seq, bool handled) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0); finish_pre_dispatch finish; finish.seq = seq; finish.handled = handled; mFinishPreDispatches.add(finish); wakeupDispatch(); mLock.unlock(); wakeupDispatchLocked(); } KeyEvent* AInputQueue::consumeUnhandledEvent() { KeyEvent* event = NULL; Mutex::Autolock _l(mLock); mLock.lock(); KeyEvent* event = NULL; if (mUnhandledKeys.size() > 0) { event = mUnhandledKeys[0]; mUnhandledKeys.removeAt(0); } mLock.unlock(); LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event); return event; } KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) { KeyEvent* event = NULL; Mutex::Autolock _l(mLock); mLock.lock(); KeyEvent* event = NULL; if (mPreDispatchingKeys.size() > 0) { const in_flight_event& inflight(mPreDispatchingKeys[0]); event = static_cast<KeyEvent*>(inflight.event); *outSeq = inflight.seq; mPreDispatchingKeys.removeAt(0); } mLock.unlock(); LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event); return event; } KeyEvent* AInputQueue::createKeyEvent() { mLock.lock(); KeyEvent* event; if (mAvailKeyEvents.size() <= 0) { event = new KeyEvent(); } else { event = mAvailKeyEvents.top(); mAvailKeyEvents.pop(); } mLock.unlock(); return event; } Mutex::Autolock _l(mLock); MotionEvent* AInputQueue::createMotionEvent() { mLock.lock(); MotionEvent* event; if (mAvailMotionEvents.size() <= 0) { event = new MotionEvent(); } else { event = mAvailMotionEvents.top(); mAvailMotionEvents.pop(); } mLock.unlock(); return event; return mPooledInputEventFactory.createKeyEvent(); } void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite); if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) { write_work(mWorkWrite, CMD_DEF_KEY); } mUnhandledKeys.add(keyEvent); mLock.unlock(); } bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { mLock.lock(); Mutex::Autolock _l(mLock); LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite); const size_t N = mInFlightEvents.size(); for (size_t i=0; i<N; i++) { Loading @@ -380,7 +358,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { if (inflight.seq >= 0) { // This event has already been pre-dispatched! LOG_TRACE("Event already pre-dispatched!"); mLock.unlock(); return false; } mSeq++; Loading @@ -391,7 +368,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { write_work(mWorkWrite, CMD_DEF_KEY); } mPreDispatchingKeys.add(inflight); mLock.unlock(); return true; } } Loading @@ -400,7 +376,7 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) { return false; } void AInputQueue::wakeupDispatch() { void AInputQueue::wakeupDispatchLocked() { restart: char dummy = 0; int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy)); Loading
include/android_runtime/android_app_NativeActivity.h +4 −9 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ extern void android_NativeActivity_hideSoftInput( * b. Java sends event through default key handler. * c. event is finished. */ struct AInputQueue : public android::InputEventFactoryInterface { struct AInputQueue { public: /* Creates a consumer associated with an input channel. */ explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite); Loading Loading @@ -96,16 +96,16 @@ public: android::KeyEvent* consumeUnhandledEvent(); android::KeyEvent* consumePreDispatchingEvent(int* outSeq); virtual android::KeyEvent* createKeyEvent(); virtual android::MotionEvent* createMotionEvent(); android::KeyEvent* createKeyEvent(); int mWorkWrite; private: void doUnhandledKey(android::KeyEvent* keyEvent); bool preDispatchKey(android::KeyEvent* keyEvent); void wakeupDispatch(); void wakeupDispatchLocked(); android::PooledInputEventFactory mPooledInputEventFactory; android::InputConsumer mConsumer; android::sp<android::Looper> mLooper; Loading @@ -127,11 +127,6 @@ private: int mSeq; // Cache of previously allocated key events. android::Vector<android::KeyEvent*> mAvailKeyEvents; // Cache of previously allocated motion events. android::Vector<android::MotionEvent*> mAvailMotionEvents; // All input events that are actively being processed. android::Vector<in_flight_event> mInFlightEvents; Loading
include/androidfw/Input.h +20 −0 Original line number Diff line number Diff line Loading @@ -615,6 +615,26 @@ private: MotionEvent mMotionEvent; }; /* * An input event factory implementation that maintains a pool of input events. */ class PooledInputEventFactory : public InputEventFactoryInterface { public: PooledInputEventFactory(size_t maxPoolSize = 20); virtual ~PooledInputEventFactory(); virtual KeyEvent* createKeyEvent(); virtual MotionEvent* createMotionEvent(); void recycle(InputEvent* event); private: const size_t mMaxPoolSize; Vector<KeyEvent*> mKeyEventPool; Vector<MotionEvent*> mMotionEventPool; }; /* * Calculates the velocity of pointer movements over time. */ Loading
include/androidfw/InputTransport.h +23 −1 Original line number Diff line number Diff line Loading @@ -292,7 +292,29 @@ public: */ status_t sendFinishedSignal(uint32_t seq, bool handled); /* Returns true if there is a pending batch. */ /* Returns true if there is a deferred event waiting. * * Should be called after calling consume() to determine whether the consumer * has a deferred event to be processed. Deferred events are somewhat special in * that they have already been removed from the input channel. If the input channel * becomes empty, the client may need to do extra work to ensure that it processes * the deferred event despite the fact that the inptu channel's file descriptor * is not readable. * * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. * This guarantees that all deferred events will be processed. * * Alternately, the caller can call hasDeferredEvent() to determine whether there is * a deferred event waiting and then ensure that its event loop wakes up at least * one more time to consume the deferred event. */ bool hasDeferredEvent() const; /* Returns true if there is a pending batch. * * Should be called after calling consume() with consumeBatches == false to determine * whether consume() should be called again later on with consumeBatches == true. */ bool hasPendingBatch() const; private: Loading
libs/androidfw/Input.cpp +52 −0 Original line number Diff line number Diff line Loading @@ -683,6 +683,58 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { } // --- PooledInputEventFactory --- PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : mMaxPoolSize(maxPoolSize) { } PooledInputEventFactory::~PooledInputEventFactory() { for (size_t i = 0; i < mKeyEventPool.size(); i++) { delete mKeyEventPool.itemAt(i); } for (size_t i = 0; i < mMotionEventPool.size(); i++) { delete mMotionEventPool.itemAt(i); } } KeyEvent* PooledInputEventFactory::createKeyEvent() { if (!mKeyEventPool.isEmpty()) { KeyEvent* event = mKeyEventPool.top(); mKeyEventPool.pop(); return event; } return new KeyEvent(); } MotionEvent* PooledInputEventFactory::createMotionEvent() { if (!mMotionEventPool.isEmpty()) { MotionEvent* event = mMotionEventPool.top(); mMotionEventPool.pop(); return event; } return new MotionEvent(); } void PooledInputEventFactory::recycle(InputEvent* event) { switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: if (mKeyEventPool.size() < mMaxPoolSize) { mKeyEventPool.push(static_cast<KeyEvent*>(event)); return; } break; case AINPUT_EVENT_TYPE_MOTION: if (mMotionEventPool.size() < mMaxPoolSize) { mMotionEventPool.push(static_cast<MotionEvent*>(event)); return; } break; } delete event; } // --- VelocityTracker --- const uint32_t VelocityTracker::DEFAULT_DEGREE; Loading