More work in progress on native events.
Refactored the code to eliminate potential deadlocks due to re-entrant
calls from the policy into the dispatcher. Also added some plumbing
that will be used to notify the framework about ANRs.
Change-Id: Iba7a10de0cb3c56cd7520d6ce716db52fdcc94ff
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 6a5c8a8..d45bfcf 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -73,7 +73,7 @@
POLICY_FLAG_MENU = 0x00000040,
POLICY_FLAG_LAUNCHER = 0x00000080,
- /* These flags are set by the input dispatch policy as it intercepts each event. */
+ /* These flags are set by the input reader policy as it intercepts each event. */
// Indicates that the screen was off when the event was received and the event
// should wake the device.
@@ -85,6 +85,37 @@
};
/*
+ * Describes the basic configuration of input devices that are present.
+ */
+struct InputConfiguration {
+ enum {
+ TOUCHSCREEN_UNDEFINED = 0,
+ TOUCHSCREEN_NOTOUCH = 1,
+ TOUCHSCREEN_STYLUS = 2,
+ TOUCHSCREEN_FINGER = 3
+ };
+
+ enum {
+ KEYBOARD_UNDEFINED = 0,
+ KEYBOARD_NOKEYS = 1,
+ KEYBOARD_QWERTY = 2,
+ KEYBOARD_12KEY = 3
+ };
+
+ enum {
+ NAVIGATION_UNDEFINED = 0,
+ NAVIGATION_NONAV = 1,
+ NAVIGATION_DPAD = 2,
+ NAVIGATION_TRACKBALL = 3,
+ NAVIGATION_WHEEL = 4
+ };
+
+ int32_t touchScreen;
+ int32_t keyboard;
+ int32_t navigation;
+};
+
+/*
* Pointer coordinate data.
*/
struct PointerCoords {
diff --git a/include/ui/InputDispatchPolicy.h b/include/ui/InputDispatchPolicy.h
deleted file mode 100644
index 3546813..0000000
--- a/include/ui/InputDispatchPolicy.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_DISPATCH_POLICY_H
-#define _UI_INPUT_DISPATCH_POLICY_H
-
-/**
- * Native input dispatch policy.
- */
-
-#include <ui/Input.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-
-namespace android {
-
-class InputChannel;
-
-/*
- * 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 dispatch policy interface.
- *
- * The input dispatch policy is used by the input dispatcher to interact with the
- * Window Manager and other system components. This separation of concerns keeps
- * the input dispatcher relatively free of special case logic such as is required
- * to determine the target of iput events, when to wake the device, how to interact
- * with key guard, and when to transition to the home screen.
- *
- * The actual implementation is partially supported by callbacks into the DVM
- * via JNI. This class is also mocked in the input dispatcher unit tests since
- * it is an ideal test seam.
- */
-class InputDispatchPolicyInterface : public virtual RefBase {
-protected:
- InputDispatchPolicyInterface() { }
- virtual ~InputDispatchPolicyInterface() { }
-
-public:
- enum {
- ROTATION_0 = 0,
- ROTATION_90 = 1,
- ROTATION_180 = 2,
- ROTATION_270 = 3
- };
-
- enum {
- // The input dispatcher should do nothing and discard the input unless other
- // flags are set.
- ACTION_NONE = 0,
-
- // The input dispatcher should dispatch the input to the application.
- ACTION_DISPATCH = 0x00000001,
-
- // The input dispatcher should perform special filtering in preparation for
- // a pending app switch.
- ACTION_APP_SWITCH_COMING = 0x00000002,
-
- // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
- // passes through the dispatch pipeline.
- ACTION_WOKE_HERE = 0x00000004,
-
- // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
- // passes through the dispatch pipeline.
- ACTION_BRIGHT_HERE = 0x00000008
- };
-
- enum {
- TOUCHSCREEN_UNDEFINED = 0,
- TOUCHSCREEN_NOTOUCH = 1,
- TOUCHSCREEN_STYLUS = 2,
- TOUCHSCREEN_FINGER = 3
- };
-
- enum {
- KEYBOARD_UNDEFINED = 0,
- KEYBOARD_NOKEYS = 1,
- KEYBOARD_QWERTY = 2,
- KEYBOARD_12KEY = 3
- };
-
- enum {
- NAVIGATION_UNDEFINED = 0,
- NAVIGATION_NONAV = 1,
- NAVIGATION_DPAD = 2,
- NAVIGATION_TRACKBALL = 3,
- NAVIGATION_WHEEL = 4
- };
-
- struct VirtualKeyDefinition {
- int32_t scanCode;
-
- // configured position data, specified in display coords
- int32_t centerX;
- int32_t centerY;
- int32_t width;
- int32_t height;
- };
-
- /* Gets information about the display with the specified id.
- * Returns true if the display info is available, false otherwise.
- */
- virtual bool getDisplayInfo(int32_t displayId,
- int32_t* width, int32_t* height, int32_t* orientation) = 0;
-
- virtual void notifyConfigurationChanged(nsecs_t when,
- int32_t touchScreenConfig, int32_t keyboardConfig, int32_t navigationConfig) = 0;
-
- virtual void notifyLidSwitchChanged(nsecs_t when, bool lidOpen) = 0;
-
- virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t flags, int32_t keyCode,
- int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
-
- virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
-
- virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
- bool rolled) = 0;
-
- virtual int32_t interceptTouch(nsecs_t when) = 0;
-
- virtual bool allowKeyRepeat() = 0;
- virtual nsecs_t getKeyRepeatTimeout() = 0;
-
- virtual void getKeyEventTargets(KeyEvent* keyEvent, uint32_t policyFlags,
- Vector<InputTarget>& outTargets) = 0;
- virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
- Vector<InputTarget>& outTargets) = 0;
-
- /* Determine whether to turn on some hacks we have to improve the touch interaction with a
- * certain device whose screen currently is not all that good.
- */
- virtual bool filterTouchEvents() = 0;
-
- /* Determine whether to turn on some hacks to improve touch interaction with another device
- * where touch coordinate data can get corrupted.
- */
- virtual bool filterJumpyTouchEvents() = 0;
-
- virtual void getVirtualKeyDefinitions(const String8& deviceName,
- Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
- virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
-};
-
-} // namespace android
-
-#endif // _UI_INPUT_DISPATCH_POLICY_H
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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. */
diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h
index eb27513..3872c26 100644
--- a/include/ui/InputManager.h
+++ b/include/ui/InputManager.h
@@ -23,7 +23,6 @@
#include <ui/EventHub.h>
#include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
@@ -32,9 +31,14 @@
namespace android {
-class InputReader;
-class InputDispatcher;
+class InputChannel;
+
+class InputReaderInterface;
+class InputReaderPolicyInterface;
class InputReaderThread;
+
+class InputDispatcherInterface;
+class InputDispatcherPolicyInterface;
class InputDispatcherThread;
/*
@@ -74,8 +78,11 @@
/* Unregisters an input channel. */
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0;
+ /* Gets input device configuration. */
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration) const = 0;
+
/*
- * Query current input state.
+ * Queries current input state.
* deviceId may be -1 to search for the device automatically, filtered by class.
* deviceClasses may be -1 to ignore device class while searching.
*/
@@ -86,7 +93,7 @@
virtual int32_t getSwitchState(int32_t deviceId, int32_t deviceClasses,
int32_t sw) const = 0;
- /* Determine whether physical keys exist for the given framework-domain key codes. */
+ /* Determines whether physical keys exist for the given framework-domain key codes. */
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
};
@@ -95,12 +102,15 @@
virtual ~InputManager();
public:
- /*
- * Creates an input manager that reads events from the given
- * event hub and applies the given input dispatch policy.
- */
- InputManager(const sp<EventHubInterface>& eventHub,
- const sp<InputDispatchPolicyInterface>& policy);
+ InputManager(
+ const sp<EventHubInterface>& eventHub,
+ const sp<InputReaderPolicyInterface>& readerPolicy,
+ const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
+
+ // (used for testing purposes)
+ InputManager(
+ const sp<InputReaderInterface>& reader,
+ const sp<InputDispatcherInterface>& dispatcher);
virtual status_t start();
virtual status_t stop();
@@ -108,6 +118,7 @@
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
+ virtual void getInputConfiguration(InputConfiguration* outConfiguration) const;
virtual int32_t getScanCodeState(int32_t deviceId, int32_t deviceClasses,
int32_t scanCode) const;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
@@ -117,16 +128,13 @@
virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
private:
- sp<EventHubInterface> mEventHub;
- sp<InputDispatchPolicyInterface> mPolicy;
-
- sp<InputDispatcher> mDispatcher;
- sp<InputDispatcherThread> mDispatcherThread;
-
- sp<InputReader> mReader;
+ sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
- void configureExcludedDevices();
+ sp<InputDispatcherInterface> mDispatcher;
+ sp<InputDispatcherThread> mDispatcherThread;
+
+ void initialize();
};
} // namespace android
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 7e7a64c..d76b8fe 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -19,7 +19,6 @@
#include <ui/EventHub.h>
#include <ui/Input.h>
-#include <ui/InputDispatchPolicy.h>
#include <ui/InputDispatcher.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
@@ -35,21 +34,6 @@
* (This is limited by our use of BitSet32 to track pointer assignments.) */
#define MAX_POINTER_ID 32
-/** Amount that trackball needs to move in order to generate a key event. */
-#define TRACKBALL_MOVEMENT_THRESHOLD 6
-
-/* Slop distance for jumpy pointer detection.
- * The vertical range of the screen divided by this is our epsilon value. */
-#define JUMPY_EPSILON_DIVISOR 212
-
-/* Number of jumpy points to drop for touchscreens that need it. */
-#define JUMPY_TRANSITION_DROPS 3
-#define JUMPY_DROP_LIMIT 3
-
-/* Maximum squared distance for averaging.
- * If moving farther than this, turn of averaging to avoid lag in response. */
-#define AVERAGING_DISTANCE_LIMIT (75 * 75)
-
/* Maximum number of historical samples to average. */
#define AVERAGING_HISTORY_SIZE 5
@@ -335,8 +319,129 @@
};
-/* Processes raw input events and sends cooked event data to an input dispatcher
- * in accordance with the input dispatch policy. */
+/*
+ * Input reader 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 InputReaderPolicyInterface : public virtual RefBase {
+protected:
+ InputReaderPolicyInterface() { }
+ virtual ~InputReaderPolicyInterface() { }
+
+public:
+ /* Display orientations. */
+ enum {
+ ROTATION_0 = 0,
+ ROTATION_90 = 1,
+ ROTATION_180 = 2,
+ ROTATION_270 = 3
+ };
+
+ /* Actions returned by interceptXXX methods. */
+ enum {
+ // The input dispatcher should do nothing and discard the input unless other
+ // flags are set.
+ ACTION_NONE = 0,
+
+ // The input dispatcher should dispatch the input to the application.
+ ACTION_DISPATCH = 0x00000001,
+
+ // The input dispatcher should perform special filtering in preparation for
+ // a pending app switch.
+ ACTION_APP_SWITCH_COMING = 0x00000002,
+
+ // The input dispatcher should add POLICY_FLAG_WOKE_HERE to the policy flags it
+ // passes through the dispatch pipeline.
+ ACTION_WOKE_HERE = 0x00000004,
+
+ // The input dispatcher should add POLICY_FLAG_BRIGHT_HERE to the policy flags it
+ // passes through the dispatch pipeline.
+ ACTION_BRIGHT_HERE = 0x00000008
+ };
+
+ /* Describes a virtual key. */
+ struct VirtualKeyDefinition {
+ int32_t scanCode;
+
+ // configured position data, specified in display coords
+ int32_t centerX;
+ int32_t centerY;
+ int32_t width;
+ int32_t height;
+ };
+
+ /* Gets information about the display with the specified id.
+ * Returns true if the display info is available, false otherwise.
+ */
+ virtual bool getDisplayInfo(int32_t displayId,
+ int32_t* width, int32_t* height, int32_t* orientation) = 0;
+
+ /* Provides feedback for a virtual key.
+ */
+ virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
+ int32_t action, int32_t flags, int32_t keyCode,
+ int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
+
+ /* Intercepts a key event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Returns a policy action constant such as ACTION_DISPATCH.
+ */
+ virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
+ bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) = 0;
+
+ /* Intercepts a trackball event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Returns a policy action constant such as ACTION_DISPATCH.
+ */
+ virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
+ bool rolled) = 0;
+
+ /* Intercepts a touch event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Returns a policy action constant such as ACTION_DISPATCH.
+ */
+ virtual int32_t interceptTouch(nsecs_t when) = 0;
+
+ /* Intercepts a switch event.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing.
+ *
+ * Switches are not dispatched to applications so this method should
+ * usually return ACTION_NONE.
+ */
+ virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) = 0;
+
+ /* Determines whether to turn on some hacks we have to improve the touch interaction with a
+ * certain device whose screen currently is not all that good.
+ */
+ virtual bool filterTouchEvents() = 0;
+
+ /* Determines whether to turn on some hacks to improve touch interaction with another device
+ * where touch coordinate data can get corrupted.
+ */
+ virtual bool filterJumpyTouchEvents() = 0;
+
+ /* Gets the configured virtual key definitions for an input device. */
+ virtual void getVirtualKeyDefinitions(const String8& deviceName,
+ Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
+
+ /* Gets the excluded device names for the platform. */
+ virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
+};
+
+
+/* Processes raw input events and sends cooked event data to an input dispatcher. */
class InputReaderInterface : public virtual RefBase {
protected:
InputReaderInterface() { }
@@ -355,16 +460,42 @@
* This method may be called on any thread (usually by the input manager).
*/
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const = 0;
+
+ /* Gets the current input device configuration.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const = 0;
+
+ /*
+ * Query current input state.
+ * deviceId may be -1 to search for the device automatically, filtered by class.
+ * deviceClasses may be -1 to ignore device class while searching.
+ */
+ virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t scanCode) const = 0;
+ virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t keyCode) const = 0;
+ virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
+ int32_t sw) const = 0;
+
+ /* Determine whether physical keys exist for the given framework-domain key codes. */
+ virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0;
};
+
/* The input reader reads raw event data from the event hub and processes it into input events
- * that it sends to the input dispatcher. Some functions of the input reader are controlled
- * by the input dispatch policy, such as early event filtering in low power states.
+ * that it sends to the input dispatcher. Some functions of the input reader, such as early
+ * event filtering in low power states, are controlled by a separate policy object.
+ *
+ * IMPORTANT INVARIANT:
+ * Because the policy can potentially block or cause re-entrance into the input reader,
+ * the input reader never calls into the policy while holding its internal locks.
*/
class InputReader : public InputReaderInterface {
public:
InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputDispatchPolicyInterface>& policy,
+ const sp<InputReaderPolicyInterface>& policy,
const sp<InputDispatcherInterface>& dispatcher);
virtual ~InputReader();
@@ -372,6 +503,17 @@
virtual bool getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const;
+ virtual void getCurrentInputConfiguration(InputConfiguration* outConfiguration) const;
+
+ virtual int32_t getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t scanCode) const;
+ virtual int32_t getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
+ int32_t keyCode) const;
+ virtual int32_t getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
+ int32_t sw) const;
+
+ virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const;
+
private:
// Lock that must be acquired while manipulating state that may be concurrently accessed
// from other threads by input state query methods. It should be held for as short a
@@ -383,15 +525,18 @@
// (but not other internal device state)
mutable Mutex mExportedStateLock;
- // current virtual key information
- int32_t mGlobalVirtualKeyCode;
- int32_t mGlobalVirtualScanCode;
+ // current virtual key information (lock mExportedStateLock)
+ int32_t mExportedVirtualKeyCode;
+ int32_t mExportedVirtualScanCode;
+
+ // current input configuration (lock mExportedStateLock)
+ InputConfiguration mExportedInputConfiguration;
// combined key meta state
int32_t mGlobalMetaState;
sp<EventHubInterface> mEventHub;
- sp<InputDispatchPolicyInterface> mPolicy;
+ sp<InputReaderPolicyInterface> mPolicy;
sp<InputDispatcherInterface> mDispatcher;
KeyedVector<int32_t, InputDevice*> mDevices;
@@ -414,7 +559,7 @@
// input policy processing and dispatch
void onKey(nsecs_t when, InputDevice* device, bool down,
int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
- void onSwitch(nsecs_t when, InputDevice* device, bool down, int32_t code);
+ void onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode, int32_t switchValue);
void onSingleTouchScreenStateChanged(nsecs_t when, InputDevice* device);
void onMultiTouchScreenStateChanged(nsecs_t when, InputDevice* device);
void onTouchScreenChanged(nsecs_t when, InputDevice* device, bool havePointerIds);
@@ -445,13 +590,17 @@
void configureVirtualKeys(InputDevice* device);
void configureAbsoluteAxisInfo(InputDevice* device, int axis, const char* name,
InputDevice::AbsoluteAxisInfo* out);
+ void configureExcludedDevices();
// global meta state management for all devices
void resetGlobalMetaState();
int32_t globalMetaState();
// virtual key management
- void updateGlobalVirtualKeyState();
+ void updateExportedVirtualKeyState();
+
+ // input configuration management
+ void updateExportedInputConfiguration();
};