summaryrefslogtreecommitdiffstats
path: root/include/ui/InputDispatcher.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/ui/InputDispatcher.h')
-rw-r--r--include/ui/InputDispatcher.h208
1 files changed, 174 insertions, 34 deletions
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index bde07f2..80a20c9 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -18,7 +18,6 @@
#define _UI_INPUT_DISPATCHER_H
#include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
#include <ui/InputTransport.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
@@ -35,6 +34,82 @@
namespace android {
+/*
+ * An input target specifies how an input event is to be dispatched to a particular window
+ * including the window's input channel, control flags, a timeout, and an X / Y offset to
+ * be added to input event coordinates to compensate for the absolute position of the
+ * window area.
+ */
+struct InputTarget {
+ enum {
+ /* This flag indicates that subsequent event delivery should be held until the
+ * current event is delivered to this target or a timeout occurs. */
+ FLAG_SYNC = 0x01,
+
+ /* This flag indicates that a MotionEvent with ACTION_DOWN falls outside of the area of
+ * this target and so should instead be delivered as an ACTION_OUTSIDE to this target. */
+ FLAG_OUTSIDE = 0x02,
+
+ /* This flag indicates that a KeyEvent or MotionEvent is being canceled.
+ * In the case of a key event, it should be delivered with KeyEvent.FLAG_CANCELED set.
+ * In the case of a motion event, it should be delivered as MotionEvent.ACTION_CANCEL. */
+ FLAG_CANCEL = 0x04
+ };
+
+ // The input channel to be targeted.
+ sp<InputChannel> inputChannel;
+
+ // Flags for the input target.
+ int32_t flags;
+
+ // The timeout for event delivery to this target in nanoseconds. Or -1 if none.
+ nsecs_t timeout;
+
+ // The x and y offset to add to a MotionEvent as it is delivered.
+ // (ignored for KeyEvents)
+ float xOffset, yOffset;
+};
+
+/*
+ * Input dispatcher policy interface.
+ *
+ * The input reader policy is used by the input reader to interact with the Window Manager
+ * and other system components.
+ *
+ * The actual implementation is partially supported by callbacks into the DVM
+ * via JNI. This interface is also mocked in the unit tests.
+ */
+class InputDispatcherPolicyInterface : public virtual RefBase {
+protected:
+ InputDispatcherPolicyInterface() { }
+ virtual ~InputDispatcherPolicyInterface() { }
+
+public:
+ /* Notifies the system that a configuration change has occurred. */
+ virtual void notifyConfigurationChanged(nsecs_t when) = 0;
+
+ /* Notifies the system that an input channel is unrecoverably broken. */
+ virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Notifies the system that an input channel is not responding. */
+ virtual void notifyInputChannelANR(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Notifies the system that an input channel recovered from ANR. */
+ virtual void notifyInputChannelRecoveredFromANR(const sp<InputChannel>& inputChannel) = 0;
+
+ /* Gets the key repeat timeout or -1 if automatic key repeating is disabled. */
+ virtual nsecs_t getKeyRepeatTimeout() = 0;
+
+ /* Gets the input targets for a key event. */
+ virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
+ Vector<InputTarget>& outTargets) = 0;
+
+ /* Gets the input targets for a motion event. */
+ virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+ Vector<InputTarget>& outTargets) = 0;
+};
+
+
/* Notifies the system about input events generated by the input reader.
* The dispatcher is expected to be mostly asynchronous. */
class InputDispatcherInterface : public virtual RefBase {
@@ -51,14 +126,10 @@ public:
virtual void dispatchOnce() = 0;
/* Notifies the dispatcher about new events.
- * The dispatcher will process most of these events asynchronously although some
- * policy processing may occur synchronously.
*
* These methods should only be called on the input reader thread.
*/
- virtual void notifyConfigurationChanged(nsecs_t eventTime,
- int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0;
- virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen) = 0;
+ virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0;
virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0;
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
@@ -76,19 +147,33 @@ public:
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
};
-/* Dispatches events. */
+/* Dispatches events to input targets. Some functions of the input dispatcher, such as
+ * identifying input targets, are controlled by a separate policy object.
+ *
+ * IMPORTANT INVARIANT:
+ * Because the policy can potentially block or cause re-entrance into the input dispatcher,
+ * the input dispatcher never calls into the policy while holding its internal locks.
+ * The implementation is also carefully designed to recover from scenarios such as an
+ * input channel becoming unregistered while identifying input targets or processing timeouts.
+ *
+ * Methods marked 'Locked' must be called with the lock acquired.
+ *
+ * Methods marked 'LockedInterruptible' must be called with the lock acquired but
+ * may during the course of their execution release the lock, call into the policy, and
+ * then reacquire the lock. The caller is responsible for recovering gracefully.
+ *
+ * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa.
+ */
class InputDispatcher : public InputDispatcherInterface {
protected:
virtual ~InputDispatcher();
public:
- explicit InputDispatcher(const sp<InputDispatchPolicyInterface>& policy);
+ explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
virtual void dispatchOnce();
- virtual void notifyConfigurationChanged(nsecs_t eventTime,
- int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig);
- virtual void notifyLidSwitchChanged(nsecs_t eventTime, bool lidOpen);
+ virtual void notifyConfigurationChanged(nsecs_t eventTime);
virtual void notifyAppSwitchComing(nsecs_t eventTime);
virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
@@ -119,12 +204,11 @@ private:
int32_t refCount;
int32_t type;
nsecs_t eventTime;
+
+ bool dispatchInProgress; // initially false, set to true while dispatching
};
struct ConfigurationChangedEntry : EventEntry {
- int32_t touchScreenConfig;
- int32_t keyboardConfig;
- int32_t navigationConfig;
};
struct KeyEntry : EventEntry {
@@ -165,6 +249,7 @@ private:
MotionSample* lastSample;
};
+ // Tracks the progress of dispatching a particular event to a particular connection.
struct DispatchEntry : Link<DispatchEntry> {
EventEntry* eventEntry; // the event to dispatch
int32_t targetFlags;
@@ -189,6 +274,36 @@ private:
MotionSample* tailMotionSample;
};
+ // A command entry captures state and behavior for an action to be performed in the
+ // dispatch loop after the initial processing has taken place. It is essentially
+ // a kind of continuation used to postpone sensitive policy interactions to a point
+ // in the dispatch loop where it is safe to release the lock (generally after finishing
+ // the critical parts of the dispatch cycle).
+ //
+ // The special thing about commands is that they can voluntarily release and reacquire
+ // the dispatcher lock at will. Initially when the command starts running, the
+ // dispatcher lock is held. However, if the command needs to call into the policy to
+ // do some work, it can release the lock, do the work, then reacquire the lock again
+ // before returning.
+ //
+ // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
+ // never calls into the policy while holding its lock.
+ //
+ // Commands are implicitly 'LockedInterruptible'.
+ struct CommandEntry;
+ typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
+
+ struct CommandEntry : Link<CommandEntry> {
+ CommandEntry();
+ ~CommandEntry();
+
+ Command command;
+
+ // parameters for the command (usage varies by command)
+ sp<InputChannel> inputChannel;
+ };
+
+ // Generic queue implementation.
template <typename T>
struct Queue {
T head;
@@ -242,17 +357,17 @@ private:
KeyEntry* obtainKeyEntry();
MotionEntry* obtainMotionEntry();
DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry);
+ CommandEntry* obtainCommandEntry(Command command);
void releaseEventEntry(EventEntry* entry);
void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry);
void releaseKeyEntry(KeyEntry* entry);
void releaseMotionEntry(MotionEntry* entry);
void releaseDispatchEntry(DispatchEntry* entry);
+ void releaseCommandEntry(CommandEntry* entry);
void appendMotionSample(MotionEntry* motionEntry,
nsecs_t eventTime, int32_t pointerCount, const PointerCoords* pointerCoords);
- void freeMotionSample(MotionSample* sample);
- void freeMotionSampleList(MotionSample* head);
private:
Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool;
@@ -260,6 +375,7 @@ private:
Pool<MotionEntry> mMotionEntryPool;
Pool<MotionSample> mMotionSamplePool;
Pool<DispatchEntry> mDispatchEntryPool;
+ Pool<CommandEntry> mCommandEntryPool;
};
/* Manages the dispatch state associated with a single input channel. */
@@ -291,7 +407,9 @@ private:
explicit Connection(const sp<InputChannel>& inputChannel);
- inline const char* getInputChannelName() { return inputChannel->getName().string(); }
+ inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
+
+ const char* getStatusLabel() const;
// Finds a DispatchEntry in the outbound queue associated with the specified event.
// Returns NULL if not found.
@@ -323,22 +441,23 @@ private:
status_t initialize();
};
- sp<InputDispatchPolicyInterface> mPolicy;
+ sp<InputDispatcherPolicyInterface> mPolicy;
Mutex mLock;
- Queue<EventEntry> mInboundQueue;
Allocator mAllocator;
-
sp<PollLoop> mPollLoop;
+ Queue<EventEntry> mInboundQueue;
+ Queue<CommandEntry> mCommandQueue;
+
// All registered connections mapped by receive pipe file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
// Active connections are connections that have a non-empty outbound queue.
Vector<Connection*> mActiveConnections;
- // Pool of key and motion event objects used only to ask the input dispatch policy
+ // Preallocated key and motion event objects used only to ask the input dispatcher policy
// for the targets of an event that is to be dispatched.
KeyEvent mReusableKeyEvent;
MotionEvent mReusableMotionEvent;
@@ -347,6 +466,7 @@ private:
// If there is a synchronous event dispatch in progress, the current input targets will
// remain unchanged until the dispatch has completed or been aborted.
Vector<InputTarget> mCurrentInputTargets;
+ bool mCurrentInputTargetsValid; // false while targets are being recomputed
// Key repeat tracking.
// XXX Move this up to the input reader instead.
@@ -357,17 +477,27 @@ private:
void resetKeyRepeatLocked();
+ // Deferred command processing.
+ bool runCommandsLockedInterruptible();
+ CommandEntry* postCommandLocked(Command command);
+
// Process events that have just been dequeued from the head of the input queue.
- void processConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry);
- void processKeyLocked(nsecs_t currentTime, KeyEntry* entry);
- void processKeyRepeatLocked(nsecs_t currentTime);
- void processMotionLocked(nsecs_t currentTime, MotionEntry* entry);
+ void processConfigurationChangedLockedInterruptible(
+ nsecs_t currentTime, ConfigurationChangedEntry* entry);
+ void processKeyLockedInterruptible(
+ nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout);
+ void processKeyRepeatLockedInterruptible(
+ nsecs_t currentTime, nsecs_t keyRepeatTimeout);
+ void processMotionLockedInterruptible(
+ nsecs_t currentTime, MotionEntry* entry);
// Identify input targets for an event and dispatch to them.
- void identifyInputTargetsAndDispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry);
- void identifyInputTargetsAndDispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry);
- void dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime, EventEntry* entry,
- bool resumeWithAppendedMotionSample);
+ void identifyInputTargetsAndDispatchKeyLockedInterruptible(
+ nsecs_t currentTime, KeyEntry* entry);
+ void identifyInputTargetsAndDispatchMotionLockedInterruptible(
+ nsecs_t currentTime, MotionEntry* entry);
+ void dispatchEventToCurrentInputTargetsLocked(
+ nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
// Manage the dispatch cycle for a single connection.
void prepareDispatchCycleLocked(nsecs_t currentTime, Connection* connection,
@@ -384,12 +514,22 @@ private:
void activateConnectionLocked(Connection* connection);
void deactivateConnectionLocked(Connection* connection);
+ // Outbound policy interactions.
+ void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry);
+
// Interesting events that we might like to log or tell the framework about.
- void onDispatchCycleStartedLocked(nsecs_t currentTime, Connection* connection);
- void onDispatchCycleFinishedLocked(nsecs_t currentTime, Connection* connection,
- bool recoveredFromANR);
- void onDispatchCycleANRLocked(nsecs_t currentTime, Connection* connection);
- void onDispatchCycleBrokenLocked(nsecs_t currentTime, Connection* connection);
+ void onDispatchCycleStartedLocked(
+ nsecs_t currentTime, Connection* connection);
+ void onDispatchCycleFinishedLocked(
+ nsecs_t currentTime, Connection* connection, bool recoveredFromANR);
+ void onDispatchCycleANRLocked(
+ nsecs_t currentTime, Connection* connection);
+ void onDispatchCycleBrokenLocked(
+ nsecs_t currentTime, Connection* connection);
+
+ void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyInputChannelANRLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyInputChannelRecoveredFromANRLockedInterruptible(CommandEntry* commandEntry);
};
/* Enqueues and dispatches input events, endlessly. */