diff options
Diffstat (limited to 'include/ui')
-rw-r--r-- | include/ui/EventHub.h | 249 | ||||
-rw-r--r-- | include/ui/FramebufferNativeWindow.h | 18 | ||||
-rw-r--r-- | include/ui/GraphicBuffer.h | 13 | ||||
-rw-r--r-- | include/ui/GraphicBufferAllocator.h | 2 | ||||
-rw-r--r-- | include/ui/GraphicLog.h | 70 | ||||
-rw-r--r-- | include/ui/Input.h | 502 | ||||
-rw-r--r-- | include/ui/InputDispatcher.h | 1083 | ||||
-rw-r--r-- | include/ui/InputManager.h | 115 | ||||
-rw-r--r-- | include/ui/InputReader.h | 927 | ||||
-rw-r--r-- | include/ui/InputTransport.h | 335 | ||||
-rwxr-xr-x | include/ui/KeycodeLabels.h | 127 | ||||
-rw-r--r-- | include/ui/PowerManager.h | 37 | ||||
-rw-r--r-- | include/ui/Rect.h | 33 | ||||
-rw-r--r-- | include/ui/android_native_buffer.h | 9 | ||||
-rw-r--r-- | include/ui/egl/android_natives.h | 174 |
15 files changed, 3475 insertions, 219 deletions
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index a21bb49..d78e35f 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -18,6 +18,7 @@ #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H +#include <android/input.h> #include <utils/String8.h> #include <utils/threads.h> #include <utils/Log.h> @@ -27,6 +28,31 @@ #include <linux/input.h> +/* These constants are not defined in linux/input.h but they are part of the multitouch + * input protocol. */ + +#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ +#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ +#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ +#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ +#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ +#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ +#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ +#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device (finger, pen, ...) */ +#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ +#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ +#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ + +#define MT_TOOL_FINGER 0 /* Identifies a finger */ +#define MT_TOOL_PEN 1 /* Identifies a pen */ + +#define SYN_MT_REPORT 2 + +/* Convenience constants. */ + +#define BTN_FIRST 0x100 // first button scancode +#define BTN_LAST 0x15f // last button scancode + struct pollfd; namespace android { @@ -34,78 +60,176 @@ namespace android { class KeyLayoutMap; /* - * Grand Central Station for events. With a single call to waitEvent() - * you can wait for: - * - input events from the keypad of a real device - * - input events and meta-events (e.g. "quit") from the simulator - * - synthetic events from the runtime (e.g. "URL fetch completed") - * - real or forged "vsync" events + * A raw event as retrieved from the EventHub. + */ +struct RawEvent { + nsecs_t when; + int32_t deviceId; + int32_t type; + int32_t scanCode; + int32_t keyCode; + int32_t value; + uint32_t flags; +}; + +/* Describes an absolute axis. */ +struct RawAbsoluteAxisInfo { + bool valid; // true if the information is valid, false otherwise + + int32_t minValue; // minimum value + int32_t maxValue; // maximum value + int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 + int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise + + inline int32_t getRange() { return maxValue - minValue; } + + inline void clear() { + valid = false; + minValue = 0; + maxValue = 0; + flat = 0; + fuzz = 0; + } +}; + +/* + * Input device classes. + */ +enum { + /* The input device is a keyboard. */ + INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, + + /* The input device is an alpha-numeric keyboard (not just a dial pad). */ + INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, + + /* The input device is a touchscreen (either single-touch or multi-touch). */ + INPUT_DEVICE_CLASS_TOUCHSCREEN = 0x00000004, + + /* The input device is a trackball. */ + INPUT_DEVICE_CLASS_TRACKBALL = 0x00000008, + + /* The input device is a multi-touch touchscreen. */ + INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010, + + /* The input device is a directional pad (implies keyboard, has DPAD keys). */ + INPUT_DEVICE_CLASS_DPAD = 0x00000020, + + /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ + INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, + + /* The input device has switches. */ + INPUT_DEVICE_CLASS_SWITCH = 0x00000080, +}; + +/* + * Grand Central Station for events. * - * Do not instantiate this class. Instead, call startUp(). + * The event hub aggregates input events received across all known input + * devices on the system, including devices that may be emulated by the simulator + * environment. In addition, the event hub generates fake input events to indicate + * when devices are added or removed. + * + * The event hub provies a stream of input events (via the getEvent function). + * It also supports querying the current actual state of input devices such as identifying + * which keys are currently down. Finally, the event hub keeps track of the capabilities of + * individual input devices, such as their class and the set of key codes that they support. */ -class EventHub : public RefBase +class EventHubInterface : public virtual RefBase { +protected: + EventHubInterface() { } + virtual ~EventHubInterface() { } + +public: + // Synthetic raw event type codes produced when devices are added or removed. + enum { + // Sent when a device is added. + DEVICE_ADDED = 0x10000000, + // Sent when a device is removed. + DEVICE_REMOVED = 0x20000000, + // Sent when all added/removed devices from the most recent scan have been reported. + // This event is always sent at least once. + FINISHED_DEVICE_SCAN = 0x30000000, + }; + + virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; + + virtual String8 getDeviceName(int32_t deviceId) const = 0; + + virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const = 0; + + virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, + int32_t* outKeycode, uint32_t* outFlags) const = 0; + + // exclude a particular device from opening + // this can be used to ignore input devices for sensors + virtual void addExcludedDevice(const char* deviceName) = 0; + + /* + * Wait for the next event to become available and return it. + * After returning, the EventHub holds onto a wake lock until the next call to getEvent. + * This ensures that the device will not go to sleep while the event is being processed. + * If the device needs to remain awake longer than that, then the caller is responsible + * for taking care of it (say, by poking the power manager user activity timer). + */ + virtual bool getEvent(RawEvent* outEvent) = 0; + + /* + * Query current input state. + */ + virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; + virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; + + /* + * Examine key input devices for specific framework keycode support + */ + virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + uint8_t* outFlags) const = 0; + + virtual void dump(String8& dump) = 0; +}; + +class EventHub : public EventHubInterface { public: EventHub(); - + status_t errorCheck() const; + + virtual uint32_t getDeviceClasses(int32_t deviceId) const; - // bit fields for classes of devices. - enum { - CLASS_KEYBOARD = 0x00000001, - CLASS_ALPHAKEY = 0x00000002, - CLASS_TOUCHSCREEN = 0x00000004, - CLASS_TRACKBALL = 0x00000008, - CLASS_TOUCHSCREEN_MT= 0x00000010, - CLASS_DPAD = 0x00000020 - }; - uint32_t getDeviceClasses(int32_t deviceId) const; - - String8 getDeviceName(int32_t deviceId) const; - - int getAbsoluteInfo(int32_t deviceId, int axis, int *outMinValue, - int* outMaxValue, int* outFlat, int* outFuzz) const; - - int getSwitchState(int sw) const; - int getSwitchState(int32_t deviceId, int sw) const; - - int getScancodeState(int key) const; - int getScancodeState(int32_t deviceId, int key) const; - - int getKeycodeState(int key) const; - int getKeycodeState(int32_t deviceId, int key) const; + virtual String8 getDeviceName(int32_t deviceId) const; - status_t scancodeToKeycode(int32_t deviceId, int scancode, + virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, + RawAbsoluteAxisInfo* outAxisInfo) const; + + virtual status_t scancodeToKeycode(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const; - // exclude a particular device from opening - // this can be used to ignore input devices for sensors - void addExcludedDevice(const char* deviceName); + virtual void addExcludedDevice(const char* deviceName); - // special type codes when devices are added/removed. - enum { - DEVICE_ADDED = 0x10000000, - DEVICE_REMOVED = 0x20000000 - }; - - // examine key input devices for specific framework keycode support - bool hasKeys(size_t numCodes, int32_t* keyCodes, uint8_t* outFlags); + virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; + virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; + virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; - virtual bool getEvent(int32_t* outDeviceId, int32_t* outType, - int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags, - int32_t* outValue, nsecs_t* outWhen); + virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) const; + + virtual bool getEvent(RawEvent* outEvent); + + virtual void dump(String8& dump); protected: virtual ~EventHub(); private: bool openPlatformInput(void); - int32_t convertDeviceKey_TI_P2(int code); - int open_device(const char *device); - int close_device(const char *device); - int scan_dir(const char *dirname); - int read_notify(int nfd); + int openDevice(const char *device); + int closeDevice(const char *device); + int scanDir(const char *dirname); + int readNotify(int nfd); status_t mError; @@ -124,9 +248,15 @@ private: ~device_t(); }; - device_t* getDevice(int32_t deviceId) const; - bool hasKeycode(device_t* device, int keycode) const; + device_t* getDeviceLocked(int32_t deviceId) const; + bool hasKeycodeLocked(device_t* device, int keycode) const; + int32_t getScanCodeStateLocked(device_t* device, int32_t scanCode) const; + int32_t getKeyCodeStateLocked(device_t* device, int32_t keyCode) const; + int32_t getSwitchStateLocked(device_t* device, int32_t sw) const; + bool markSupportedKeyCodesLocked(device_t* device, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags) const; + // Protect all internal state. mutable Mutex mLock; @@ -148,12 +278,19 @@ private: int mFDCount; bool mOpened; + bool mNeedToSendFinishedDeviceScan; List<String8> mExcludedDevices; // device ids that report particular switches. #ifdef EV_SW - int32_t mSwitches[SW_MAX+1]; + int32_t mSwitches[SW_MAX + 1]; #endif + + static const int INPUT_BUFFER_SIZE = 64; + struct input_event mInputBufferData[INPUT_BUFFER_SIZE]; + int32_t mInputBufferIndex; + int32_t mInputBufferCount; + int32_t mInputDeviceIndex; }; }; // namespace android diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h index e9c7df2..2cd0911 100644 --- a/include/ui/FramebufferNativeWindow.h +++ b/include/ui/FramebufferNativeWindow.h @@ -44,7 +44,7 @@ class NativeBuffer; class FramebufferNativeWindow : public EGLNativeBase< - android_native_window_t, + ANativeWindow, FramebufferNativeWindow, LightRefBase<FramebufferNativeWindow> > { @@ -57,15 +57,18 @@ public: status_t setUpdateRectangle(const Rect& updateRect); status_t compositionComplete(); + // for debugging only + int getCurrentBufferIndex() const; + private: friend class LightRefBase<FramebufferNativeWindow>; ~FramebufferNativeWindow(); // this class cannot be overloaded - static int setSwapInterval(android_native_window_t* window, int interval); - static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer); - static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer); - static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer); - static int query(android_native_window_t* window, int what, int* value); - static int perform(android_native_window_t* window, int operation, ...); + static int setSwapInterval(ANativeWindow* window, int interval); + static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer); + static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer); + static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer); + static int query(ANativeWindow* window, int what, int* value); + static int perform(ANativeWindow* window, int operation, ...); framebuffer_device_t* fbDev; alloc_device_t* grDev; @@ -78,6 +81,7 @@ private: int32_t mNumBuffers; int32_t mNumFreeBuffers; int32_t mBufferHead; + int32_t mCurrentBufferIndex; bool mUpdateOnDemand; }; diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h index e72b6b3..a3e85a9 100644 --- a/include/ui/GraphicBuffer.h +++ b/include/ui/GraphicBuffer.h @@ -93,10 +93,8 @@ public: void setIndex(int index); int getIndex() const; - void setVerticalStride(uint32_t vstride); - uint32_t getVerticalStride() const; -protected: +private: virtual ~GraphicBuffer(); enum { @@ -105,8 +103,12 @@ protected: ownData = 2, }; - inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; } - inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; } + inline const GraphicBufferMapper& getBufferMapper() const { + return mBufferMapper; + } + inline GraphicBufferMapper& getBufferMapper() { + return mBufferMapper; + } uint8_t mOwner; private: @@ -134,7 +136,6 @@ private: GraphicBufferMapper& mBufferMapper; ssize_t mInitCheck; - uint32_t mVStride; int mIndex; }; diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h index 741d763..54b8236 100644 --- a/include/ui/GraphicBufferAllocator.h +++ b/include/ui/GraphicBufferAllocator.h @@ -73,9 +73,9 @@ private: struct alloc_rec_t { uint32_t w; uint32_t h; + uint32_t s; PixelFormat format; uint32_t usage; - void* vaddr; size_t size; }; diff --git a/include/ui/GraphicLog.h b/include/ui/GraphicLog.h new file mode 100644 index 0000000..ee1b09a --- /dev/null +++ b/include/ui/GraphicLog.h @@ -0,0 +1,70 @@ +/* + * 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_GRAPHIC_LOG_H +#define _UI_GRAPHIC_LOG_H + +#include <utils/Singleton.h> +#include <cutils/compiler.h> + +namespace android { + +class GraphicLog : public Singleton<GraphicLog> +{ + int32_t mEnabled; + static void logImpl(int32_t tag, int32_t buffer); + static void logImpl(int32_t tag, int32_t identity, int32_t buffer); + +public: + enum { + SF_APP_DEQUEUE_BEFORE = 60100, + SF_APP_DEQUEUE_AFTER = 60101, + SF_APP_LOCK_BEFORE = 60102, + SF_APP_LOCK_AFTER = 60103, + SF_APP_QUEUE = 60104, + + SF_REPAINT = 60105, + SF_COMPOSITION_COMPLETE = 60106, + SF_UNLOCK_CLIENTS = 60107, + SF_SWAP_BUFFERS = 60108, + SF_REPAINT_DONE = 60109, + + SF_FB_POST_BEFORE = 60110, + SF_FB_POST_AFTER = 60111, + SF_FB_DEQUEUE_BEFORE = 60112, + SF_FB_DEQUEUE_AFTER = 60113, + SF_FB_LOCK_BEFORE = 60114, + SF_FB_LOCK_AFTER = 60115, + }; + + inline void log(int32_t tag, int32_t buffer) { + if (CC_UNLIKELY(mEnabled)) + logImpl(tag, buffer); + } + inline void log(int32_t tag, int32_t identity, int32_t buffer) { + if (CC_UNLIKELY(mEnabled)) + logImpl(tag, identity, buffer); + } + + GraphicLog(); + + void setEnabled(bool enable); +}; + +} + +#endif // _UI_GRAPHIC_LOG_H + diff --git a/include/ui/Input.h b/include/ui/Input.h new file mode 100644 index 0000000..8c6018b --- /dev/null +++ b/include/ui/Input.h @@ -0,0 +1,502 @@ +/* + * 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_H +#define _UI_INPUT_H + +/** + * Native input event structures. + */ + +#include <android/input.h> +#include <utils/Vector.h> +#include <utils/KeyedVector.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +/* + * Additional private constants not defined in ndk/ui/input.h. + */ +enum { + /* + * Private control to determine when an app is tracking a key sequence. + */ + AKEY_EVENT_FLAG_START_TRACKING = 0x40000000 +}; + +/* + * Maximum number of pointers supported per motion event. + * Smallest number of pointers is 1. + */ +#define MAX_POINTERS 10 + +/* + * Maximum pointer id value supported in a motion event. + * Smallest pointer id is 0. + * (This is limited by our use of BitSet32 to track pointer assignments.) + */ +#define MAX_POINTER_ID 31 + +/* + * Declare a concrete type for the NDK's input event forward declaration. + */ +struct AInputEvent { + virtual ~AInputEvent() { } +}; + +/* + * Declare a concrete type for the NDK's input device forward declaration. + */ +struct AInputDevice { + virtual ~AInputDevice() { } +}; + + +namespace android { + +/* + * Flags that flow alongside events in the input dispatch system to help with certain + * policy decisions such as waking from device sleep. + * + * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. + */ +enum { + /* These flags originate in RawEvents and are generally set in the key map. + * See also labels for policy flags in KeycodeLabels.h. */ + + POLICY_FLAG_WAKE = 0x00000001, + POLICY_FLAG_WAKE_DROPPED = 0x00000002, + POLICY_FLAG_SHIFT = 0x00000004, + POLICY_FLAG_CAPS_LOCK = 0x00000008, + POLICY_FLAG_ALT = 0x00000010, + POLICY_FLAG_ALT_GR = 0x00000020, + POLICY_FLAG_MENU = 0x00000040, + POLICY_FLAG_LAUNCHER = 0x00000080, + POLICY_FLAG_VIRTUAL = 0x00000100, + + POLICY_FLAG_RAW_MASK = 0x0000ffff, + + /* These flags are set by the input dispatcher. */ + + // Indicates that the input event was injected. + POLICY_FLAG_INJECTED = 0x01000000, + + // Indicates that the input event is from a trusted source such as a directly attached + // input device or an application with system-wide event injection permission. + POLICY_FLAG_TRUSTED = 0x02000000, + + /* 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. + POLICY_FLAG_WOKE_HERE = 0x10000000, + + // Indicates that the screen was dim when the event was received and the event + // should brighten the device. + POLICY_FLAG_BRIGHT_HERE = 0x20000000, + + // Indicates that the event should be dispatched to applications. + // The input event should still be sent to the InputDispatcher so that it can see all + // input events received include those that it will not deliver. + POLICY_FLAG_PASS_TO_USER = 0x40000000, +}; + +/* + * 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 { + float x; + float y; + float pressure; + float size; + float touchMajor; + float touchMinor; + float toolMajor; + float toolMinor; + float orientation; +}; + +/* + * Input events. + */ +class InputEvent : public AInputEvent { +public: + virtual ~InputEvent() { } + + virtual int32_t getType() const = 0; + + inline int32_t getDeviceId() const { return mDeviceId; } + + inline int32_t getSource() const { return mSource; } + +protected: + void initialize(int32_t deviceId, int32_t source); + void initialize(const InputEvent& from); + +private: + int32_t mDeviceId; + int32_t mSource; +}; + +/* + * Key events. + */ +class KeyEvent : public InputEvent { +public: + virtual ~KeyEvent() { } + + virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; } + + inline int32_t getAction() const { return mAction; } + + inline int32_t getFlags() const { return mFlags; } + + inline int32_t getKeyCode() const { return mKeyCode; } + + inline int32_t getScanCode() const { return mScanCode; } + + inline int32_t getMetaState() const { return mMetaState; } + + inline int32_t getRepeatCount() const { return mRepeatCount; } + + inline nsecs_t getDownTime() const { return mDownTime; } + + inline nsecs_t getEventTime() const { return mEventTime; } + + // Return true if this event may have a default action implementation. + static bool hasDefaultAction(int32_t keyCode); + bool hasDefaultAction() const; + + // Return true if this event represents a system key. + static bool isSystemKey(int32_t keyCode); + bool isSystemKey() const; + + void initialize( + int32_t deviceId, + int32_t source, + int32_t action, + int32_t flags, + int32_t keyCode, + int32_t scanCode, + int32_t metaState, + int32_t repeatCount, + nsecs_t downTime, + nsecs_t eventTime); + void initialize(const KeyEvent& from); + +private: + int32_t mAction; + int32_t mFlags; + int32_t mKeyCode; + int32_t mScanCode; + int32_t mMetaState; + int32_t mRepeatCount; + nsecs_t mDownTime; + nsecs_t mEventTime; +}; + +/* + * Motion events. + */ +class MotionEvent : public InputEvent { +public: + virtual ~MotionEvent() { } + + virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; } + + inline int32_t getAction() const { return mAction; } + + inline int32_t getFlags() const { return mFlags; } + + inline int32_t getEdgeFlags() const { return mEdgeFlags; } + + inline int32_t getMetaState() const { return mMetaState; } + + inline float getXOffset() const { return mXOffset; } + + inline float getYOffset() const { return mYOffset; } + + inline float getXPrecision() const { return mXPrecision; } + + inline float getYPrecision() const { return mYPrecision; } + + inline nsecs_t getDownTime() const { return mDownTime; } + + inline size_t getPointerCount() const { return mPointerIds.size(); } + + inline int32_t getPointerId(size_t pointerIndex) const { return mPointerIds[pointerIndex]; } + + inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } + + inline float getRawX(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).x; + } + + inline float getRawY(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).y; + } + + inline float getX(size_t pointerIndex) const { + return getRawX(pointerIndex) + mXOffset; + } + + inline float getY(size_t pointerIndex) const { + return getRawY(pointerIndex) + mYOffset; + } + + inline float getPressure(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).pressure; + } + + inline float getSize(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).size; + } + + inline float getTouchMajor(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).touchMajor; + } + + inline float getTouchMinor(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).touchMinor; + } + + inline float getToolMajor(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).toolMajor; + } + + inline float getToolMinor(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).toolMinor; + } + + inline float getOrientation(size_t pointerIndex) const { + return getCurrentPointerCoords(pointerIndex).orientation; + } + + inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; } + + inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const { + return mSampleEventTimes[historicalIndex]; + } + + inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).x; + } + + inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).y; + } + + inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalRawX(pointerIndex, historicalIndex) + mXOffset; + } + + inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalRawY(pointerIndex, historicalIndex) + mYOffset; + } + + inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure; + } + + inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).size; + } + + inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMajor; + } + + inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMinor; + } + + inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMajor; + } + + inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMinor; + } + + inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const { + return getHistoricalPointerCoords(pointerIndex, historicalIndex).orientation; + } + + void initialize( + int32_t deviceId, + int32_t source, + int32_t action, + int32_t flags, + int32_t edgeFlags, + int32_t metaState, + float xOffset, + float yOffset, + float xPrecision, + float yPrecision, + nsecs_t downTime, + nsecs_t eventTime, + size_t pointerCount, + const int32_t* pointerIds, + const PointerCoords* pointerCoords); + + void addSample( + nsecs_t eventTime, + const PointerCoords* pointerCoords); + + void offsetLocation(float xOffset, float yOffset); + + // Low-level accessors. + inline const int32_t* getPointerIds() const { return mPointerIds.array(); } + inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } + inline const PointerCoords* getSamplePointerCoords() const { + return mSamplePointerCoords.array(); + } + +private: + int32_t mAction; + int32_t mFlags; + int32_t mEdgeFlags; + int32_t mMetaState; + float mXOffset; + float mYOffset; + float mXPrecision; + float mYPrecision; + nsecs_t mDownTime; + Vector<int32_t> mPointerIds; + Vector<nsecs_t> mSampleEventTimes; + Vector<PointerCoords> mSamplePointerCoords; + + inline const PointerCoords& getCurrentPointerCoords(size_t pointerIndex) const { + return mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; + } + + inline const PointerCoords& getHistoricalPointerCoords( + size_t pointerIndex, size_t historicalIndex) const { + return mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; + } +}; + +/* + * Input event factory. + */ +class InputEventFactoryInterface { +protected: + virtual ~InputEventFactoryInterface() { } + +public: + InputEventFactoryInterface() { } + + virtual KeyEvent* createKeyEvent() = 0; + virtual MotionEvent* createMotionEvent() = 0; +}; + +/* + * A simple input event factory implementation that uses a single preallocated instance + * of each type of input event that are reused for each request. + */ +class PreallocatedInputEventFactory : public InputEventFactoryInterface { +public: + PreallocatedInputEventFactory() { } + virtual ~PreallocatedInputEventFactory() { } + + virtual KeyEvent* createKeyEvent() { return & mKeyEvent; } + virtual MotionEvent* createMotionEvent() { return & mMotionEvent; } + +private: + KeyEvent mKeyEvent; + MotionEvent mMotionEvent; +}; + +/* + * Describes the characteristics and capabilities of an input device. + */ +class InputDeviceInfo { +public: + InputDeviceInfo(); + InputDeviceInfo(const InputDeviceInfo& other); + ~InputDeviceInfo(); + + struct MotionRange { + float min; + float max; + float flat; + float fuzz; + }; + + void initialize(int32_t id, const String8& name); + + inline int32_t getId() const { return mId; } + inline const String8 getName() const { return mName; } + inline uint32_t getSources() const { return mSources; } + + const MotionRange* getMotionRange(int32_t rangeType) const; + + void addSource(uint32_t source); + void addMotionRange(int32_t rangeType, float min, float max, float flat, float fuzz); + void addMotionRange(int32_t rangeType, const MotionRange& range); + + inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } + inline int32_t getKeyboardType() const { return mKeyboardType; } + + inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const { + return mMotionRanges; + } + +private: + int32_t mId; + String8 mName; + uint32_t mSources; + int32_t mKeyboardType; + + KeyedVector<int32_t, MotionRange> mMotionRanges; +}; + + +} // namespace android + +#endif // _UI_INPUT_H diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h new file mode 100644 index 0000000..5f77cba --- /dev/null +++ b/include/ui/InputDispatcher.h @@ -0,0 +1,1083 @@ +/* + * 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_DISPATCHER_H +#define _UI_INPUT_DISPATCHER_H + +#include <ui/Input.h> +#include <ui/InputTransport.h> +#include <utils/KeyedVector.h> +#include <utils/Vector.h> +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/Looper.h> +#include <utils/Pool.h> +#include <utils/BitSet.h> + +#include <stddef.h> +#include <unistd.h> +#include <limits.h> + + +namespace android { + +/* + * Constants used to report the outcome of input event injection. + */ +enum { + /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ + INPUT_EVENT_INJECTION_PENDING = -1, + + /* Injection succeeded. */ + INPUT_EVENT_INJECTION_SUCCEEDED = 0, + + /* Injection failed because the injector did not have permission to inject + * into the application with input focus. */ + INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, + + /* Injection failed because there were no available input targets. */ + INPUT_EVENT_INJECTION_FAILED = 2, + + /* Injection failed due to a timeout. */ + INPUT_EVENT_INJECTION_TIMED_OUT = 3 +}; + +/* + * Constants used to determine the input event injection synchronization mode. + */ +enum { + /* Injection is asynchronous and is assumed always to be successful. */ + INPUT_EVENT_INJECTION_SYNC_NONE = 0, + + /* Waits for previous events to be dispatched so that the input dispatcher can determine + * whether input event injection willbe permitted based on the current input focus. + * Does not wait for the input event to finish processing. */ + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, + + /* Waits for the input event to be completely processed. */ + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, +}; + + +/* + * 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 the event is being delivered to a foreground application. */ + FLAG_FOREGROUND = 0x01, + + /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside + * of the area of this target and so should instead be delivered as an + * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ + FLAG_OUTSIDE = 0x02, + + /* This flag indicates that the target of a MotionEvent is partly or wholly + * obscured by another visible window above it. The motion event should be + * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ + FLAG_WINDOW_IS_OBSCURED = 0x04, + + /* This flag indicates that a motion event is being split across multiple windows. */ + FLAG_SPLIT = 0x08, + }; + + // The input channel to be targeted. + sp<InputChannel> inputChannel; + + // Flags for the input target. + int32_t flags; + + // The x and y offset to add to a MotionEvent as it is delivered. + // (ignored for KeyEvents) + float xOffset, yOffset; + + // The subset of pointer ids to include in motion events dispatched to this input target + // if FLAG_SPLIT is set. + BitSet32 pointerIds; +}; + + +/* + * An input window describes the bounds of a window that can receive input. + */ +struct InputWindow { + // Window flags from WindowManager.LayoutParams + enum { + FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + FLAG_DIM_BEHIND = 0x00000002, + FLAG_BLUR_BEHIND = 0x00000004, + FLAG_NOT_FOCUSABLE = 0x00000008, + FLAG_NOT_TOUCHABLE = 0x00000010, + FLAG_NOT_TOUCH_MODAL = 0x00000020, + FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + FLAG_KEEP_SCREEN_ON = 0x00000080, + FLAG_LAYOUT_IN_SCREEN = 0x00000100, + FLAG_LAYOUT_NO_LIMITS = 0x00000200, + FLAG_FULLSCREEN = 0x00000400, + FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + FLAG_DITHER = 0x00001000, + FLAG_SECURE = 0x00002000, + FLAG_SCALED = 0x00004000, + FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + FLAG_LAYOUT_INSET_DECOR = 0x00010000, + FLAG_ALT_FOCUSABLE_IM = 0x00020000, + FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + FLAG_SHOW_WHEN_LOCKED = 0x00080000, + FLAG_SHOW_WALLPAPER = 0x00100000, + FLAG_TURN_SCREEN_ON = 0x00200000, + FLAG_DISMISS_KEYGUARD = 0x00400000, + FLAG_SPLIT_TOUCH = 0x00800000, + FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, + FLAG_COMPATIBLE_WINDOW = 0x20000000, + FLAG_SYSTEM_ERROR = 0x40000000, + }; + + // Window types from WindowManager.LayoutParams + enum { + FIRST_APPLICATION_WINDOW = 1, + TYPE_BASE_APPLICATION = 1, + TYPE_APPLICATION = 2, + TYPE_APPLICATION_STARTING = 3, + LAST_APPLICATION_WINDOW = 99, + FIRST_SUB_WINDOW = 1000, + TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, + TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, + TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, + TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, + TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, + LAST_SUB_WINDOW = 1999, + FIRST_SYSTEM_WINDOW = 2000, + TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, + TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, + TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, + TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, + TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, + TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, + TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, + TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, + TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, + TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, + TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, + TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, + TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, + TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, + TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, + TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, + LAST_SYSTEM_WINDOW = 2999, + }; + + sp<InputChannel> inputChannel; + String8 name; + int32_t layoutParamsFlags; + int32_t layoutParamsType; + nsecs_t dispatchingTimeout; + int32_t frameLeft; + int32_t frameTop; + int32_t frameRight; + int32_t frameBottom; + int32_t visibleFrameLeft; + int32_t visibleFrameTop; + int32_t visibleFrameRight; + int32_t visibleFrameBottom; + int32_t touchableAreaLeft; + int32_t touchableAreaTop; + int32_t touchableAreaRight; + int32_t touchableAreaBottom; + bool visible; + bool canReceiveKeys; + bool hasFocus; + bool hasWallpaper; + bool paused; + int32_t layer; + int32_t ownerPid; + int32_t ownerUid; + + bool touchableAreaContainsPoint(int32_t x, int32_t y) const; + bool frameContainsPoint(int32_t x, int32_t y) const; + + /* Returns true if the window is of a trusted type that is allowed to silently + * overlay other windows for the purpose of implementing the secure views feature. + * Trusted overlays, such as IME windows, can partly obscure other windows without causing + * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. + */ + bool isTrustedOverlay() const; +}; + + +/* + * A private handle type used by the input manager to track the window. + */ +class InputApplicationHandle : public RefBase { +protected: + InputApplicationHandle() { } + virtual ~InputApplicationHandle() { } +}; + + +/* + * An input application describes properties of an application that can receive input. + */ +struct InputApplication { + String8 name; + nsecs_t dispatchingTimeout; + sp<InputApplicationHandle> handle; +}; + + +/* + * 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 application is not responding. + * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ + virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, + const sp<InputChannel>& inputChannel) = 0; + + /* Notifies the system that an input channel is unrecoverably broken. */ + virtual void notifyInputChannelBroken(const sp<InputChannel>& inputChannel) = 0; + + /* Gets the key repeat initial timeout or -1 if automatic key repeating is disabled. */ + virtual nsecs_t getKeyRepeatTimeout() = 0; + + /* Gets the key repeat inter-key delay. */ + virtual nsecs_t getKeyRepeatDelay() = 0; + + /* Gets the maximum suggested event delivery rate per second. + * This value is used to throttle motion event movement actions on a per-device + * basis. It is not intended to be a hard limit. + */ + virtual int32_t getMaxEventsPerSecond() = 0; + + /* Intercepts a key event immediately before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, + int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, + uint32_t& policyFlags) = 0; + + /* Intercepts a generic touch, trackball or other event before queueing it. + * The policy can use this method as an opportunity to perform power management functions + * and early event preprocessing such as updating policy flags. + * + * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event + * should be dispatched to applications. + */ + virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; + + /* Allows the policy a chance to intercept a key before dispatching. */ + virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, + const KeyEvent* keyEvent, uint32_t policyFlags) = 0; + + /* Notifies the policy about switch events. + */ + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; + + /* Poke user activity for an event dispatched to a window. */ + virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; + + /* Checks whether a given application pid/uid has permission to inject input events + * into other applications. + * + * This method is special in that its implementation promises to be non-reentrant and + * is safe to call while holding other locks. (Most other methods make no such guarantees!) + */ + virtual bool checkInjectEventsPermissionNonReentrant( + int32_t injectorPid, int32_t injectorUid) = 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 { +protected: + InputDispatcherInterface() { } + virtual ~InputDispatcherInterface() { } + +public: + /* Dumps the state of the input dispatcher. + * + * This method may be called on any thread (usually by the input manager). */ + virtual void dump(String8& dump) = 0; + + /* Runs a single iteration of the dispatch loop. + * Nominally processes one queued event, a timeout, or a response from an input consumer. + * + * This method should only be called on the input dispatcher thread. + */ + virtual void dispatchOnce() = 0; + + /* Notifies the dispatcher about new events. + * + * These methods should only be called on the input reader thread. + */ + virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0; + virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source, + uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0; + virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source, + uint32_t policyFlags, int32_t action, int32_t flags, + int32_t metaState, int32_t edgeFlags, + uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, nsecs_t downTime) = 0; + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; + + /* Injects an input event and optionally waits for sync. + * The synchronization mode determines whether the method blocks while waiting for + * input injection to proceed. + * Returns one of the INPUT_EVENT_INJECTION_XXX constants. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual int32_t injectInputEvent(const InputEvent* event, + int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) = 0; + + /* Sets the list of input windows. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0; + + /* Sets the focused application. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setFocusedApplication(const InputApplication* inputApplication) = 0; + + /* Sets the input dispatching mode. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; + + /* Registers or unregister input channels that may be used as targets for input events. + * If monitor is true, the channel will receive a copy of all input events. + * + * These methods may be called on any thread (usually by the input manager). + */ + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor) = 0; + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; +}; + +/* 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<InputDispatcherPolicyInterface>& policy); + + virtual void dump(String8& dump); + + virtual void dispatchOnce(); + + virtual void notifyConfigurationChanged(nsecs_t eventTime); + virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source, + uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, + int32_t scanCode, int32_t metaState, nsecs_t downTime); + virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source, + uint32_t policyFlags, int32_t action, int32_t flags, + int32_t metaState, int32_t edgeFlags, + uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, nsecs_t downTime); + virtual void notifySwitch(nsecs_t when, + int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ; + + virtual int32_t injectInputEvent(const InputEvent* event, + int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis); + + virtual void setInputWindows(const Vector<InputWindow>& inputWindows); + virtual void setFocusedApplication(const InputApplication* inputApplication); + virtual void setInputDispatchMode(bool enabled, bool frozen); + + virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor); + virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); + +private: + template <typename T> + struct Link { + T* next; + T* prev; + }; + + struct InjectionState { + mutable int32_t refCount; + + int32_t injectorPid; + int32_t injectorUid; + int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING + bool injectionIsAsync; // set to true if injection is not waiting for the result + int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress + }; + + struct EventEntry : Link<EventEntry> { + enum { + TYPE_SENTINEL, + TYPE_CONFIGURATION_CHANGED, + TYPE_KEY, + TYPE_MOTION + }; + + mutable int32_t refCount; + int32_t type; + nsecs_t eventTime; + uint32_t policyFlags; + InjectionState* injectionState; + + bool dispatchInProgress; // initially false, set to true while dispatching + + inline bool isInjected() { return injectionState != NULL; } + }; + + struct ConfigurationChangedEntry : EventEntry { + }; + + struct KeyEntry : EventEntry { + int32_t deviceId; + int32_t source; + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; + nsecs_t downTime; + + bool syntheticRepeat; // set to true for synthetic key repeats + + enum InterceptKeyResult { + INTERCEPT_KEY_RESULT_UNKNOWN, + INTERCEPT_KEY_RESULT_SKIP, + INTERCEPT_KEY_RESULT_CONTINUE, + }; + InterceptKeyResult interceptKeyResult; // set based on the interception result + }; + + struct MotionSample { + MotionSample* next; + + nsecs_t eventTime; + PointerCoords pointerCoords[MAX_POINTERS]; + }; + + struct MotionEntry : EventEntry { + int32_t deviceId; + int32_t source; + int32_t action; + int32_t flags; + int32_t metaState; + int32_t edgeFlags; + float xPrecision; + float yPrecision; + nsecs_t downTime; + uint32_t pointerCount; + int32_t pointerIds[MAX_POINTERS]; + + // Linked list of motion samples associated with this motion event. + MotionSample firstSample; + MotionSample* lastSample; + + uint32_t countSamples() const; + }; + + // 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; + float xOffset; + float yOffset; + + // True if dispatch has started. + bool inProgress; + + // For motion events: + // Pointer to the first motion sample to dispatch in this cycle. + // Usually NULL to indicate that the list of motion samples begins at + // MotionEntry::firstSample. Otherwise, some samples were dispatched in a previous + // cycle and this pointer indicates the location of the first remainining sample + // to dispatch during the current cycle. + MotionSample* headMotionSample; + // Pointer to a motion sample to dispatch in the next cycle if the dispatcher was + // unable to send all motion samples during this cycle. On the next cycle, + // headMotionSample will be initialized to tailMotionSample and tailMotionSample + // will be set to NULL. + MotionSample* tailMotionSample; + + inline bool hasForegroundTarget() const { + return targetFlags & InputTarget::FLAG_FOREGROUND; + } + + inline bool isSplit() const { + return targetFlags & InputTarget::FLAG_SPLIT; + } + }; + + // 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); + + class Connection; + struct CommandEntry : Link<CommandEntry> { + CommandEntry(); + ~CommandEntry(); + + Command command; + + // parameters for the command (usage varies by command) + sp<Connection> connection; + nsecs_t eventTime; + KeyEntry* keyEntry; + sp<InputChannel> inputChannel; + sp<InputApplicationHandle> inputApplicationHandle; + int32_t userActivityEventType; + }; + + // Generic queue implementation. + template <typename T> + struct Queue { + T headSentinel; + T tailSentinel; + + inline Queue() { + headSentinel.prev = NULL; + headSentinel.next = & tailSentinel; + tailSentinel.prev = & headSentinel; + tailSentinel.next = NULL; + } + + inline bool isEmpty() const { + return headSentinel.next == & tailSentinel; + } + + inline void enqueueAtTail(T* entry) { + T* last = tailSentinel.prev; + last->next = entry; + entry->prev = last; + entry->next = & tailSentinel; + tailSentinel.prev = entry; + } + + inline void enqueueAtHead(T* entry) { + T* first = headSentinel.next; + headSentinel.next = entry; + entry->prev = & headSentinel; + entry->next = first; + first->prev = entry; + } + + inline void dequeue(T* entry) { + entry->prev->next = entry->next; + entry->next->prev = entry->prev; + } + + inline T* dequeueAtHead() { + T* first = headSentinel.next; + dequeue(first); + return first; + } + + uint32_t count() const; + }; + + /* Allocates queue entries and performs reference counting as needed. */ + class Allocator { + public: + Allocator(); + + InjectionState* obtainInjectionState(int32_t injectorPid, int32_t injectorUid); + ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime); + KeyEntry* obtainKeyEntry(nsecs_t eventTime, + int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, + int32_t repeatCount, nsecs_t downTime); + MotionEntry* obtainMotionEntry(nsecs_t eventTime, + int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t metaState, int32_t edgeFlags, + float xPrecision, float yPrecision, + nsecs_t downTime, uint32_t pointerCount, + const int32_t* pointerIds, const PointerCoords* pointerCoords); + DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry, + int32_t targetFlags, float xOffset, float yOffset); + CommandEntry* obtainCommandEntry(Command command); + + void releaseInjectionState(InjectionState* injectionState); + 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 recycleKeyEntry(KeyEntry* entry); + + void appendMotionSample(MotionEntry* motionEntry, + nsecs_t eventTime, const PointerCoords* pointerCoords); + + private: + Pool<InjectionState> mInjectionStatePool; + Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool; + Pool<KeyEntry> mKeyEntryPool; + Pool<MotionEntry> mMotionEntryPool; + Pool<MotionSample> mMotionSamplePool; + Pool<DispatchEntry> mDispatchEntryPool; + Pool<CommandEntry> mCommandEntryPool; + + void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime, + uint32_t policyFlags); + void releaseEventEntryInjectionState(EventEntry* entry); + }; + + /* Tracks dispatched key and motion event state so that cancelation events can be + * synthesized when events are dropped. */ + class InputState { + public: + // Specifies whether a given event will violate input state consistency. + enum Consistency { + // The event is consistent with the current input state. + CONSISTENT, + // The event is inconsistent with the current input state but applications + // will tolerate it. eg. Down followed by another down. + TOLERABLE, + // The event is inconsistent with the current input state and will probably + // cause applications to crash. eg. Up without prior down, move with + // unexpected number of pointers. + BROKEN + }; + + // Specifies the sources to cancel. + enum CancelationOptions { + CANCEL_ALL_EVENTS = 0, + CANCEL_POINTER_EVENTS = 1, + CANCEL_NON_POINTER_EVENTS = 2, + }; + + InputState(); + ~InputState(); + + // Returns true if there is no state to be canceled. + bool isNeutral() const; + + // Records tracking information for an event that has just been published. + // Returns whether the event is consistent with the current input state. + Consistency trackEvent(const EventEntry* entry); + + // Records tracking information for a key event that has just been published. + // Returns whether the event is consistent with the current input state. + Consistency trackKey(const KeyEntry* entry); + + // Records tracking information for a motion event that has just been published. + // Returns whether the event is consistent with the current input state. + Consistency trackMotion(const MotionEntry* entry); + + // Synthesizes cancelation events for the current state and resets the tracked state. + void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator, + Vector<EventEntry*>& outEvents, CancelationOptions options); + + // Clears the current state. + void clear(); + + private: + struct KeyMemento { + int32_t deviceId; + int32_t source; + int32_t keyCode; + int32_t scanCode; + nsecs_t downTime; + }; + + struct MotionMemento { + int32_t deviceId; + int32_t source; + float xPrecision; + float yPrecision; + nsecs_t downTime; + uint32_t pointerCount; + int32_t pointerIds[MAX_POINTERS]; + PointerCoords pointerCoords[MAX_POINTERS]; + + void setPointers(const MotionEntry* entry); + }; + + Vector<KeyMemento> mKeyMementos; + Vector<MotionMemento> mMotionMementos; + + static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options); + }; + + /* Manages the dispatch state associated with a single input channel. */ + class Connection : public RefBase { + protected: + virtual ~Connection(); + + public: + enum Status { + // Everything is peachy. + STATUS_NORMAL, + // An unrecoverable communication error has occurred. + STATUS_BROKEN, + // The input channel has been unregistered. + STATUS_ZOMBIE + }; + + Status status; + sp<InputChannel> inputChannel; + InputPublisher inputPublisher; + InputState inputState; + Queue<DispatchEntry> outboundQueue; + + nsecs_t lastEventTime; // the time when the event was originally captured + nsecs_t lastDispatchTime; // the time when the last event was dispatched + + explicit Connection(const sp<InputChannel>& inputChannel); + + 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. + DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const; + + // Gets the time since the current event was originally obtained from the input driver. + inline double getEventLatencyMillis(nsecs_t currentTime) const { + return (currentTime - lastEventTime) / 1000000.0; + } + + // Gets the time since the current event entered the outbound dispatch queue. + inline double getDispatchLatencyMillis(nsecs_t currentTime) const { + return (currentTime - lastDispatchTime) / 1000000.0; + } + + status_t initialize(); + }; + + enum DropReason { + DROP_REASON_NOT_DROPPED = 0, + DROP_REASON_POLICY = 1, + DROP_REASON_APP_SWITCH = 2, + DROP_REASON_DISABLED = 3, + }; + + sp<InputDispatcherPolicyInterface> mPolicy; + + Mutex mLock; + + Allocator mAllocator; + sp<Looper> mLooper; + + EventEntry* mPendingEvent; + Queue<EventEntry> mInboundQueue; + Queue<CommandEntry> mCommandQueue; + + Vector<EventEntry*> mTempCancelationEvents; + + void dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, nsecs_t keyRepeatDelay, + nsecs_t* nextWakeupTime); + + // Enqueues an inbound event. Returns true if mLooper->wake() should be called. + bool enqueueInboundEventLocked(EventEntry* entry); + + // Cleans up input state when dropping an inbound event. + void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); + + // App switch latency optimization. + bool mAppSwitchSawKeyDown; + nsecs_t mAppSwitchDueTime; + + static bool isAppSwitchKeyCode(int32_t keyCode); + bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); + bool isAppSwitchPendingLocked(); + void resetPendingAppSwitchLocked(bool handled); + + // All registered connections mapped by receive pipe file descriptor. + KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd; + + ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel); + + // Active connections are connections that have a non-empty outbound queue. + // We don't use a ref-counted pointer here because we explicitly abort connections + // during unregistration which causes the connection's outbound queue to be cleared + // and the connection itself to be deactivated. + Vector<Connection*> mActiveConnections; + + // Input channels that will receive a copy of all input events. + Vector<sp<InputChannel> > mMonitoringChannels; + + // Preallocated key event object used for policy inquiries. + KeyEvent mReusableKeyEvent; + + // Event injection and synchronization. + Condition mInjectionResultAvailableCondition; + bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); + void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); + + Condition mInjectionSyncFinishedCondition; + void incrementPendingForegroundDispatchesLocked(EventEntry* entry); + void decrementPendingForegroundDispatchesLocked(EventEntry* entry); + + // Throttling state. + struct ThrottleState { + nsecs_t minTimeBetweenEvents; + + nsecs_t lastEventTime; + int32_t lastDeviceId; + uint32_t lastSource; + + uint32_t originalSampleCount; // only collected during debugging + } mThrottleState; + + // Key repeat tracking. + struct KeyRepeatState { + KeyEntry* lastKeyEntry; // or null if no repeat + nsecs_t nextRepeatTime; + } mKeyRepeatState; + + void resetKeyRepeatLocked(); + KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime, nsecs_t keyRepeatTimeout); + + // Deferred command processing. + bool runCommandsLockedInterruptible(); + CommandEntry* postCommandLocked(Command command); + + // Inbound event processing. + void drainInboundQueueLocked(); + void releasePendingEventLocked(); + void releaseInboundEventLocked(EventEntry* entry); + + // Dispatch state. + bool mDispatchEnabled; + bool mDispatchFrozen; + + Vector<InputWindow> mWindows; + + const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel); + + // Focus tracking for keys, trackball, etc. + const InputWindow* mFocusedWindow; + + // Focus tracking for touch. + struct TouchedWindow { + const InputWindow* window; + int32_t targetFlags; + BitSet32 pointerIds; + sp<InputChannel> channel; + }; + struct TouchState { + bool down; + bool split; + Vector<TouchedWindow> windows; + + TouchState(); + ~TouchState(); + void reset(); + void copyFrom(const TouchState& other); + void addOrUpdateWindow(const InputWindow* window, int32_t targetFlags, BitSet32 pointerIds); + void removeOutsideTouchWindows(); + const InputWindow* getFirstForegroundWindow(); + }; + + TouchState mTouchState; + TouchState mTempTouchState; + + // Focused application. + InputApplication* mFocusedApplication; + InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication + void releaseFocusedApplicationLocked(); + + // Dispatch inbound events. + bool dispatchConfigurationChangedLocked( + nsecs_t currentTime, ConfigurationChangedEntry* entry); + bool dispatchKeyLocked( + nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout, + DropReason* dropReason, nsecs_t* nextWakeupTime); + bool dispatchMotionLocked( + nsecs_t currentTime, MotionEntry* entry, + DropReason* dropReason, nsecs_t* nextWakeupTime); + void dispatchEventToCurrentInputTargetsLocked( + nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample); + + void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry); + void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry); + + // The input targets that were most recently identified for dispatch. + bool mCurrentInputTargetsValid; // false while targets are being recomputed + Vector<InputTarget> mCurrentInputTargets; + + enum InputTargetWaitCause { + INPUT_TARGET_WAIT_CAUSE_NONE, + INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, + INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, + }; + + InputTargetWaitCause mInputTargetWaitCause; + nsecs_t mInputTargetWaitStartTime; + nsecs_t mInputTargetWaitTimeoutTime; + bool mInputTargetWaitTimeoutExpired; + + // Finding targets for input events. + void resetTargetsLocked(); + void commitTargetsLocked(); + int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, + const InputApplication* application, const InputWindow* window, + nsecs_t* nextWakeupTime); + void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, + const sp<InputChannel>& inputChannel); + nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); + void resetANRTimeoutsLocked(); + + int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, + nsecs_t* nextWakeupTime); + int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, + nsecs_t* nextWakeupTime); + + void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags, + BitSet32 pointerIds); + void addMonitoringTargetsLocked(); + void pokeUserActivityLocked(const EventEntry* eventEntry); + bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState); + bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const; + bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window); + String8 getApplicationWindowLabelLocked(const InputApplication* application, + const InputWindow* window); + + // Manage the dispatch cycle for a single connection. + // These methods are deliberately not Interruptible because doing all of the work + // with the mutex held makes it easier to ensure that connection invariants are maintained. + // If needed, the methods post commands to run later once the critical bits are done. + void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, + EventEntry* eventEntry, const InputTarget* inputTarget, + bool resumeWithAppendedMotionSample); + void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); + void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); + void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); + void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); + void drainOutboundQueueLocked(Connection* connection); + static int handleReceiveCallback(int receiveFd, int events, void* data); + + void synthesizeCancelationEventsForAllConnectionsLocked( + InputState::CancelationOptions options, const char* reason); + void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, + InputState::CancelationOptions options, const char* reason); + void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, + InputState::CancelationOptions options, const char* reason); + + // Splitting motion events across windows. + MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); + + // Reset and drop everything the dispatcher is doing. + void resetAndDropEverythingLocked(const char* reason); + + // Dump state. + void dumpDispatchStateLocked(String8& dump); + void logDispatchStateLocked(); + + // Add or remove a connection to the mActiveConnections vector. + void activateConnectionLocked(Connection* connection); + void deactivateConnectionLocked(Connection* connection); + + // Interesting events that we might like to log or tell the framework about. + void onDispatchCycleStartedLocked( + nsecs_t currentTime, const sp<Connection>& connection); + void onDispatchCycleFinishedLocked( + nsecs_t currentTime, const sp<Connection>& connection); + void onDispatchCycleBrokenLocked( + nsecs_t currentTime, const sp<Connection>& connection); + void onANRLocked( + nsecs_t currentTime, const InputApplication* application, const InputWindow* window, + nsecs_t eventTime, nsecs_t waitStartTime); + + // Outbound policy interactions. + void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry); + void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); + void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); + void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); + void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); + + // Statistics gathering. + void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, + int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); +}; + +/* Enqueues and dispatches input events, endlessly. */ +class InputDispatcherThread : public Thread { +public: + explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher); + ~InputDispatcherThread(); + +private: + virtual bool threadLoop(); + + sp<InputDispatcherInterface> mDispatcher; +}; + +} // namespace android + +#endif // _UI_INPUT_DISPATCHER_H diff --git a/include/ui/InputManager.h b/include/ui/InputManager.h new file mode 100644 index 0000000..568568b --- /dev/null +++ b/include/ui/InputManager.h @@ -0,0 +1,115 @@ +/* + * 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_MANAGER_H +#define _UI_INPUT_MANAGER_H + +/** + * Native input manager. + */ + +#include <ui/EventHub.h> +#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; + +class InputReaderInterface; +class InputReaderPolicyInterface; +class InputReaderThread; + +class InputDispatcherInterface; +class InputDispatcherPolicyInterface; +class InputDispatcherThread; + +/* + * The input manager is the core of the system event processing. + * + * The input manager uses two threads. + * + * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events, + * applies policy, and posts messages to a queue managed by the DispatcherThread. + * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the + * queue and asynchronously dispatches them to applications. + * + * By design, the InputReaderThread class and InputDispatcherThread class do not share any + * internal state. Moreover, all communication is done one way from the InputReaderThread + * into the InputDispatcherThread and never the reverse. Both classes may interact with the + * InputDispatchPolicy, however. + * + * The InputManager class never makes any calls into Java itself. Instead, the + * InputDispatchPolicy is responsible for performing all external interactions with the + * system, including calling DVM services. + */ +class InputManagerInterface : public virtual RefBase { +protected: + InputManagerInterface() { } + virtual ~InputManagerInterface() { } + +public: + /* Starts the input manager threads. */ + virtual status_t start() = 0; + + /* Stops the input manager threads and waits for them to exit. */ + virtual status_t stop() = 0; + + /* Gets the input reader. */ + virtual sp<InputReaderInterface> getReader() = 0; + + /* Gets the input dispatcher. */ + virtual sp<InputDispatcherInterface> getDispatcher() = 0; +}; + +class InputManager : public InputManagerInterface { +protected: + virtual ~InputManager(); + +public: + 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(); + + virtual sp<InputReaderInterface> getReader(); + virtual sp<InputDispatcherInterface> getDispatcher(); + +private: + sp<InputReaderInterface> mReader; + sp<InputReaderThread> mReaderThread; + + sp<InputDispatcherInterface> mDispatcher; + sp<InputDispatcherThread> mDispatcherThread; + + void initialize(); +}; + +} // namespace android + +#endif // _UI_INPUT_MANAGER_H diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h new file mode 100644 index 0000000..49351b0 --- /dev/null +++ b/include/ui/InputReader.h @@ -0,0 +1,927 @@ +/* + * 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_READER_H +#define _UI_INPUT_READER_H + +#include <ui/EventHub.h> +#include <ui/Input.h> +#include <ui/InputDispatcher.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/BitSet.h> + +#include <stddef.h> +#include <unistd.h> + +namespace android { + +class InputDevice; +class InputMapper; + +/* 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; +}; + + +/* Specifies input device calibration settings. */ +class InputDeviceCalibration { +public: + InputDeviceCalibration(); + + void clear(); + void addProperty(const String8& key, const String8& value); + + bool tryGetProperty(const String8& key, String8& outValue) const; + bool tryGetProperty(const String8& key, int32_t& outValue) const; + bool tryGetProperty(const String8& key, float& outValue) const; + +private: + KeyedVector<String8, String8> mProperties; +}; + + +/* + * 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 + }; + + /* 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; + + /* 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 calibration for an input device. */ + virtual void getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration) = 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() { } + virtual ~InputReaderInterface() { } + +public: + /* Dumps the state of the input reader. + * + * This method may be called on any thread (usually by the input manager). */ + virtual void dump(String8& dump) = 0; + + /* Runs a single iteration of the processing loop. + * Nominally reads and processes one incoming message from the EventHub. + * + * This method should be called on the input reader thread. + */ + virtual void loopOnce() = 0; + + /* Gets the current input device configuration. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual void getInputConfiguration(InputConfiguration* outConfiguration) = 0; + + /* Gets information about the specified input device. + * Returns OK if the device information was obtained or NAME_NOT_FOUND if there + * was no such device. + * + * This method may be called on any thread (usually by the input manager). + */ + virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) = 0; + + /* Gets the list of all registered device ids. */ + virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds) = 0; + + /* Query current input state. */ + virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t scanCode) = 0; + virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t keyCode) = 0; + virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, + int32_t sw) = 0; + + /* Determine whether physical keys exist for the given framework-domain key codes. */ + virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, + size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; +}; + + +/* Internal interface used by individual input devices to access global input device state + * and parameters maintained by the input reader. + */ +class InputReaderContext { +public: + InputReaderContext() { } + virtual ~InputReaderContext() { } + + virtual void updateGlobalMetaState() = 0; + virtual int32_t getGlobalMetaState() = 0; + + virtual InputReaderPolicyInterface* getPolicy() = 0; + virtual InputDispatcherInterface* getDispatcher() = 0; + virtual EventHubInterface* getEventHub() = 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, such as early + * event filtering in low power states, are controlled by a separate policy object. + * + * IMPORTANT INVARIANT: + * Because the policy and dispatcher can potentially block or cause re-entrance into + * the input reader, the input reader never calls into other components while holding + * an exclusive internal lock whenever re-entrance can happen. + */ +class InputReader : public InputReaderInterface, protected InputReaderContext { +public: + InputReader(const sp<EventHubInterface>& eventHub, + const sp<InputReaderPolicyInterface>& policy, + const sp<InputDispatcherInterface>& dispatcher); + virtual ~InputReader(); + + virtual void dump(String8& dump); + + virtual void loopOnce(); + + virtual void getInputConfiguration(InputConfiguration* outConfiguration); + + virtual status_t getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo); + virtual void getInputDeviceIds(Vector<int32_t>& outDeviceIds); + + virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t scanCode); + virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, + int32_t keyCode); + virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, + int32_t sw); + + virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, + size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); + +protected: + // These methods are protected virtual so they can be overridden and instrumented + // by test cases. + virtual InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); + +private: + sp<EventHubInterface> mEventHub; + sp<InputReaderPolicyInterface> mPolicy; + sp<InputDispatcherInterface> mDispatcher; + + virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); } + virtual InputDispatcherInterface* getDispatcher() { return mDispatcher.get(); } + virtual EventHubInterface* getEventHub() { return mEventHub.get(); } + + // This reader/writer lock guards the list of input devices. + // The writer lock must be held whenever the list of input devices is modified + // and then promptly released. + // The reader lock must be held whenever the list of input devices is traversed or an + // input device in the list is accessed. + // This lock only protects the registry and prevents inadvertent deletion of device objects + // that are in use. Individual devices are responsible for guarding their own internal state + // as needed for concurrent operation. + RWLock mDeviceRegistryLock; + KeyedVector<int32_t, InputDevice*> mDevices; + + // low-level input event decoding and device management + void process(const RawEvent* rawEvent); + + void addDevice(int32_t deviceId); + void removeDevice(int32_t deviceId); + void configureExcludedDevices(); + + void consumeEvent(const RawEvent* rawEvent); + + void handleConfigurationChanged(nsecs_t when); + + // state management for all devices + Mutex mStateLock; + + int32_t mGlobalMetaState; + virtual void updateGlobalMetaState(); + virtual int32_t getGlobalMetaState(); + + InputConfiguration mInputConfiguration; + void updateInputConfiguration(); + + // state queries + typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); + int32_t getState(int32_t deviceId, uint32_t sourceMask, int32_t code, + GetStateFunc getStateFunc); + bool markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); +}; + + +/* Reads raw events from the event hub and processes them, endlessly. */ +class InputReaderThread : public Thread { +public: + InputReaderThread(const sp<InputReaderInterface>& reader); + virtual ~InputReaderThread(); + +private: + sp<InputReaderInterface> mReader; + + virtual bool threadLoop(); +}; + + +/* Represents the state of a single input device. */ +class InputDevice { +public: + InputDevice(InputReaderContext* context, int32_t id, const String8& name); + ~InputDevice(); + + inline InputReaderContext* getContext() { return mContext; } + inline int32_t getId() { return mId; } + inline const String8& getName() { return mName; } + inline uint32_t getSources() { return mSources; } + + inline bool isIgnored() { return mMappers.isEmpty(); } + + void dump(String8& dump); + void addMapper(InputMapper* mapper); + void configure(); + void reset(); + void process(const RawEvent* rawEvent); + + void getDeviceInfo(InputDeviceInfo* outDeviceInfo); + int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + int32_t getMetaState(); + + inline const InputDeviceCalibration& getCalibration() { + return mCalibration; + } + +private: + InputReaderContext* mContext; + int32_t mId; + + Vector<InputMapper*> mMappers; + + String8 mName; + uint32_t mSources; + + typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); + int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); + + InputDeviceCalibration mCalibration; +}; + + +/* An input mapper transforms raw input events into cooked event data. + * A single input device can have multiple associated input mappers in order to interpret + * different classes of events. + */ +class InputMapper { +public: + InputMapper(InputDevice* device); + virtual ~InputMapper(); + + inline InputDevice* getDevice() { return mDevice; } + inline int32_t getDeviceId() { return mDevice->getId(); } + inline const String8 getDeviceName() { return mDevice->getName(); } + inline InputReaderContext* getContext() { return mContext; } + inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } + inline InputDispatcherInterface* getDispatcher() { return mContext->getDispatcher(); } + inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + + virtual uint32_t getSources() = 0; + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void configure(); + virtual void reset(); + virtual void process(const RawEvent* rawEvent) = 0; + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual int32_t getMetaState(); + +protected: + InputDevice* mDevice; + InputReaderContext* mContext; +}; + + +class SwitchInputMapper : public InputMapper { +public: + SwitchInputMapper(InputDevice* device); + virtual ~SwitchInputMapper(); + + virtual uint32_t getSources(); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); + +private: + void processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue); +}; + + +class KeyboardInputMapper : public InputMapper { +public: + KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId, uint32_t sources, + int32_t keyboardType); + virtual ~KeyboardInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void reset(); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + + virtual int32_t getMetaState(); + +private: + Mutex mLock; + + struct KeyDown { + int32_t keyCode; + int32_t scanCode; + }; + + int32_t mAssociatedDisplayId; + uint32_t mSources; + int32_t mKeyboardType; + + struct LockedState { + Vector<KeyDown> keyDowns; // keys that are down + int32_t metaState; + nsecs_t downTime; // time of most recent key down + } mLocked; + + void initializeLocked(); + + bool isKeyboardOrGamepadKey(int32_t scanCode); + + void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, + uint32_t policyFlags); + + ssize_t findKeyDownLocked(int32_t scanCode); +}; + + +class TrackballInputMapper : public InputMapper { +public: + TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId); + virtual ~TrackballInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void reset(); + virtual void process(const RawEvent* rawEvent); + + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + +private: + // Amount that trackball needs to move in order to generate a key event. + static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; + + Mutex mLock; + + int32_t mAssociatedDisplayId; + + struct Accumulator { + enum { + FIELD_BTN_MOUSE = 1, + FIELD_REL_X = 2, + FIELD_REL_Y = 4 + }; + + uint32_t fields; + + bool btnMouse; + int32_t relX; + int32_t relY; + + inline void clear() { + fields = 0; + } + } mAccumulator; + + float mXScale; + float mYScale; + float mXPrecision; + float mYPrecision; + + struct LockedState { + bool down; + nsecs_t downTime; + } mLocked; + + void initializeLocked(); + + void sync(nsecs_t when); +}; + + +class TouchInputMapper : public InputMapper { +public: + TouchInputMapper(InputDevice* device, int32_t associatedDisplayId); + virtual ~TouchInputMapper(); + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void configure(); + virtual void reset(); + + virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); + virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, + const int32_t* keyCodes, uint8_t* outFlags); + +protected: + Mutex mLock; + + struct VirtualKey { + int32_t keyCode; + int32_t scanCode; + uint32_t flags; + + // computed hit box, specified in touch screen coords based on known display size + int32_t hitLeft; + int32_t hitTop; + int32_t hitRight; + int32_t hitBottom; + + inline bool isHit(int32_t x, int32_t y) const { + return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; + } + }; + + // Raw data for a single pointer. + struct PointerData { + uint32_t id; + int32_t x; + int32_t y; + int32_t pressure; + int32_t touchMajor; + int32_t touchMinor; + int32_t toolMajor; + int32_t toolMinor; + int32_t orientation; + + inline bool operator== (const PointerData& other) const { + return id == other.id + && x == other.x + && y == other.y + && pressure == other.pressure + && touchMajor == other.touchMajor + && touchMinor == other.touchMinor + && toolMajor == other.toolMajor + && toolMinor == other.toolMinor + && orientation == other.orientation; + } + inline bool operator!= (const PointerData& other) const { + return !(*this == other); + } + }; + + // Raw data for a collection of pointers including a pointer id mapping table. + struct TouchData { + uint32_t pointerCount; + PointerData pointers[MAX_POINTERS]; + BitSet32 idBits; + uint32_t idToIndex[MAX_POINTER_ID + 1]; + + void copyFrom(const TouchData& other) { + pointerCount = other.pointerCount; + idBits = other.idBits; + + for (uint32_t i = 0; i < pointerCount; i++) { + pointers[i] = other.pointers[i]; + + int id = pointers[i].id; + idToIndex[id] = other.idToIndex[id]; + } + } + + inline void clear() { + pointerCount = 0; + idBits.clear(); + } + }; + + int32_t mAssociatedDisplayId; + + // Immutable configuration parameters. + struct Parameters { + bool useBadTouchFilter; + bool useJumpyTouchFilter; + bool useAveragingTouchFilter; + } mParameters; + + // Immutable calibration parameters in parsed form. + struct Calibration { + // Touch Size + enum TouchSizeCalibration { + TOUCH_SIZE_CALIBRATION_DEFAULT, + TOUCH_SIZE_CALIBRATION_NONE, + TOUCH_SIZE_CALIBRATION_GEOMETRIC, + TOUCH_SIZE_CALIBRATION_PRESSURE, + }; + + TouchSizeCalibration touchSizeCalibration; + + // Tool Size + enum ToolSizeCalibration { + TOOL_SIZE_CALIBRATION_DEFAULT, + TOOL_SIZE_CALIBRATION_NONE, + TOOL_SIZE_CALIBRATION_GEOMETRIC, + TOOL_SIZE_CALIBRATION_LINEAR, + TOOL_SIZE_CALIBRATION_AREA, + }; + + ToolSizeCalibration toolSizeCalibration; + bool haveToolSizeLinearScale; + float toolSizeLinearScale; + bool haveToolSizeLinearBias; + float toolSizeLinearBias; + bool haveToolSizeAreaScale; + float toolSizeAreaScale; + bool haveToolSizeAreaBias; + float toolSizeAreaBias; + bool haveToolSizeIsSummed; + int32_t toolSizeIsSummed; + + // Pressure + enum PressureCalibration { + PRESSURE_CALIBRATION_DEFAULT, + PRESSURE_CALIBRATION_NONE, + PRESSURE_CALIBRATION_PHYSICAL, + PRESSURE_CALIBRATION_AMPLITUDE, + }; + enum PressureSource { + PRESSURE_SOURCE_DEFAULT, + PRESSURE_SOURCE_PRESSURE, + PRESSURE_SOURCE_TOUCH, + }; + + PressureCalibration pressureCalibration; + PressureSource pressureSource; + bool havePressureScale; + float pressureScale; + + // Size + enum SizeCalibration { + SIZE_CALIBRATION_DEFAULT, + SIZE_CALIBRATION_NONE, + SIZE_CALIBRATION_NORMALIZED, + }; + + SizeCalibration sizeCalibration; + + // Orientation + enum OrientationCalibration { + ORIENTATION_CALIBRATION_DEFAULT, + ORIENTATION_CALIBRATION_NONE, + ORIENTATION_CALIBRATION_INTERPOLATED, + }; + + OrientationCalibration orientationCalibration; + } mCalibration; + + // Raw axis information from the driver. + struct RawAxes { + RawAbsoluteAxisInfo x; + RawAbsoluteAxisInfo y; + RawAbsoluteAxisInfo pressure; + RawAbsoluteAxisInfo touchMajor; + RawAbsoluteAxisInfo touchMinor; + RawAbsoluteAxisInfo toolMajor; + RawAbsoluteAxisInfo toolMinor; + RawAbsoluteAxisInfo orientation; + } mRawAxes; + + // Current and previous touch sample data. + TouchData mCurrentTouch; + TouchData mLastTouch; + + // The time the primary pointer last went down. + nsecs_t mDownTime; + + struct LockedState { + Vector<VirtualKey> virtualKeys; + + // The surface orientation and width and height set by configureSurfaceLocked(). + int32_t surfaceOrientation; + int32_t surfaceWidth, surfaceHeight; + + // Translation and scaling factors, orientation-independent. + int32_t xOrigin; + float xScale; + float xPrecision; + + int32_t yOrigin; + float yScale; + float yPrecision; + + float geometricScale; + + float toolSizeLinearScale; + float toolSizeLinearBias; + float toolSizeAreaScale; + float toolSizeAreaBias; + + float pressureScale; + + float sizeScale; + + float orientationScale; + + // Oriented motion ranges for input device info. + struct OrientedRanges { + InputDeviceInfo::MotionRange x; + InputDeviceInfo::MotionRange y; + + bool havePressure; + InputDeviceInfo::MotionRange pressure; + + bool haveSize; + InputDeviceInfo::MotionRange size; + + bool haveTouchSize; + InputDeviceInfo::MotionRange touchMajor; + InputDeviceInfo::MotionRange touchMinor; + + bool haveToolSize; + InputDeviceInfo::MotionRange toolMajor; + InputDeviceInfo::MotionRange toolMinor; + + bool haveOrientation; + InputDeviceInfo::MotionRange orientation; + } orientedRanges; + + // Oriented dimensions and precision. + float orientedSurfaceWidth, orientedSurfaceHeight; + float orientedXPrecision, orientedYPrecision; + + struct CurrentVirtualKeyState { + bool down; + nsecs_t downTime; + int32_t keyCode; + int32_t scanCode; + } currentVirtualKey; + } mLocked; + + virtual void configureParameters(); + virtual void dumpParameters(String8& dump); + virtual void configureRawAxes(); + virtual void dumpRawAxes(String8& dump); + virtual bool configureSurfaceLocked(); + virtual void dumpSurfaceLocked(String8& dump); + virtual void configureVirtualKeysLocked(); + virtual void dumpVirtualKeysLocked(String8& dump); + virtual void parseCalibration(); + virtual void resolveCalibration(); + virtual void dumpCalibration(String8& dump); + + enum TouchResult { + // Dispatch the touch normally. + DISPATCH_TOUCH, + // Do not dispatch the touch, but keep tracking the current stroke. + SKIP_TOUCH, + // Do not dispatch the touch, and drop all information associated with the current stoke + // so the next movement will appear as a new down. + DROP_STROKE + }; + + void syncTouch(nsecs_t when, bool havePointerIds); + +private: + /* Maximum number of historical samples to average. */ + static const uint32_t AVERAGING_HISTORY_SIZE = 5; + + /* Slop distance for jumpy pointer detection. + * The vertical range of the screen divided by this is our epsilon value. */ + static const uint32_t JUMPY_EPSILON_DIVISOR = 212; + + /* Number of jumpy points to drop for touchscreens that need it. */ + static const uint32_t JUMPY_TRANSITION_DROPS = 3; + static const uint32_t JUMPY_DROP_LIMIT = 3; + + /* Maximum squared distance for averaging. + * If moving farther than this, turn of averaging to avoid lag in response. */ + static const uint64_t AVERAGING_DISTANCE_LIMIT = 75 * 75; + + struct AveragingTouchFilterState { + // Individual history tracks are stored by pointer id + uint32_t historyStart[MAX_POINTERS]; + uint32_t historyEnd[MAX_POINTERS]; + struct { + struct { + int32_t x; + int32_t y; + int32_t pressure; + } pointers[MAX_POINTERS]; + } historyData[AVERAGING_HISTORY_SIZE]; + } mAveragingTouchFilter; + + struct JumpyTouchFilterState { + uint32_t jumpyPointsDropped; + } mJumpyTouchFilter; + + struct PointerDistanceHeapElement { + uint32_t currentPointerIndex : 8; + uint32_t lastPointerIndex : 8; + uint64_t distance : 48; // squared distance + }; + + void initializeLocked(); + + TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags); + void dispatchTouches(nsecs_t when, uint32_t policyFlags); + void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch, + BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, + int32_t motionEventAction); + + bool isPointInsideSurfaceLocked(int32_t x, int32_t y); + const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y); + + bool applyBadTouchFilter(); + bool applyJumpyTouchFilter(); + void applyAveragingTouchFilter(); + void calculatePointerIds(); +}; + + +class SingleTouchInputMapper : public TouchInputMapper { +public: + SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId); + virtual ~SingleTouchInputMapper(); + + virtual void reset(); + virtual void process(const RawEvent* rawEvent); + +protected: + virtual void configureRawAxes(); + +private: + struct Accumulator { + enum { + FIELD_BTN_TOUCH = 1, + FIELD_ABS_X = 2, + FIELD_ABS_Y = 4, + FIELD_ABS_PRESSURE = 8, + FIELD_ABS_TOOL_WIDTH = 16 + }; + + uint32_t fields; + + bool btnTouch; + int32_t absX; + int32_t absY; + int32_t absPressure; + int32_t absToolWidth; + + inline void clear() { + fields = 0; + } + } mAccumulator; + + bool mDown; + int32_t mX; + int32_t mY; + int32_t mPressure; + int32_t mToolWidth; + + void initialize(); + + void sync(nsecs_t when); +}; + + +class MultiTouchInputMapper : public TouchInputMapper { +public: + MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId); + virtual ~MultiTouchInputMapper(); + + virtual void reset(); + virtual void process(const RawEvent* rawEvent); + +protected: + virtual void configureRawAxes(); + +private: + struct Accumulator { + enum { + FIELD_ABS_MT_POSITION_X = 1, + FIELD_ABS_MT_POSITION_Y = 2, + FIELD_ABS_MT_TOUCH_MAJOR = 4, + FIELD_ABS_MT_TOUCH_MINOR = 8, + FIELD_ABS_MT_WIDTH_MAJOR = 16, + FIELD_ABS_MT_WIDTH_MINOR = 32, + FIELD_ABS_MT_ORIENTATION = 64, + FIELD_ABS_MT_TRACKING_ID = 128, + FIELD_ABS_MT_PRESSURE = 256, + }; + + uint32_t pointerCount; + struct Pointer { + uint32_t fields; + + int32_t absMTPositionX; + int32_t absMTPositionY; + int32_t absMTTouchMajor; + int32_t absMTTouchMinor; + int32_t absMTWidthMajor; + int32_t absMTWidthMinor; + int32_t absMTOrientation; + int32_t absMTTrackingId; + int32_t absMTPressure; + + inline void clear() { + fields = 0; + } + } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks + + inline void clear() { + pointerCount = 0; + pointers[0].clear(); + } + } mAccumulator; + + void initialize(); + + void sync(nsecs_t when); +}; + +} // namespace android + +#endif // _UI_INPUT_READER_H diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h new file mode 100644 index 0000000..dc9e27a --- /dev/null +++ b/include/ui/InputTransport.h @@ -0,0 +1,335 @@ +/* + * 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_TRANSPORT_H +#define _UI_INPUT_TRANSPORT_H + +/** + * Native input transport. + * + * Uses anonymous shared memory as a whiteboard for sending input events from an + * InputPublisher to an InputConsumer and ensuring appropriate synchronization. + * One interesting feature is that published events can be updated in place as long as they + * have not yet been consumed. + * + * The InputPublisher and InputConsumer only take care of transferring event data + * over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue + * build on these abstractions to add multiplexing and queueing. + */ + +#include <semaphore.h> +#include <ui/Input.h> +#include <utils/Errors.h> +#include <utils/Timers.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +namespace android { + +/* + * An input channel consists of a shared memory buffer and a pair of pipes + * used to send input messages from an InputPublisher to an InputConsumer + * across processes. Each channel has a descriptive name for debugging purposes. + * + * Each endpoint has its own InputChannel object that specifies its own file descriptors. + * + * The input channel is closed when all references to it are released. + */ +class InputChannel : public RefBase { +protected: + virtual ~InputChannel(); + +public: + InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd, + int32_t sendPipeFd); + + /* Creates a pair of input channels and their underlying shared memory buffers + * and pipes. + * + * Returns OK on success. + */ + static status_t openInputChannelPair(const String8& name, + sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel); + + inline String8 getName() const { return mName; } + inline int32_t getAshmemFd() const { return mAshmemFd; } + inline int32_t getReceivePipeFd() const { return mReceivePipeFd; } + inline int32_t getSendPipeFd() const { return mSendPipeFd; } + + /* Sends a signal to the other endpoint. + * + * Returns OK on success. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t sendSignal(char signal); + + /* Receives a signal send by the other endpoint. + * (Should only call this after poll() indicates that the receivePipeFd has available input.) + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no signal present. + * Returns DEAD_OBJECT if the channel's peer has been closed. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveSignal(char* outSignal); + +private: + String8 mName; + int32_t mAshmemFd; + int32_t mReceivePipeFd; + int32_t mSendPipeFd; +}; + +/* + * Private intermediate representation of input events as messages written into an + * ashmem buffer. + */ +struct InputMessage { + /* Semaphore count is set to 1 when the message is published. + * It becomes 0 transiently while the publisher updates the message. + * It becomes 0 permanently when the consumer consumes the message. + */ + sem_t semaphore; + + /* Initialized to false by the publisher. + * Set to true by the consumer when it consumes the message. + */ + bool consumed; + + int32_t type; + + struct SampleData { + nsecs_t eventTime; + PointerCoords coords[0]; // variable length + }; + + int32_t deviceId; + int32_t source; + + union { + struct { + int32_t action; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; + nsecs_t downTime; + nsecs_t eventTime; + } key; + + struct { + int32_t action; + int32_t flags; + int32_t metaState; + int32_t edgeFlags; + nsecs_t downTime; + float xOffset; + float yOffset; + float xPrecision; + float yPrecision; + size_t pointerCount; + int32_t pointerIds[MAX_POINTERS]; + size_t sampleCount; + SampleData sampleData[0]; // variable length + } motion; + }; + + /* Gets the number of bytes to add to step to the next SampleData object in a motion + * event message for a given number of pointers. + */ + static inline size_t sampleDataStride(size_t pointerCount) { + return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords); + } + + /* Adds the SampleData stride to the given pointer. */ + static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) { + return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride); + } +}; + +/* + * Publishes input events to an anonymous shared memory buffer. + * Uses atomic operations to coordinate shared access with a single concurrent consumer. + */ +class InputPublisher { +public: + /* Creates a publisher associated with an input channel. */ + explicit InputPublisher(const sp<InputChannel>& channel); + + /* Destroys the publisher and releases its input channel. */ + ~InputPublisher(); + + /* Gets the underlying input channel. */ + inline sp<InputChannel> getChannel() { return mChannel; } + + /* Prepares the publisher for use. Must be called before it is used. + * Returns OK on success. + * + * This method implicitly calls reset(). */ + status_t initialize(); + + /* Resets the publisher to its initial state and unpins its ashmem buffer. + * Returns OK on success. + * + * Should be called after an event has been consumed to release resources used by the + * publisher until the next event is ready to be published. + */ + status_t reset(); + + /* Publishes a key event to the ashmem buffer. + * + * Returns OK on success. + * Returns INVALID_OPERATION if the publisher has not been reset. + */ + status_t publishKeyEvent( + int32_t deviceId, + int32_t source, + int32_t action, + int32_t flags, + int32_t keyCode, + int32_t scanCode, + int32_t metaState, + int32_t repeatCount, + nsecs_t downTime, + nsecs_t eventTime); + + /* Publishes a motion event to the ashmem buffer. + * + * Returns OK on success. + * Returns INVALID_OPERATION if the publisher has not been reset. + * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS. + */ + status_t publishMotionEvent( + int32_t deviceId, + int32_t source, + int32_t action, + int32_t flags, + int32_t edgeFlags, + int32_t metaState, + float xOffset, + float yOffset, + float xPrecision, + float yPrecision, + nsecs_t downTime, + nsecs_t eventTime, + size_t pointerCount, + const int32_t* pointerIds, + const PointerCoords* pointerCoords); + + /* Appends a motion sample to a motion event unless already consumed. + * + * Returns OK on success. + * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event. + * Returns FAILED_TRANSACTION if the current event has already been consumed. + * Returns NO_MEMORY if the buffer is full and no additional samples can be added. + */ + status_t appendMotionSample( + nsecs_t eventTime, + const PointerCoords* pointerCoords); + + /* Sends a dispatch signal to the consumer to inform it that a new message is available. + * + * Returns OK on success. + * Errors probably indicate that the channel is broken. + */ + status_t sendDispatchSignal(); + + /* Receives the finished signal from the consumer in reply to the original dispatch signal. + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no signal present. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveFinishedSignal(); + +private: + sp<InputChannel> mChannel; + + size_t mAshmemSize; + InputMessage* mSharedMessage; + bool mPinned; + bool mSemaphoreInitialized; + bool mWasDispatched; + + size_t mMotionEventPointerCount; + InputMessage::SampleData* mMotionEventSampleDataTail; + size_t mMotionEventSampleDataStride; + + status_t publishInputEvent( + int32_t type, + int32_t deviceId, + int32_t source); +}; + +/* + * Consumes input events from an anonymous shared memory buffer. + * Uses atomic operations to coordinate shared access with a single concurrent publisher. + */ +class InputConsumer { +public: + /* Creates a consumer associated with an input channel. */ + explicit InputConsumer(const sp<InputChannel>& channel); + + /* Destroys the consumer and releases its input channel. */ + ~InputConsumer(); + + /* Gets the underlying input channel. */ + inline sp<InputChannel> getChannel() { return mChannel; } + + /* Prepares the consumer for use. Must be called before it is used. */ + status_t initialize(); + + /* Consumes the input event in the buffer and copies its contents into + * an InputEvent object created using the specified factory. + * This operation will block if the publisher is updating the event. + * + * Returns OK on success. + * Returns INVALID_OPERATION if there is no currently published event. + * Returns NO_MEMORY if the event could not be created. + */ + status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent); + + /* Sends a finished signal to the publisher to inform it that the current message is + * finished processing. + * + * Returns OK on success. + * Errors probably indicate that the channel is broken. + */ + status_t sendFinishedSignal(); + + /* Receives the dispatched signal from the publisher. + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no signal present. + * Other errors probably indicate that the channel is broken. + */ + status_t receiveDispatchSignal(); + +private: + sp<InputChannel> mChannel; + + size_t mAshmemSize; + InputMessage* mSharedMessage; + + void populateKeyEvent(KeyEvent* keyEvent) const; + void populateMotionEvent(MotionEvent* motionEvent) const; +}; + +} // namespace android + +#endif // _UI_INPUT_TRANSPORT_H diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index e81d0f9..f71d9cd 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -17,6 +17,8 @@ #ifndef _UI_KEYCODE_LABELS_H #define _UI_KEYCODE_LABELS_H +#include <android/keycodes.h> + struct KeycodeLabel { const char *literal; int value; @@ -118,117 +120,29 @@ static const KeycodeLabel KEYCODES[] = { { "PAGE_DOWN", 93 }, { "PICTSYMBOLS", 94 }, { "SWITCH_CHARSET", 95 }, + { "BUTTON_A", 96 }, + { "BUTTON_B", 97 }, + { "BUTTON_C", 98 }, + { "BUTTON_X", 99 }, + { "BUTTON_Y", 100 }, + { "BUTTON_Z", 101 }, + { "BUTTON_L1", 102 }, + { "BUTTON_R1", 103 }, + { "BUTTON_L2", 104 }, + { "BUTTON_R2", 105 }, + { "BUTTON_THUMBL", 106 }, + { "BUTTON_THUMBR", 107 }, + { "BUTTON_START", 108 }, + { "BUTTON_SELECT", 109 }, + { "BUTTON_MODE", 110 }, - // NOTE: If you add a new keycode here you must also add it to: - // (enum KeyCode, in this file) - // frameworks/base/core/java/android/view/KeyEvent.java - // tools/puppet_master/PuppetMaster.nav_keys.py - // frameworks/base/core/res/res/values/attrs.xml + // NOTE: If you add a new keycode here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. { NULL, 0 } }; -// These constants need to match the above mappings. -typedef enum KeyCode { - kKeyCodeUnknown = 0, - - kKeyCodeSoftLeft = 1, - kKeyCodeSoftRight = 2, - kKeyCodeHome = 3, - kKeyCodeBack = 4, - kKeyCodeCall = 5, - kKeyCodeEndCall = 6, - kKeyCode0 = 7, - kKeyCode1 = 8, - kKeyCode2 = 9, - kKeyCode3 = 10, - kKeyCode4 = 11, - kKeyCode5 = 12, - kKeyCode6 = 13, - kKeyCode7 = 14, - kKeyCode8 = 15, - kKeyCode9 = 16, - kKeyCodeStar = 17, - kKeyCodePound = 18, - kKeyCodeDpadUp = 19, - kKeyCodeDpadDown = 20, - kKeyCodeDpadLeft = 21, - kKeyCodeDpadRight = 22, - kKeyCodeDpadCenter = 23, - kKeyCodeVolumeUp = 24, - kKeyCodeVolumeDown = 25, - kKeyCodePower = 26, - kKeyCodeCamera = 27, - kKeyCodeClear = 28, - kKeyCodeA = 29, - kKeyCodeB = 30, - kKeyCodeC = 31, - kKeyCodeD = 32, - kKeyCodeE = 33, - kKeyCodeF = 34, - kKeyCodeG = 35, - kKeyCodeH = 36, - kKeyCodeI = 37, - kKeyCodeJ = 38, - kKeyCodeK = 39, - kKeyCodeL = 40, - kKeyCodeM = 41, - kKeyCodeN = 42, - kKeyCodeO = 43, - kKeyCodeP = 44, - kKeyCodeQ = 45, - kKeyCodeR = 46, - kKeyCodeS = 47, - kKeyCodeT = 48, - kKeyCodeU = 49, - kKeyCodeV = 50, - kKeyCodeW = 51, - kKeyCodeX = 52, - kKeyCodeY = 53, - kKeyCodeZ = 54, - kKeyCodeComma = 55, - kKeyCodePeriod = 56, - kKeyCodeAltLeft = 57, - kKeyCodeAltRight = 58, - kKeyCodeShiftLeft = 59, - kKeyCodeShiftRight = 60, - kKeyCodeTab = 61, - kKeyCodeSpace = 62, - kKeyCodeSym = 63, - kKeyCodeExplorer = 64, - kKeyCodeEnvelope = 65, - kKeyCodeNewline = 66, - kKeyCodeDel = 67, - kKeyCodeGrave = 68, - kKeyCodeMinus = 69, - kKeyCodeEquals = 70, - kKeyCodeLeftBracket = 71, - kKeyCodeRightBracket = 72, - kKeyCodeBackslash = 73, - kKeyCodeSemicolon = 74, - kKeyCodeApostrophe = 75, - kKeyCodeSlash = 76, - kKeyCodeAt = 77, - kKeyCodeNum = 78, - kKeyCodeHeadSetHook = 79, - kKeyCodeFocus = 80, - kKeyCodePlus = 81, - kKeyCodeMenu = 82, - kKeyCodeNotification = 83, - kKeyCodeSearch = 84, - kKeyCodePlayPause = 85, - kKeyCodeStop = 86, - kKeyCodeNextSong = 87, - kKeyCodePreviousSong = 88, - kKeyCodeRewind = 89, - kKeyCodeForward = 90, - kKeyCodeMute = 91, - kKeyCodePageUp = 92, - kKeyCodePageDown = 93, - kKeyCodePictSymbols = 94, - kKeyCodeSwitchCharset = 95 -} KeyCode; - +// See also policy flags in Input.h. static const KeycodeLabel FLAGS[] = { { "WAKE", 0x00000001 }, { "WAKE_DROPPED", 0x00000002 }, @@ -238,6 +152,7 @@ static const KeycodeLabel FLAGS[] = { { "ALT_GR", 0x00000020 }, { "MENU", 0x00000040 }, { "LAUNCHER", 0x00000080 }, + { "VIRTUAL", 0x00000100 }, { NULL, 0 } }; diff --git a/include/ui/PowerManager.h b/include/ui/PowerManager.h new file mode 100644 index 0000000..5434b4f --- /dev/null +++ b/include/ui/PowerManager.h @@ -0,0 +1,37 @@ +/* + * 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_POWER_MANAGER_H +#define _UI_POWER_MANAGER_H + + +namespace android { + +enum { + POWER_MANAGER_OTHER_EVENT = 0, + POWER_MANAGER_CHEEK_EVENT = 1, + POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either + // up events or LONG_TOUCH events. + POWER_MANAGER_LONG_TOUCH_EVENT = 3, + POWER_MANAGER_TOUCH_UP_EVENT = 4, + POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events. + + POWER_MANAGER_LAST_EVENT = POWER_MANAGER_BUTTON_EVENT, // Last valid event code. +}; + +} // namespace android + +#endif // _UI_POWER_MANAGER_H diff --git a/include/ui/Rect.h b/include/ui/Rect.h index a213c09..4e65a2d 100644 --- a/include/ui/Rect.h +++ b/include/ui/Rect.h @@ -20,31 +20,28 @@ #include <utils/TypeHelpers.h> #include <ui/Point.h> +#include <android/rect.h> + namespace android { -class Rect +class Rect : public ARect { public: - int left; - int top; - int right; - int bottom; - - typedef int value_type; + typedef int32_t value_type; // we don't provide copy-ctor and operator= on purpose // because we want the compiler generated versions inline Rect() { } - inline Rect(int w, int h) - : left(0), top(0), right(w), bottom(h) { + inline Rect(int32_t w, int32_t h) { + left = top = 0; right = w; bottom = h; } - inline Rect(int l, int t, int r, int b) - : left(l), top(t), right(r), bottom(b) { + inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) { + left = l; top = t; right = r; bottom = b; } - inline Rect(const Point& lt, const Point& rb) - : left(lt.x), top(lt.y), right(rb.x), bottom(rb.y) { + inline Rect(const Point& lt, const Point& rb) { + left = lt.x; top = lt.y; right = rb.x; bottom = rb.y; } void makeInvalid(); @@ -68,12 +65,12 @@ public: } // rectangle's width - inline int width() const { + inline int32_t width() const { return right-left; } // rectangle's height - inline int height() const { + inline int32_t height() const { return bottom-top; } @@ -136,12 +133,12 @@ public: const Rect operator + (const Point& rhs) const; const Rect operator - (const Point& rhs) const; - void translate(int dx, int dy) { // legacy, don't use. + void translate(int32_t dx, int32_t dy) { // legacy, don't use. offsetBy(dx, dy); } - Rect& offsetTo(int x, int y); - Rect& offsetBy(int x, int y); + Rect& offsetTo(int32_t x, int32_t y); + Rect& offsetBy(int32_t x, int32_t y); bool intersect(const Rect& with, Rect* result) const; }; diff --git a/include/ui/android_native_buffer.h b/include/ui/android_native_buffer.h index 9c92af8..402843e 100644 --- a/include/ui/android_native_buffer.h +++ b/include/ui/android_native_buffer.h @@ -33,6 +33,15 @@ typedef struct android_native_buffer_t common.version = sizeof(android_native_buffer_t); memset(common.reserved, 0, sizeof(common.reserved)); } + + // Implement the methods that sp<android_native_buffer_t> expects so that it + // can be used to automatically refcount android_native_buffer_t's. + void incStrong(const void* id) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* id) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } #endif struct android_native_base_t common; diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h index 773fd93..654d0f3 100644 --- a/include/ui/egl/android_natives.h +++ b/include/ui/egl/android_natives.h @@ -22,6 +22,8 @@ #include <hardware/gralloc.h> +#include <android/native_window.h> + #ifdef __cplusplus extern "C" { #endif @@ -41,6 +43,14 @@ extern "C" { struct android_native_buffer_t; +typedef struct android_native_rect_t +{ + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} android_native_rect_t; + // --------------------------------------------------------------------------- typedef struct android_native_base_t @@ -63,15 +73,19 @@ typedef struct android_native_base_t /* attributes queriable with query() */ enum { NATIVE_WINDOW_WIDTH = 0, - NATIVE_WINDOW_HEIGHT = 1, - NATIVE_WINDOW_FORMAT = 2, + NATIVE_WINDOW_HEIGHT, + NATIVE_WINDOW_FORMAT, }; /* valid operations for the (*perform)() hook */ enum { NATIVE_WINDOW_SET_USAGE = 0, - NATIVE_WINDOW_CONNECT = 1, - NATIVE_WINDOW_DISCONNECT = 2 + NATIVE_WINDOW_CONNECT, + NATIVE_WINDOW_DISCONNECT, + NATIVE_WINDOW_SET_CROP, + NATIVE_WINDOW_SET_BUFFER_COUNT, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, + NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, }; /* parameter for NATIVE_WINDOW_[DIS]CONNECT */ @@ -79,16 +93,39 @@ enum { NATIVE_WINDOW_API_EGL = 1 }; -typedef struct android_native_window_t +/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */ +enum { + /* flip source image horizontally */ + NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H , + /* flip source image vertically */ + NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V, + /* rotate source image 90 degrees clock-wise */ + NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90, + /* rotate source image 180 degrees */ + NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180, + /* rotate source image 270 degrees clock-wise */ + NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270, +}; + +struct ANativeWindow { #ifdef __cplusplus - android_native_window_t() + ANativeWindow() : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0) { common.magic = ANDROID_NATIVE_WINDOW_MAGIC; - common.version = sizeof(android_native_window_t); + common.version = sizeof(ANativeWindow); memset(common.reserved, 0, sizeof(common.reserved)); } + + // Implement the methods that sp<ANativeWindow> expects so that it + // can be used to automatically refcount ANativeWindow's. + void incStrong(const void* id) const { + common.incRef(const_cast<android_native_base_t*>(&common)); + } + void decStrong(const void* id) const { + common.decRef(const_cast<android_native_base_t*>(&common)); + } #endif struct android_native_base_t common; @@ -115,7 +152,7 @@ typedef struct android_native_window_t * * Returns 0 on success or -errno on error. */ - int (*setSwapInterval)(struct android_native_window_t* window, + int (*setSwapInterval)(struct ANativeWindow* window, int interval); /* @@ -125,7 +162,7 @@ typedef struct android_native_window_t * * Returns 0 on success or -errno on error. */ - int (*dequeueBuffer)(struct android_native_window_t* window, + int (*dequeueBuffer)(struct ANativeWindow* window, struct android_native_buffer_t** buffer); /* @@ -135,7 +172,7 @@ typedef struct android_native_window_t * * Returns 0 on success or -errno on error. */ - int (*lockBuffer)(struct android_native_window_t* window, + int (*lockBuffer)(struct ANativeWindow* window, struct android_native_buffer_t* buffer); /* * hook called by EGL when modifications to the render buffer are done. @@ -145,7 +182,7 @@ typedef struct android_native_window_t * * Returns 0 on success or -errno on error. */ - int (*queueBuffer)(struct android_native_window_t* window, + int (*queueBuffer)(struct ANativeWindow* window, struct android_native_buffer_t* buffer); /* @@ -153,13 +190,13 @@ typedef struct android_native_window_t * * Returns 0 on success or -errno on error. */ - int (*query)(struct android_native_window_t* window, + int (*query)(struct ANativeWindow* window, int what, int* value); /* * hook used to perform various operations on the surface. * (*perform)() is a generic mechanism to add functionality to - * android_native_window_t while keeping backward binary compatibility. + * ANativeWindow while keeping backward binary compatibility. * * This hook should not be called directly, instead use the helper functions * defined below. @@ -171,19 +208,36 @@ typedef struct android_native_window_t * NATIVE_WINDOW_SET_USAGE * NATIVE_WINDOW_CONNECT * NATIVE_WINDOW_DISCONNECT + * NATIVE_WINDOW_SET_CROP + * NATIVE_WINDOW_SET_BUFFER_COUNT + * NATIVE_WINDOW_SET_BUFFERS_GEOMETRY + * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM * */ - int (*perform)(struct android_native_window_t* window, + int (*perform)(struct ANativeWindow* window, int operation, ... ); - void* reserved_proc[3]; -} android_native_window_t; + /* + * hook used to cancel a buffer that has been dequeued. + * No synchronization is performed between dequeue() and cancel(), so + * either external synchronization is needed, or these functions must be + * called from the same thread. + */ + int (*cancelBuffer)(struct ANativeWindow* window, + struct android_native_buffer_t* buffer); + + void* reserved_proc[2]; +}; + +// Backwards compatibility... please switch to ANativeWindow. +typedef struct ANativeWindow android_native_window_t; /* - * native_window_set_usage() sets the intended usage flags for the next - * buffers acquired with (*lockBuffer)() and on. + * native_window_set_usage(..., usage) + * Sets the intended usage flags for the next buffers + * acquired with (*lockBuffer)() and on. * By default (if this function is never called), a usage of * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE * is assumed. @@ -192,35 +246,96 @@ typedef struct android_native_window_t */ static inline int native_window_set_usage( - android_native_window_t* window, int usage) + ANativeWindow* window, int usage) { return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage); } /* - * native_window_connect(..., NATIVE_WINDOW_API_EGL) must be called - * by EGL when the window is made current. + * native_window_connect(..., NATIVE_WINDOW_API_EGL) + * Must be called by EGL when the window is made current. * Returns -EINVAL if for some reason the window cannot be connected, which * can happen if it's connected to some other API. */ static inline int native_window_connect( - android_native_window_t* window, int api) + ANativeWindow* window, int api) { return window->perform(window, NATIVE_WINDOW_CONNECT, api); } /* - * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) must be called - * by EGL when the window is made not current. + * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) + * Must be called by EGL when the window is made not current. * An error is returned if for instance the window wasn't connected in the * first place. */ static inline int native_window_disconnect( - android_native_window_t* window, int api) + ANativeWindow* window, int api) { return window->perform(window, NATIVE_WINDOW_DISCONNECT, api); } +/* + * native_window_set_crop(..., crop) + * Sets which region of the next queued buffers needs to be considered. + * A buffer's crop region is scaled to match the surface's size. + * + * The specified crop region applies to all buffers queued after it is called. + * + * if 'crop' is NULL, subsequently queued buffers won't be cropped. + * + * An error is returned if for instance the crop region is invalid, + * out of the buffer's bound or if the window is invalid. + */ +static inline int native_window_set_crop( + ANativeWindow* window, + android_native_rect_t const * crop) +{ + return window->perform(window, NATIVE_WINDOW_SET_CROP, crop); +} + +/* + * native_window_set_buffer_count(..., count) + * Sets the number of buffers associated with this native window. + */ +static inline int native_window_set_buffer_count( + ANativeWindow* window, + size_t bufferCount) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount); +} + +/* + * native_window_set_buffers_geometry(..., int w, int h, int format) + * All buffers dequeued after this call will have the geometry specified. + * In particular, all buffers will have a fixed-size, independent form the + * native-window size. They will be appropriately scaled to the window-size + * upon composition. + * + * If all parameters are 0, the normal behavior is restored. That is, + * dequeued buffers following this call will be sized to the window's size. + * + */ +static inline int native_window_set_buffers_geometry( + ANativeWindow* window, + int w, int h, int format) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY, + w, h, format); +} + +/* + * native_window_set_buffers_transform(..., int transform) + * All buffers queued after this call will be displayed transformed according + * to the transform parameter specified. + */ +static inline int native_window_set_buffers_transform( + ANativeWindow* window, + int transform) +{ + return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, + transform); +} // --------------------------------------------------------------------------- @@ -263,6 +378,15 @@ namespace android { template <typename NATIVE_TYPE, typename TYPE, typename REF> class EGLNativeBase : public NATIVE_TYPE, public REF { +public: + // Disambiguate between the incStrong in REF and NATIVE_TYPE + void incStrong(const void* id) const { + REF::incStrong(id); + } + void decStrong(const void* id) const { + REF::decStrong(id); + } + protected: typedef EGLNativeBase<NATIVE_TYPE, TYPE, REF> BASE; EGLNativeBase() : NATIVE_TYPE(), REF() { |