From 54bc281639e5ff6955d7a86104f6f21624941aca Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 15 Jun 2010 01:31:58 -0700 Subject: 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 --- include/ui/Input.h | 33 ++++++- include/ui/InputDispatchPolicy.h | 198 ------------------------------------- include/ui/InputDispatcher.h | 208 ++++++++++++++++++++++++++++++++------- include/ui/InputManager.h | 44 +++++---- include/ui/InputReader.h | 203 +++++++++++++++++++++++++++++++++----- 5 files changed, 408 insertions(+), 278 deletions(-) delete mode 100644 include/ui/InputDispatchPolicy.h (limited to 'include') 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 @@ enum { 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 @@ enum { }; /* + * 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 -#include -#include -#include -#include -#include - -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; - - // 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& outTargets) = 0; - virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, - Vector& 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& outVirtualKeyDefinitions) = 0; - virtual void getExcludedDeviceNames(Vector& 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 -#include #include #include #include @@ -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; + + // 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) = 0; + + /* Notifies the system that an input channel is not responding. */ + virtual void notifyInputChannelANR(const sp& inputChannel) = 0; + + /* Notifies the system that an input channel recovered from ANR. */ + virtual void notifyInputChannelRecoveredFromANR(const sp& 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& outTargets) = 0; + + /* Gets the input targets for a motion event. */ + virtual void getMotionEventTargets(MotionEvent* motionEvent, uint32_t policyFlags, + Vector& 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) = 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& policy); + explicit InputDispatcher(const sp& 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 { 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(); + + Command command; + + // parameters for the command (usage varies by command) + sp inputChannel; + }; + + // Generic queue implementation. template 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 mConfigurationChangeEntryPool; @@ -260,6 +375,7 @@ private: Pool mMotionEntryPool; Pool mMotionSamplePool; Pool mDispatchEntryPool; + Pool mCommandEntryPool; }; /* Manages the dispatch state associated with a single input channel. */ @@ -291,7 +407,9 @@ private: explicit Connection(const sp& 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 mPolicy; + sp mPolicy; Mutex mLock; - Queue mInboundQueue; Allocator mAllocator; - sp mPollLoop; + Queue mInboundQueue; + Queue mCommandQueue; + // All registered connections mapped by receive pipe file descriptor. KeyedVector > mConnectionsByReceiveFd; // Active connections are connections that have a non-empty outbound queue. Vector 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 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. */ 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 #include -#include #include #include #include @@ -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 @@ public: /* Unregisters an input channel. */ virtual status_t unregisterInputChannel(const sp& 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 @@ public: 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 @@ protected: 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& eventHub, - const sp& policy); + InputManager( + const sp& eventHub, + const sp& readerPolicy, + const sp& dispatcherPolicy); + + // (used for testing purposes) + InputManager( + const sp& reader, + const sp& dispatcher); virtual status_t start(); virtual status_t stop(); @@ -108,6 +118,7 @@ public: virtual status_t registerInputChannel(const sp& inputChannel); virtual status_t unregisterInputChannel(const sp& 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 @@ public: virtual bool hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; private: - sp mEventHub; - sp mPolicy; + sp mReader; + sp mReaderThread; - sp mDispatcher; + sp mDispatcher; sp mDispatcherThread; - sp mReader; - sp mReaderThread; - - void configureExcludedDevices(); + 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 #include -#include #include #include #include @@ -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 @@ struct InputDevice { }; -/* 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& outVirtualKeyDefinitions) = 0; + + /* Gets the excluded device names for the platform. */ + virtual void getExcludedDeviceNames(Vector& 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 @@ public: * 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& eventHub, - const sp& policy, + const sp& policy, const sp& dispatcher); virtual ~InputReader(); @@ -372,6 +503,17 @@ public: 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 @@ private: // (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 mEventHub; - sp mPolicy; + sp mPolicy; sp mDispatcher; KeyedVector mDevices; @@ -414,7 +559,7 @@ private: // 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 @@ private: 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(); }; -- cgit v1.1