Implement native key pre-dispatching to IMEs.
This significantly re-works the native key dispatching code to
allow events to be pre-dispatched to the current IME before
being processed by native code. It introduces one new public
API, which must be called after retrieving an event if the app
wishes for it to be pre-dispatched.
Currently the native code will only do pre-dispatching of
system keys, to avoid significant overhead for gaming input.
This should be improved to be smarted, filtering for only
keys that the IME is interested in. Unfortunately IMEs don't
currently provide this information. :p
Change-Id: Ic1c7aeec8b348164957f2cd88119eb5bd85c2a9f
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index d7a9a2c..c388ba8 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -42,8 +42,26 @@
/*
* NDK input queue API.
+ *
+ * Here is the event flow:
+ * 1. Event arrives in input consumer, and is returned by getEvent().
+ * 2. Application calls preDispatchEvent():
+ * a. Event is assigned a sequence ID and enqueued in mPreDispatchingKeys.
+ * b. Main thread picks up event, hands to input method.
+ * c. Input method eventually returns sequence # and whether it was handled.
+ * d. finishPreDispatch() is called to enqueue the information.
+ * e. next getEvent() call will:
+ * - finish any pre-dispatch events that the input method handled
+ * - return the next pre-dispatched event that the input method didn't handle.
+ * f. (A preDispatchEvent() call on this event will now return false).
+ * 3. Application calls finishEvent() with whether it was handled.
+ * - If handled is true, the event is finished.
+ * - If handled is false, the event is put on mUnhandledKeys, and:
+ * a. Main thread receives event from consumeUnhandledEvent().
+ * b. Java sends event through default key handler.
+ * c. event is finished.
*/
-struct AInputQueue {
+struct AInputQueue : public android::InputEventFactoryInterface {
public:
/* Creates a consumer associated with an input channel. */
explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite);
@@ -59,8 +77,9 @@
int32_t getEvent(AInputEvent** outEvent);
- void finishEvent(AInputEvent* event, bool handled);
+ bool preDispatchEvent(AInputEvent* event);
+ void finishEvent(AInputEvent* event, bool handled);
// ----------------------------------------------------------
@@ -68,28 +87,63 @@
void dispatchEvent(android::KeyEvent* event);
+ void finishPreDispatch(int seq, bool handled);
+
android::KeyEvent* consumeUnhandledEvent();
+ android::KeyEvent* consumePreDispatchingEvent(int* outSeq);
+
+ virtual android::KeyEvent* createKeyEvent();
+ virtual android::MotionEvent* createMotionEvent();
int mWorkWrite;
private:
- void doDefaultKey(android::KeyEvent* keyEvent);
+ void doUnhandledKey(android::KeyEvent* keyEvent);
+ bool preDispatchKey(android::KeyEvent* keyEvent);
+ void wakeupDispatch();
android::InputConsumer mConsumer;
- android::PreallocatedInputEventFactory mInputEventFactory;
android::sp<android::PollLoop> mPollLoop;
int mDispatchKeyRead;
int mDispatchKeyWrite;
- // This is only touched by the event reader thread. It is the current
- // key events that came out of the mDispatchingKeys list and are now
- //Êdelivered to the app.
- android::Vector<android::KeyEvent*> mDeliveringKeys;
+ struct in_flight_event {
+ android::InputEvent* event;
+ int seq;
+ bool doFinish;
+ };
+
+ struct finish_pre_dispatch {
+ int seq;
+ bool handled;
+ };
android::Mutex mLock;
- android::Vector<android::KeyEvent*> mPendingKeys;
+
+ 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;
+
+ // Key events that the app didn't handle, and are pending for
+ // delivery to the activity's default key handling.
+ android::Vector<android::KeyEvent*> mUnhandledKeys;
+
+ // Keys that arrived in the Java framework and need to be
+ // dispatched to the app.
android::Vector<android::KeyEvent*> mDispatchingKeys;
+
+ // Key events that are pending to be pre-dispatched to the IME.
+ android::Vector<in_flight_event> mPreDispatchingKeys;
+
+ // Event sequence numbers that we have finished pre-dispatching.
+ android::Vector<finish_pre_dispatch> mFinishPreDispatches;
};
#endif // _ANDROID_APP_NATIVEACTIVITY_H
diff --git a/include/ui/Input.h b/include/ui/Input.h
index f069888..d9b1091 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -152,6 +152,7 @@
protected:
void initialize(int32_t deviceId, int32_t source);
+ void initialize(const InputEvent& from);
private:
int32_t mDeviceId;
@@ -202,6 +203,7 @@
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime);
+ void initialize(const KeyEvent& from);
private:
int32_t mAction;