Bug 737199, part 1: Import the Ice Cream Sandwich version of InputReader and friends to get off the treadmill of an internal interface. r=cjones,mwu (npotb)

This commit is contained in:
Michael Wu ext:(%20%28and%20others%29) 2012-03-25 02:11:05 -07:00
Родитель e23b52de32
Коммит d90564f1dc
32 изменённых файлов: 22523 добавлений и 2 удалений

Просмотреть файл

@ -38,7 +38,10 @@
DEPTH = ../.. DEPTH = ../..
topsrcdir = @top_srcdir@ topsrcdir = @top_srcdir@
srcdir = @srcdir@ srcdir = @srcdir@
VPATH = @srcdir@ VPATH = \
$(srcdir) \
$(srcdir)/libui \
$(NULL)
include $(DEPTH)/config/autoconf.mk include $(DEPTH)/config/autoconf.mk
@ -58,20 +61,35 @@ CPPSRCS = \
nsWindow.cpp \ nsWindow.cpp \
nsLookAndFeel.cpp \ nsLookAndFeel.cpp \
nsIdleServiceGonk.cpp \ nsIdleServiceGonk.cpp \
EventHub.cpp \
InputApplication.cpp \
InputDispatcher.cpp \
InputListener.cpp \
InputReader.cpp \
InputTransport.cpp \
InputWindow.cpp \
Keyboard.cpp \
KeyCharacterMap.cpp \
KeyLayoutMap.cpp \
PixelFormat.cpp \
VirtualKeyMap.cpp \
$(NULL) $(NULL)
SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk
DEFINES += -D_IMPL_NS_WIDGET DEFINES += -D_IMPL_NS_WIDGET -DHAVE_OFF64_T
LOCAL_INCLUDES += \ LOCAL_INCLUDES += \
-I$(topsrcdir)/widget/xpwidgets \ -I$(topsrcdir)/widget/xpwidgets \
-I$(topsrcdir)/widget/shared \ -I$(topsrcdir)/widget/shared \
-I$(topsrcdir)/dom/system/android \ -I$(topsrcdir)/dom/system/android \
-I$(topsrcdir)/content/events/src \ -I$(topsrcdir)/content/events/src \
-I$(topsrcdir)/gfx/skia/include/core \
-I$(topsrcdir)/gfx/skia/include/config \
-I$(srcdir) \ -I$(srcdir) \
$(NULL) $(NULL)
include $(topsrcdir)/ipc/chromium/chromium-config.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk

Просмотреть файл

@ -0,0 +1,52 @@
/*
* Copyright (C) 2007 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 ANDROID_UI_DISPLAY_INFO_H
#define ANDROID_UI_DISPLAY_INFO_H
#include <stdint.h>
#include <sys/types.h>
#include "PixelFormat.h"
namespace android {
struct DisplayInfo {
uint32_t w;
uint32_t h;
PixelFormatInfo pixelFormatInfo;
uint8_t orientation;
uint8_t reserved[3];
float fps;
float density;
float xdpi;
float ydpi;
};
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
enum {
DISPLAY_ORIENTATION_0 = 0,
DISPLAY_ORIENTATION_90 = 1,
DISPLAY_ORIENTATION_180 = 2,
DISPLAY_ORIENTATION_270 = 3
};
}; // namespace android
#endif // ANDROID_COMPOSER_DISPLAY_INFO_H

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,377 @@
/*
* Copyright (C) 2005 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 _RUNTIME_EVENT_HUB_H
#define _RUNTIME_EVENT_HUB_H
#include "Input.h"
#include "Keyboard.h"
#include "KeyLayoutMap.h"
#include "KeyCharacterMap.h"
#include "VirtualKeyMap.h"
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
#include <utils/PropertyMap.h>
#include <utils/Vector.h>
#include <utils/KeyedVector.h>
#include <linux/input.h>
#include <sys/epoll.h>
/* Convenience constants. */
#define BTN_FIRST 0x100 // first button scancode
#define BTN_LAST 0x15f // last button scancode
namespace android {
/*
* 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
int32_t resolution; // resolution in units per mm or radians per mm
inline void clear() {
valid = false;
minValue = 0;
maxValue = 0;
flat = 0;
fuzz = 0;
resolution = 0;
}
};
/*
* Input device classes.
*/
enum {
/* The input device is a keyboard or has buttons. */
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 or a touchpad (either single-touch or multi-touch). */
INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
/* The input device is a cursor device such as a trackball or mouse. */
INPUT_DEVICE_CLASS_CURSOR = 0x00000008,
/* The input device is a multi-touch touchscreen. */
INPUT_DEVICE_CLASS_TOUCH_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,
/* The input device is a joystick (implies gamepad, has joystick absolute axes). */
INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,
/* The input device is external (not built-in). */
INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
};
/*
* Gets the class that owns an axis, in cases where multiple classes might claim
* the same axis for different purposes.
*/
extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses);
/*
* Grand Central Station for events.
*
* 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 provides 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 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,
FIRST_SYNTHETIC_EVENT = DEVICE_ADDED,
};
virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0;
virtual String8 getDeviceName(int32_t deviceId) const = 0;
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const = 0;
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;
virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const = 0;
virtual status_t mapAxis(int32_t deviceId, int scancode,
AxisInfo* outAxisInfo) const = 0;
// Sets devices that are excluded from opening.
// This can be used to ignore input devices for sensors.
virtual void setExcludedDevices(const Vector<String8>& devices) = 0;
/*
* Wait for events to become available and returns them.
* 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).
*
* The timeout is advisory only. If the device is asleep, it will not wake just to
* service the timeout.
*
* Returns the number of events obtained, or 0 if the timeout expired.
*/
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 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;
virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
int32_t* outValue) 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 bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
virtual void getVirtualKeyDefinitions(int32_t deviceId,
Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
virtual String8 getKeyCharacterMapFile(int32_t deviceId) const = 0;
/* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
virtual void requestReopenDevices() = 0;
/* Wakes up getEvents() if it is blocked on a read. */
virtual void wake() = 0;
/* Dump EventHub state to a string. */
virtual void dump(String8& dump) = 0;
/* Called by the heatbeat to ensures that the reader has not deadlocked. */
virtual void monitor() = 0;
};
class EventHub : public EventHubInterface
{
public:
EventHub();
virtual uint32_t getDeviceClasses(int32_t deviceId) const;
virtual String8 getDeviceName(int32_t deviceId) const;
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const;
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const;
virtual bool hasInputProperty(int32_t deviceId, int property) const;
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const;
virtual status_t mapAxis(int32_t deviceId, int scancode,
AxisInfo* outAxisInfo) const;
virtual void setExcludedDevices(const Vector<String8>& devices);
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 status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const;
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const;
virtual bool hasLed(int32_t deviceId, int32_t led) const;
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
virtual void getVirtualKeyDefinitions(int32_t deviceId,
Vector<VirtualKeyDefinition>& outVirtualKeys) const;
virtual String8 getKeyCharacterMapFile(int32_t deviceId) const;
virtual void requestReopenDevices();
virtual void wake();
virtual void dump(String8& dump);
virtual void monitor();
protected:
virtual ~EventHub();
private:
struct Device {
Device* next;
int fd;
const int32_t id;
const String8 path;
const InputDeviceIdentifier identifier;
uint32_t classes;
uint8_t keyBitmask[(KEY_MAX + 1) / 8];
uint8_t absBitmask[(ABS_MAX + 1) / 8];
uint8_t relBitmask[(REL_MAX + 1) / 8];
uint8_t swBitmask[(SW_MAX + 1) / 8];
uint8_t ledBitmask[(LED_MAX + 1) / 8];
uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
String8 configurationFile;
PropertyMap* configuration;
VirtualKeyMap* virtualKeyMap;
KeyMap keyMap;
Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier);
~Device();
void close();
};
status_t openDeviceLocked(const char *devicePath);
status_t closeDeviceByPathLocked(const char *devicePath);
void closeDeviceLocked(Device* device);
void closeAllDevicesLocked();
status_t scanDirLocked(const char *dirname);
void scanDevicesLocked();
status_t readNotifyLocked();
Device* getDeviceLocked(int32_t deviceId) const;
Device* getDeviceByPathLocked(const char* devicePath) const;
bool hasKeycodeLocked(Device* device, int keycode) const;
void loadConfigurationLocked(Device* device);
status_t loadVirtualKeyMapLocked(Device* device);
status_t loadKeyMapLocked(Device* device);
bool isExternalDeviceLocked(Device* device);
// Protect all internal state.
mutable Mutex mLock;
// The actual id of the built-in keyboard, or -1 if none.
// EventHub remaps the built-in keyboard to id 0 externally as required by the API.
int32_t mBuiltInKeyboardId;
int32_t mNextDeviceId;
KeyedVector<int32_t, Device*> mDevices;
Device *mOpeningDevices;
Device *mClosingDevices;
bool mNeedToSendFinishedDeviceScan;
bool mNeedToReopenDevices;
bool mNeedToScanDevices;
Vector<String8> mExcludedDevices;
int mEpollFd;
int mINotifyFd;
int mWakeReadPipeFd;
int mWakeWritePipeFd;
// Ids used for epoll notifications not associated with devices.
static const uint32_t EPOLL_ID_INOTIFY = 0x80000001;
static const uint32_t EPOLL_ID_WAKE = 0x80000002;
// Epoll FD list size hint.
static const int EPOLL_SIZE_HINT = 8;
// Maximum number of signalled FDs to handle at a time.
static const int EPOLL_MAX_EVENTS = 16;
// The array of pending epoll events and the index of the next event to be handled.
struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS];
size_t mPendingEventCount;
size_t mPendingEventIndex;
bool mPendingINotify;
// Set to the number of CPUs.
int32_t mNumCpus;
};
}; // namespace android
#endif // _RUNTIME_EVENT_HUB_H

897
widget/gonk/libui/Input.h Normal file
Просмотреть файл

@ -0,0 +1,897 @@
/*
* 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>
#include <utils/BitSet.h>
#ifdef HAVE_ANDROID_OS
class SkMatrix;
#endif
/*
* 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,
/* Key event is inconsistent with previously sent key events. */
AKEY_EVENT_FLAG_TAINTED = 0x80000000,
};
enum {
/* Motion event is inconsistent with previously sent motion events. */
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
};
enum {
/*
* Indicates that an input device has switches.
* This input source flag is hidden from the API because switches are only used by the system
* and applications have no way to interact with them.
*/
AINPUT_SOURCE_SWITCH = 0x80000000,
};
/*
* SystemUiVisibility constants from View.
*/
enum {
ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
};
/*
* Maximum number of pointers supported per motion event.
* Smallest number of pointers is 1.
* (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
* will occasionally emit 11. There is not much harm making this constant bigger.)
*/
#define MAX_POINTERS 16
/*
* 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 {
#ifdef HAVE_ANDROID_OS
class Parcel;
#endif
/*
* 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.
* NOTE: If you edit these flags, also edit labels 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_FUNCTION = 0x00000200,
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,
// Indicates that the input event has passed through an input filter.
POLICY_FLAG_FILTERED = 0x04000000,
// Disables automatic key repeating behavior.
POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000,
/* 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 {
enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64
// Bitfield of axes that are present in this structure.
uint64_t bits;
// Values of axes that are stored in this structure packed in order by axis id
// for each axis that is present in the structure according to 'bits'.
float values[MAX_AXES];
inline void clear() {
bits = 0;
}
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
void scale(float scale);
inline float getX() const {
return getAxisValue(AMOTION_EVENT_AXIS_X);
}
inline float getY() const {
return getAxisValue(AMOTION_EVENT_AXIS_Y);
}
#ifdef HAVE_ANDROID_OS
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
#endif
bool operator==(const PointerCoords& other) const;
inline bool operator!=(const PointerCoords& other) const {
return !(*this == other);
}
void copyFrom(const PointerCoords& other);
private:
void tooManyAxes(int axis);
};
/*
* Pointer property data.
*/
struct PointerProperties {
// The id of the pointer.
int32_t id;
// The pointer tool type.
int32_t toolType;
inline void clear() {
id = -1;
toolType = 0;
}
bool operator==(const PointerProperties& other) const;
inline bool operator!=(const PointerProperties& other) const {
return !(*this == other);
}
void copyFrom(const PointerProperties& other);
};
/*
* 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; }
inline void setSource(int32_t source) { mSource = source; }
protected:
void initialize(int32_t deviceId, int32_t source);
void initialize(const InputEvent& from);
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);
protected:
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 getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
inline int32_t getActionIndex() const {
return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
>> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
inline void setAction(int32_t action) { mAction = action; }
inline int32_t getFlags() const { return mFlags; }
inline void setFlags(int32_t flags) { mFlags = flags; }
inline int32_t getEdgeFlags() const { return mEdgeFlags; }
inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; }
inline int32_t getMetaState() const { return mMetaState; }
inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
inline int32_t getButtonState() const { return mButtonState; }
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 void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
inline size_t getPointerCount() const { return mPointerProperties.size(); }
inline const PointerProperties* getPointerProperties(size_t pointerIndex) const {
return &mPointerProperties[pointerIndex];
}
inline int32_t getPointerId(size_t pointerIndex) const {
return mPointerProperties[pointerIndex].id;
}
inline int32_t getToolType(size_t pointerIndex) const {
return mPointerProperties[pointerIndex].toolType;
}
inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
inline float getRawX(size_t pointerIndex) const {
return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
}
inline float getRawY(size_t pointerIndex) const {
return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
}
float getAxisValue(int32_t axis, size_t pointerIndex) const;
inline float getX(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
}
inline float getY(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
}
inline float getPressure(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex);
}
inline float getSize(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex);
}
inline float getTouchMajor(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex);
}
inline float getTouchMinor(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex);
}
inline float getToolMajor(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex);
}
inline float getToolMinor(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex);
}
inline float getOrientation(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex);
}
inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const {
return mSampleEventTimes[historicalIndex];
}
const PointerCoords* getHistoricalRawPointerCoords(
size_t pointerIndex, size_t historicalIndex) const;
float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
size_t historicalIndex) const;
inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalRawAxisValue(
AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
}
inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalRawAxisValue(
AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
}
float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const;
inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
}
inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
}
inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex);
}
inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex);
}
inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex);
}
inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex);
}
inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex);
}
inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex);
}
inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
return getHistoricalAxisValue(
AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
}
ssize_t findPointerIndex(int32_t pointerId) const;
void initialize(
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
float xOffset,
float yOffset,
float xPrecision,
float yPrecision,
nsecs_t downTime,
nsecs_t eventTime,
size_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
void copyFrom(const MotionEvent* other, bool keepHistory);
void addSample(
nsecs_t eventTime,
const PointerCoords* pointerCoords);
void offsetLocation(float xOffset, float yOffset);
void scale(float scaleFactor);
#ifdef HAVE_ANDROID_OS
void transform(const SkMatrix* matrix);
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
#endif
static bool isTouchEvent(int32_t source, int32_t action);
inline bool isTouchEvent() const {
return isTouchEvent(mSource, mAction);
}
// Low-level accessors.
inline const PointerProperties* getPointerProperties() const {
return mPointerProperties.array();
}
inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
inline const PointerCoords* getSamplePointerCoords() const {
return mSamplePointerCoords.array();
}
protected:
int32_t mAction;
int32_t mFlags;
int32_t mEdgeFlags;
int32_t mMetaState;
int32_t mButtonState;
float mXOffset;
float mYOffset;
float mXPrecision;
float mYPrecision;
nsecs_t mDownTime;
Vector<PointerProperties> mPointerProperties;
Vector<nsecs_t> mSampleEventTimes;
Vector<PointerCoords> mSamplePointerCoords;
};
/*
* 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;
};
/*
* Calculates the velocity of pointer movements over time.
*/
class VelocityTracker {
public:
// Default polynomial degree. (used by getVelocity)
static const uint32_t DEFAULT_DEGREE = 2;
// Default sample horizon. (used by getVelocity)
// We don't use too much history by default since we want to react to quick
// changes in direction.
static const nsecs_t DEFAULT_HORIZON = 100 * 1000000; // 100 ms
struct Position {
float x, y;
};
struct Estimator {
static const size_t MAX_DEGREE = 2;
// Polynomial coefficients describing motion in X and Y.
float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
// Polynomial degree (number of coefficients), or zero if no information is
// available.
uint32_t degree;
// Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit).
float confidence;
inline void clear() {
degree = 0;
confidence = 0;
for (size_t i = 0; i <= MAX_DEGREE; i++) {
xCoeff[i] = 0;
yCoeff[i] = 0;
}
}
};
VelocityTracker();
// Resets the velocity tracker state.
void clear();
// Resets the velocity tracker state for specific pointers.
// Call this method when some pointers have changed and may be reusing
// an id that was assigned to a different pointer earlier.
void clearPointers(BitSet32 idBits);
// Adds movement information for a set of pointers.
// The idBits bitfield specifies the pointer ids of the pointers whose positions
// are included in the movement.
// The positions array contains position information for each pointer in order by
// increasing id. Its size should be equal to the number of one bits in idBits.
void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
// Adds movement information for all pointers in a MotionEvent, including historical samples.
void addMovement(const MotionEvent* event);
// Gets the velocity of the specified pointer id in position units per second.
// Returns false and sets the velocity components to zero if there is
// insufficient movement information for the pointer.
bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
// Gets a quadratic estimator for the movements of the specified pointer id.
// Returns false and clears the estimator if there is no information available
// about the pointer.
bool getEstimator(uint32_t id, uint32_t degree, nsecs_t horizon,
Estimator* outEstimator) const;
// Gets the active pointer id, or -1 if none.
inline int32_t getActivePointerId() const { return mActivePointerId; }
// Gets a bitset containing all pointer ids from the most recent movement.
inline BitSet32 getCurrentPointerIdBits() const { return mMovements[mIndex].idBits; }
private:
// Number of samples to keep.
static const uint32_t HISTORY_SIZE = 20;
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
Position positions[MAX_POINTERS];
inline const Position& getPosition(uint32_t id) const {
return positions[idBits.getIndexOfBit(id)];
}
};
uint32_t mIndex;
Movement mMovements[HISTORY_SIZE];
int32_t mActivePointerId;
};
/*
* Specifies parameters that govern pointer or wheel acceleration.
*/
struct VelocityControlParameters {
// A scale factor that is multiplied with the raw velocity deltas
// prior to applying any other velocity control factors. The scale
// factor should be used to adapt the input device resolution
// (eg. counts per inch) to the output device resolution (eg. pixels per inch).
//
// Must be a positive value.
// Default is 1.0 (no scaling).
float scale;
// The scaled speed at which acceleration begins to be applied.
// This value establishes the upper bound of a low speed regime for
// small precise motions that are performed without any acceleration.
//
// Must be a non-negative value.
// Default is 0.0 (no low threshold).
float lowThreshold;
// The scaled speed at which maximum acceleration is applied.
// The difference between highThreshold and lowThreshold controls
// the range of speeds over which the acceleration factor is interpolated.
// The wider the range, the smoother the acceleration.
//
// Must be a non-negative value greater than or equal to lowThreshold.
// Default is 0.0 (no high threshold).
float highThreshold;
// The acceleration factor.
// When the speed is above the low speed threshold, the velocity will scaled
// by an interpolated value between 1.0 and this amount.
//
// Must be a positive greater than or equal to 1.0.
// Default is 1.0 (no acceleration).
float acceleration;
VelocityControlParameters() :
scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
}
VelocityControlParameters(float scale, float lowThreshold,
float highThreshold, float acceleration) :
scale(scale), lowThreshold(lowThreshold),
highThreshold(highThreshold), acceleration(acceleration) {
}
};
/*
* Implements mouse pointer and wheel speed control and acceleration.
*/
class VelocityControl {
public:
VelocityControl();
/* Sets the various parameters. */
void setParameters(const VelocityControlParameters& parameters);
/* Resets the current movement counters to zero.
* This has the effect of nullifying any acceleration. */
void reset();
/* Translates a raw movement delta into an appropriately
* scaled / accelerated delta based on the current velocity. */
void move(nsecs_t eventTime, float* deltaX, float* deltaY);
private:
// If no movements are received within this amount of time,
// we assume the movement has stopped and reset the movement counters.
static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
VelocityControlParameters mParameters;
nsecs_t mLastMovementTime;
VelocityTracker::Position mRawPosition;
VelocityTracker mVelocityTracker;
};
/*
* Describes the characteristics and capabilities of an input device.
*/
class InputDeviceInfo {
public:
InputDeviceInfo();
InputDeviceInfo(const InputDeviceInfo& other);
~InputDeviceInfo();
struct MotionRange {
int32_t axis;
uint32_t source;
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 axis, uint32_t source) const;
void addSource(uint32_t source);
void addMotionRange(int32_t axis, uint32_t source,
float min, float max, float flat, float fuzz);
void addMotionRange(const MotionRange& range);
inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
inline int32_t getKeyboardType() const { return mKeyboardType; }
inline void setKeyCharacterMapFile(const String8& value) { mKeyCharacterMapFile = value; }
inline const String8& getKeyCharacterMapFile() const { return mKeyCharacterMapFile; }
inline const Vector<MotionRange>& getMotionRanges() const {
return mMotionRanges;
}
private:
int32_t mId;
String8 mName;
uint32_t mSources;
int32_t mKeyboardType;
String8 mKeyCharacterMapFile;
Vector<MotionRange> mMotionRanges;
};
/*
* Identifies a device.
*/
struct InputDeviceIdentifier {
inline InputDeviceIdentifier() :
bus(0), vendor(0), product(0), version(0) {
}
String8 name;
String8 location;
String8 uniqueId;
uint16_t bus;
uint16_t vendor;
uint16_t product;
uint16_t version;
};
/* Types of input device configuration files. */
enum InputDeviceConfigurationFileType {
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
};
/*
* Gets the path of an input device configuration file, if one is available.
* Considers both system provided and user installed configuration files.
*
* The device identifier is used to construct several default configuration file
* names to try based on the device name, vendor, product, and version.
*
* Returns an empty string if not found.
*/
extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type);
/*
* Gets the path of an input device configuration file, if one is available.
* Considers both system provided and user installed configuration files.
*
* The name is case-sensitive and is used to construct the filename to resolve.
* All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores.
*
* Returns an empty string if not found.
*/
extern String8 getInputDeviceConfigurationFilePathByName(
const String8& name, InputDeviceConfigurationFileType type);
} // namespace android
#endif // _UI_INPUT_H

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Copyright (C) 2011 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.
*/
#define LOG_TAG "InputApplication"
#include "InputApplication.h"
#include <cutils/log.h>
namespace android {
// --- InputApplicationHandle ---
InputApplicationHandle::InputApplicationHandle() :
mInfo(NULL) {
}
InputApplicationHandle::~InputApplicationHandle() {
delete mInfo;
}
void InputApplicationHandle::releaseInfo() {
if (mInfo) {
delete mInfo;
mInfo = NULL;
}
}
} // namespace android

Просмотреть файл

@ -0,0 +1,83 @@
/*
* Copyright (C) 2011 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_APPLICATION_H
#define _UI_INPUT_APPLICATION_H
#include "Input.h"
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/String8.h>
namespace android {
/*
* Describes the properties of an application that can receive input.
*/
struct InputApplicationInfo {
String8 name;
nsecs_t dispatchingTimeout;
};
/*
* Handle for an application that can receive input.
*
* Used by the native input dispatcher as a handle for the window manager objects
* that describe an application.
*/
class InputApplicationHandle : public RefBase {
public:
inline const InputApplicationInfo* getInfo() const {
return mInfo;
}
inline String8 getName() const {
return mInfo ? mInfo->name : String8("<invalid>");
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
return mInfo ? mInfo->dispatchingTimeout : defaultValue;
}
/**
* Requests that the state of this object be updated to reflect
* the most current available information about the application.
*
* This method should only be called from within the input dispatcher's
* critical section.
*
* Returns true on success, or false if the handle is no longer valid.
*/
virtual bool updateInfo() = 0;
/**
* Releases the storage used by the associated information when it is
* no longer needed.
*/
void releaseInfo();
protected:
InputApplicationHandle();
virtual ~InputApplicationHandle();
InputApplicationInfo* mInfo;
};
} // namespace android
#endif // _UI_INPUT_APPLICATION_H

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,181 @@
/*
* Copyright (C) 2011 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.
*/
#define LOG_TAG "InputListener"
//#define LOG_NDEBUG 0
#include "InputListener.h"
#include <cutils/log.h>
namespace android {
// --- NotifyConfigurationChangedArgs ---
NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) :
eventTime(eventTime) {
}
NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(
const NotifyConfigurationChangedArgs& other) :
eventTime(other.eventTime) {
}
void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyConfigurationChanged(this);
}
// --- NotifyKeyArgs ---
NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
metaState(metaState), downTime(downTime) {
}
NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
policyFlags(other.policyFlags),
action(other.action), flags(other.flags),
keyCode(other.keyCode), scanCode(other.scanCode),
metaState(other.metaState), downTime(other.downTime) {
}
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
// --- NotifyMotionArgs ---
NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
int32_t edgeFlags, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
action(action), flags(flags), metaState(metaState), buttonState(buttonState),
edgeFlags(edgeFlags), pointerCount(pointerCount),
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
this->pointerCoords[i].copyFrom(pointerCoords[i]);
}
}
NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
policyFlags(other.policyFlags),
action(other.action), flags(other.flags),
metaState(other.metaState), buttonState(other.buttonState),
edgeFlags(other.edgeFlags), pointerCount(other.pointerCount),
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
pointerCoords[i].copyFrom(other.pointerCoords[i]);
}
}
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
// --- NotifySwitchArgs ---
NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
int32_t switchCode, int32_t switchValue) :
eventTime(eventTime), policyFlags(policyFlags),
switchCode(switchCode), switchValue(switchValue) {
}
NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) :
eventTime(other.eventTime), policyFlags(other.policyFlags),
switchCode(other.switchCode), switchValue(other.switchValue) {
}
void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifySwitch(this);
}
// --- NotifyDeviceResetArgs ---
NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) :
eventTime(eventTime), deviceId(deviceId) {
}
NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) :
eventTime(other.eventTime), deviceId(other.deviceId) {
}
void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyDeviceReset(this);
}
// --- QueuedInputListener ---
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
QueuedInputListener::~QueuedInputListener() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
delete mArgsQueue[i];
}
}
void QueuedInputListener::notifyConfigurationChanged(
const NotifyConfigurationChangedArgs* args) {
mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));
}
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
mArgsQueue.push(new NotifySwitchArgs(*args));
}
void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
mArgsQueue.push(new NotifyDeviceResetArgs(*args));
}
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
} // namespace android

Просмотреть файл

@ -0,0 +1,195 @@
/*
* Copyright (C) 2011 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_LISTENER_H
#define _UI_INPUT_LISTENER_H
#include "Input.h"
#include <utils/RefBase.h>
#include <utils/Vector.h>
namespace android {
class InputListenerInterface;
/* Superclass of all input event argument objects */
struct NotifyArgs {
virtual ~NotifyArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const = 0;
};
/* Describes a configuration change event. */
struct NotifyConfigurationChangedArgs : public NotifyArgs {
nsecs_t eventTime;
inline NotifyConfigurationChangedArgs() { }
NotifyConfigurationChangedArgs(nsecs_t eventTime);
NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
virtual ~NotifyConfigurationChangedArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
/* Describes a key event. */
struct NotifyKeyArgs : public NotifyArgs {
nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t keyCode;
int32_t scanCode;
int32_t metaState;
nsecs_t downTime;
inline NotifyKeyArgs() { }
NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, nsecs_t downTime);
NotifyKeyArgs(const NotifyKeyArgs& other);
virtual ~NotifyKeyArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
/* Describes a motion event. */
struct NotifyMotionArgs : public NotifyArgs {
nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t metaState;
int32_t buttonState;
int32_t edgeFlags;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
float xPrecision;
float yPrecision;
nsecs_t downTime;
inline NotifyMotionArgs() { }
NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
int32_t edgeFlags, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
NotifyMotionArgs(const NotifyMotionArgs& other);
virtual ~NotifyMotionArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
/* Describes a switch event. */
struct NotifySwitchArgs : public NotifyArgs {
nsecs_t eventTime;
uint32_t policyFlags;
int32_t switchCode;
int32_t switchValue;
inline NotifySwitchArgs() { }
NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags,
int32_t switchCode, int32_t switchValue);
NotifySwitchArgs(const NotifySwitchArgs& other);
virtual ~NotifySwitchArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
/* Describes a device reset event, such as when a device is added,
* reconfigured, or removed. */
struct NotifyDeviceResetArgs : public NotifyArgs {
nsecs_t eventTime;
int32_t deviceId;
inline NotifyDeviceResetArgs() { }
NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId);
NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other);
virtual ~NotifyDeviceResetArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
/*
* The interface used by the InputReader to notify the InputListener about input events.
*/
class InputListenerInterface : public virtual RefBase {
protected:
InputListenerInterface() { }
virtual ~InputListenerInterface() { }
public:
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
virtual void notifyKey(const NotifyKeyArgs* args) = 0;
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
};
/*
* An implementation of the listener interface that queues up and defers dispatch
* of decoded events until flushed.
*/
class QueuedInputListener : public InputListenerInterface {
protected:
virtual ~QueuedInputListener();
public:
QueuedInputListener(const sp<InputListenerInterface>& innerListener);
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
virtual void notifyKey(const NotifyKeyArgs* args);
virtual void notifyMotion(const NotifyMotionArgs* args);
virtual void notifySwitch(const NotifySwitchArgs* args);
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
void flush();
private:
sp<InputListenerInterface> mInnerListener;
Vector<NotifyArgs*> mArgsQueue;
};
} // namespace android
#endif // _UI_INPUT_LISTENER_H

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,727 @@
//
// Copyright 2010 The Android Open Source Project
//
// Provides a shared memory transport for input events.
//
#define LOG_TAG "InputTransport"
//#define LOG_NDEBUG 0
// Log debug messages about channel signalling (send signal, receive signal)
#define DEBUG_CHANNEL_SIGNALS 0
// Log debug messages whenever InputChannel objects are created/destroyed
#define DEBUG_CHANNEL_LIFECYCLE 0
// Log debug messages about transport actions (initialize, reset, publish, ...)
#define DEBUG_TRANSPORT_ACTIONS 0
#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "InputTransport.h"
#include <unistd.h>
namespace android {
#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
#define MIN_HISTORY_DEPTH 20
// Must be at least sizeof(InputMessage) + sufficient space for pointer data
static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
sizeof(InputMessage) + MIN_HISTORY_DEPTH
* (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
4096);
// Signal sent by the producer to the consumer to inform it that a new message is
// available to be consumed in the shared memory buffer.
static const char INPUT_SIGNAL_DISPATCH = 'D';
// Signal sent by the consumer to the producer to inform it that it has finished
// consuming the most recent message and it handled it.
static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
// Signal sent by the consumer to the producer to inform it that it has finished
// consuming the most recent message but it did not handle it.
static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
// --- InputChannel ---
InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
int32_t sendPipeFd) :
mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
#if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
#endif
int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
"non-blocking. errno=%d", mName.string(), errno);
result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
"non-blocking. errno=%d", mName.string(), errno);
}
InputChannel::~InputChannel() {
#if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
#endif
::close(mAshmemFd);
::close(mReceivePipeFd);
::close(mSendPipeFd);
}
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
status_t result;
String8 ashmemName("InputChannel ");
ashmemName.append(name);
int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
if (serverAshmemFd < 0) {
result = -errno;
ALOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
name.string(), errno);
} else {
result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
if (result < 0) {
ALOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
name.string(), result, serverAshmemFd);
} else {
// Dup the file descriptor because the server and client input channel objects that
// are returned may have different lifetimes but they share the same shared memory region.
int clientAshmemFd;
clientAshmemFd = dup(serverAshmemFd);
if (clientAshmemFd < 0) {
result = -errno;
ALOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
name.string(), errno);
} else {
int forward[2];
if (pipe(forward)) {
result = -errno;
ALOGE("channel '%s' ~ Could not create forward pipe. errno=%d",
name.string(), errno);
} else {
int reverse[2];
if (pipe(reverse)) {
result = -errno;
ALOGE("channel '%s' ~ Could not create reverse pipe. errno=%d",
name.string(), errno);
} else {
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName,
serverAshmemFd, reverse[0], forward[1]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName,
clientAshmemFd, forward[0], reverse[1]);
return OK;
}
::close(forward[0]);
::close(forward[1]);
}
::close(clientAshmemFd);
}
}
::close(serverAshmemFd);
}
outServerChannel.clear();
outClientChannel.clear();
return result;
}
status_t InputChannel::sendSignal(char signal) {
ssize_t nWrite;
do {
nWrite = ::write(mSendPipeFd, & signal, 1);
} while (nWrite == -1 && errno == EINTR);
if (nWrite == 1) {
#if DEBUG_CHANNEL_SIGNALS
ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
#endif
return OK;
}
#if DEBUG_CHANNEL_SIGNALS
ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
#endif
return -errno;
}
status_t InputChannel::receiveSignal(char* outSignal) {
ssize_t nRead;
do {
nRead = ::read(mReceivePipeFd, outSignal, 1);
} while (nRead == -1 && errno == EINTR);
if (nRead == 1) {
#if DEBUG_CHANNEL_SIGNALS
ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
#endif
return OK;
}
if (nRead == 0) { // check for EOF
#if DEBUG_CHANNEL_SIGNALS
ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
#endif
return DEAD_OBJECT;
}
if (errno == EAGAIN) {
#if DEBUG_CHANNEL_SIGNALS
ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
#endif
return WOULD_BLOCK;
}
#if DEBUG_CHANNEL_SIGNALS
ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
#endif
return -errno;
}
// --- InputPublisher ---
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
mChannel(channel), mSharedMessage(NULL),
mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
mMotionEventSampleDataTail(NULL) {
}
InputPublisher::~InputPublisher() {
reset();
if (mSharedMessage) {
munmap(mSharedMessage, mAshmemSize);
}
}
status_t InputPublisher::initialize() {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ initialize",
mChannel->getName().string());
#endif
int ashmemFd = mChannel->getAshmemFd();
int result = ashmem_get_size_region(ashmemFd);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
mChannel->getName().string(), result, ashmemFd);
return UNKNOWN_ERROR;
}
mAshmemSize = (size_t) result;
mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
if (! mSharedMessage) {
ALOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
mChannel->getName().string(), ashmemFd);
return NO_MEMORY;
}
mPinned = true;
mSharedMessage->consumed = false;
return reset();
}
status_t InputPublisher::reset() {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ reset",
mChannel->getName().string());
#endif
if (mPinned) {
// Destroy the semaphore since we are about to unpin the memory region that contains it.
int result;
if (mSemaphoreInitialized) {
if (mSharedMessage->consumed) {
result = sem_post(& mSharedMessage->semaphore);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
mChannel->getName().string(), errno);
return UNKNOWN_ERROR;
}
}
result = sem_destroy(& mSharedMessage->semaphore);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
mChannel->getName().string(), errno);
return UNKNOWN_ERROR;
}
mSemaphoreInitialized = false;
}
// Unpin the region since we no longer care about its contents.
int ashmemFd = mChannel->getAshmemFd();
result = ashmem_unpin_region(ashmemFd, 0, 0);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
mChannel->getName().string(), result, ashmemFd);
return UNKNOWN_ERROR;
}
mPinned = false;
}
mMotionEventSampleDataTail = NULL;
mWasDispatched = false;
return OK;
}
status_t InputPublisher::publishInputEvent(
int32_t type,
int32_t deviceId,
int32_t source) {
if (mPinned) {
ALOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
"not yet been reset.", mChannel->getName().string());
return INVALID_OPERATION;
}
// Pin the region.
// We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
// contents of the buffer so it does not matter whether it was purged in the meantime.
int ashmemFd = mChannel->getAshmemFd();
int result = ashmem_pin_region(ashmemFd, 0, 0);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
mChannel->getName().string(), result, ashmemFd);
return UNKNOWN_ERROR;
}
mPinned = true;
result = sem_init(& mSharedMessage->semaphore, 1, 1);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d in sem_init.",
mChannel->getName().string(), errno);
return UNKNOWN_ERROR;
}
mSemaphoreInitialized = true;
mSharedMessage->consumed = false;
mSharedMessage->type = type;
mSharedMessage->deviceId = deviceId;
mSharedMessage->source = source;
return OK;
}
status_t InputPublisher::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) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%lld, eventTime=%lld",
mChannel->getName().string(),
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
downTime, eventTime);
#endif
status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
if (result < 0) {
return result;
}
mSharedMessage->key.action = action;
mSharedMessage->key.flags = flags;
mSharedMessage->key.keyCode = keyCode;
mSharedMessage->key.scanCode = scanCode;
mSharedMessage->key.metaState = metaState;
mSharedMessage->key.repeatCount = repeatCount;
mSharedMessage->key.downTime = downTime;
mSharedMessage->key.eventTime = eventTime;
return OK;
}
status_t InputPublisher::publishMotionEvent(
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
float xOffset,
float yOffset,
float xPrecision,
float yPrecision,
nsecs_t downTime,
nsecs_t eventTime,
size_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
"xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
"pointerCount=%d",
mChannel->getName().string(),
deviceId, source, action, flags, edgeFlags, metaState, buttonState,
xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
if (pointerCount > MAX_POINTERS || pointerCount < 1) {
ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
mChannel->getName().string(), pointerCount);
return BAD_VALUE;
}
status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
if (result < 0) {
return result;
}
mSharedMessage->motion.action = action;
mSharedMessage->motion.flags = flags;
mSharedMessage->motion.edgeFlags = edgeFlags;
mSharedMessage->motion.metaState = metaState;
mSharedMessage->motion.buttonState = buttonState;
mSharedMessage->motion.xOffset = xOffset;
mSharedMessage->motion.yOffset = yOffset;
mSharedMessage->motion.xPrecision = xPrecision;
mSharedMessage->motion.yPrecision = yPrecision;
mSharedMessage->motion.downTime = downTime;
mSharedMessage->motion.pointerCount = pointerCount;
mSharedMessage->motion.sampleCount = 1;
mSharedMessage->motion.sampleData[0].eventTime = eventTime;
for (size_t i = 0; i < pointerCount; i++) {
mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
}
// Cache essential information about the motion event to ensure that a malicious consumer
// cannot confuse the publisher by modifying the contents of the shared memory buffer while
// it is being updated.
if (action == AMOTION_EVENT_ACTION_MOVE
|| action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
mMotionEventPointerCount = pointerCount;
mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
} else {
mMotionEventSampleDataTail = NULL;
}
return OK;
}
status_t InputPublisher::appendMotionSample(
nsecs_t eventTime,
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
mChannel->getName().string(), eventTime);
#endif
if (! mPinned || ! mMotionEventSampleDataTail) {
ALOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
"AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
mChannel->getName().string());
return INVALID_OPERATION;
}
InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
mMotionEventSampleDataTail, mMotionEventSampleDataStride);
size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
reinterpret_cast<char*>(mSharedMessage);
if (newBytesUsed > mAshmemSize) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
"buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
mChannel->getName().string(),
mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
#endif
return NO_MEMORY;
}
int result;
if (mWasDispatched) {
result = sem_trywait(& mSharedMessage->semaphore);
if (result < 0) {
if (errno == EAGAIN) {
// Only possible source of contention is the consumer having consumed (or being in the
// process of consuming) the message and left the semaphore count at 0.
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
"already been consumed.", mChannel->getName().string());
#endif
return FAILED_TRANSACTION;
} else {
ALOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
mChannel->getName().string(), errno);
return UNKNOWN_ERROR;
}
}
}
mMotionEventSampleDataTail->eventTime = eventTime;
for (size_t i = 0; i < mMotionEventPointerCount; i++) {
mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
}
mMotionEventSampleDataTail = newTail;
mSharedMessage->motion.sampleCount += 1;
if (mWasDispatched) {
result = sem_post(& mSharedMessage->semaphore);
if (result < 0) {
ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
mChannel->getName().string(), errno);
return UNKNOWN_ERROR;
}
}
return OK;
}
status_t InputPublisher::sendDispatchSignal() {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ sendDispatchSignal",
mChannel->getName().string());
#endif
mWasDispatched = true;
return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
}
status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
mChannel->getName().string());
#endif
char signal;
status_t result = mChannel->receiveSignal(& signal);
if (result) {
*outHandled = false;
return result;
}
if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
*outHandled = true;
} else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
*outHandled = false;
} else {
ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
mChannel->getName().string(), signal);
return UNKNOWN_ERROR;
}
return OK;
}
// --- InputConsumer ---
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
mChannel(channel), mSharedMessage(NULL) {
}
InputConsumer::~InputConsumer() {
if (mSharedMessage) {
munmap(mSharedMessage, mAshmemSize);
}
}
status_t InputConsumer::initialize() {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ initialize",
mChannel->getName().string());
#endif
int ashmemFd = mChannel->getAshmemFd();
int result = ashmem_get_size_region(ashmemFd);
if (result < 0) {
ALOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
mChannel->getName().string(), result, ashmemFd);
return UNKNOWN_ERROR;
}
mAshmemSize = (size_t) result;
mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
if (! mSharedMessage) {
ALOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
mChannel->getName().string(), ashmemFd);
return NO_MEMORY;
}
return OK;
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consume",
mChannel->getName().string());
#endif
*outEvent = NULL;
int ashmemFd = mChannel->getAshmemFd();
int result = ashmem_pin_region(ashmemFd, 0, 0);
if (result != ASHMEM_NOT_PURGED) {
if (result == ASHMEM_WAS_PURGED) {
ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
"which probably indicates that the publisher and consumer are out of sync.",
mChannel->getName().string(), result, ashmemFd);
return INVALID_OPERATION;
}
ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
mChannel->getName().string(), result, ashmemFd);
return UNKNOWN_ERROR;
}
if (mSharedMessage->consumed) {
ALOGE("channel '%s' consumer ~ The current message has already been consumed.",
mChannel->getName().string());
return INVALID_OPERATION;
}
// Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
// to the publisher that the message has been consumed (or is in the process of being
// consumed). Eventually the publisher will reinitialize the semaphore for the next message.
result = sem_wait(& mSharedMessage->semaphore);
if (result < 0) {
ALOGE("channel '%s' consumer ~ Error %d in sem_wait.",
mChannel->getName().string(), errno);
return UNKNOWN_ERROR;
}
mSharedMessage->consumed = true;
switch (mSharedMessage->type) {
case AINPUT_EVENT_TYPE_KEY: {
KeyEvent* keyEvent = factory->createKeyEvent();
if (! keyEvent) return NO_MEMORY;
populateKeyEvent(keyEvent);
*outEvent = keyEvent;
break;
}
case AINPUT_EVENT_TYPE_MOTION: {
MotionEvent* motionEvent = factory->createMotionEvent();
if (! motionEvent) return NO_MEMORY;
populateMotionEvent(motionEvent);
*outEvent = motionEvent;
break;
}
default:
ALOGE("channel '%s' consumer ~ Received message of unknown type %d",
mChannel->getName().string(), mSharedMessage->type);
return UNKNOWN_ERROR;
}
return OK;
}
status_t InputConsumer::sendFinishedSignal(bool handled) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
mChannel->getName().string(), handled);
#endif
return mChannel->sendSignal(handled
? INPUT_SIGNAL_FINISHED_HANDLED
: INPUT_SIGNAL_FINISHED_UNHANDLED);
}
status_t InputConsumer::receiveDispatchSignal() {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ receiveDispatchSignal",
mChannel->getName().string());
#endif
char signal;
status_t result = mChannel->receiveSignal(& signal);
if (result) {
return result;
}
if (signal != INPUT_SIGNAL_DISPATCH) {
ALOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
mChannel->getName().string(), signal);
return UNKNOWN_ERROR;
}
return OK;
}
void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
keyEvent->initialize(
mSharedMessage->deviceId,
mSharedMessage->source,
mSharedMessage->key.action,
mSharedMessage->key.flags,
mSharedMessage->key.keyCode,
mSharedMessage->key.scanCode,
mSharedMessage->key.metaState,
mSharedMessage->key.repeatCount,
mSharedMessage->key.downTime,
mSharedMessage->key.eventTime);
}
void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
motionEvent->initialize(
mSharedMessage->deviceId,
mSharedMessage->source,
mSharedMessage->motion.action,
mSharedMessage->motion.flags,
mSharedMessage->motion.edgeFlags,
mSharedMessage->motion.metaState,
mSharedMessage->motion.buttonState,
mSharedMessage->motion.xOffset,
mSharedMessage->motion.yOffset,
mSharedMessage->motion.xPrecision,
mSharedMessage->motion.yPrecision,
mSharedMessage->motion.downTime,
mSharedMessage->motion.sampleData[0].eventTime,
mSharedMessage->motion.pointerCount,
mSharedMessage->motion.pointerProperties,
mSharedMessage->motion.sampleData[0].coords);
size_t sampleCount = mSharedMessage->motion.sampleCount;
if (sampleCount > 1) {
InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
size_t sampleDataStride = InputMessage::sampleDataStride(
mSharedMessage->motion.pointerCount);
while (--sampleCount > 0) {
sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
motionEvent->addSample(sampleData->eventTime, sampleData->coords);
}
}
}
} // namespace android

Просмотреть файл

@ -0,0 +1,338 @@
/*
* 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 "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 buttonState;
int32_t edgeFlags;
nsecs_t downTime;
float xOffset;
float yOffset;
float xPrecision;
float yPrecision;
size_t pointerCount;
PointerProperties pointerProperties[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,
int32_t buttonState,
float xOffset,
float yOffset,
float xPrecision,
float yPrecision,
nsecs_t downTime,
nsecs_t eventTime,
size_t pointerCount,
const PointerProperties* pointerProperties,
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 whether the consumer handled the message.
*
* 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(bool* outHandled);
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 and specifies whether the message was handled by the consumer.
*
* Returns OK on success.
* Errors probably indicate that the channel is broken.
*/
status_t sendFinishedSignal(bool handled);
/* 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

Просмотреть файл

@ -0,0 +1,68 @@
/*
* Copyright (C) 2011 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.
*/
#define LOG_TAG "InputWindow"
#include "InputWindow.h"
#include <cutils/log.h>
namespace android {
// --- InputWindowInfo ---
bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
#ifdef HAVE_ANDROID_OS
return touchableRegion.contains(x, y);
#else
return false;
#endif
}
bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight
&& y >= frameTop && y <= frameBottom;
}
bool InputWindowInfo::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
bool InputWindowInfo::supportsSplitTouch() const {
return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
// --- InputWindowHandle ---
InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
}
InputWindowHandle::~InputWindowHandle() {
delete mInfo;
}
void InputWindowHandle::releaseInfo() {
if (mInfo) {
delete mInfo;
mInfo = NULL;
}
}
} // namespace android

Просмотреть файл

@ -0,0 +1,204 @@
/*
* Copyright (C) 2011 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_WINDOW_H
#define _UI_INPUT_WINDOW_H
#include "Input.h"
#include "InputTransport.h"
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/String8.h>
#include "SkRegion.h"
#include "InputApplication.h"
namespace android {
/*
* Describes the properties of a window that can receive input.
*/
struct InputWindowInfo {
// 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_HARDWARE_ACCELERATED = 0x01000000,
FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000,
FLAG_SLIPPERY = 0x04000000,
FLAG_NEEDS_MENU_KEY = 0x08000000,
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,
TYPE_DRAG = FIRST_SYSTEM_WINDOW+16,
TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17,
TYPE_POINTER = FIRST_SYSTEM_WINDOW+18,
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
LAST_SYSTEM_WINDOW = 2999,
};
enum {
INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
};
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;
float scaleFactor;
#ifdef HAVE_ANDROID_OS
SkRegion touchableRegion;
#endif
bool visible;
bool canReceiveKeys;
bool hasFocus;
bool hasWallpaper;
bool paused;
int32_t layer;
int32_t ownerPid;
int32_t ownerUid;
int32_t inputFeatures;
bool touchableRegionContainsPoint(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;
bool supportsSplitTouch() const;
};
/*
* Handle for a window that can receive input.
*
* Used by the native input dispatcher to indirectly refer to the window manager objects
* that describe a window.
*/
class InputWindowHandle : public RefBase {
public:
const sp<InputApplicationHandle> inputApplicationHandle;
inline const InputWindowInfo* getInfo() const {
return mInfo;
}
inline sp<InputChannel> getInputChannel() const {
return mInfo ? mInfo->inputChannel : NULL;
}
inline String8 getName() const {
return mInfo ? mInfo->name : String8("<invalid>");
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
return mInfo ? mInfo->dispatchingTimeout : defaultValue;
}
/**
* Requests that the state of this object be updated to reflect
* the most current available information about the application.
*
* This method should only be called from within the input dispatcher's
* critical section.
*
* Returns true on success, or false if the handle is no longer valid.
*/
virtual bool updateInfo() = 0;
/**
* Releases the storage used by the associated information when it is
* no longer needed.
*/
void releaseInfo();
protected:
InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual ~InputWindowHandle();
InputWindowInfo* mInfo;
};
} // namespace android
#endif // _UI_INPUT_WINDOW_H

Просмотреть файл

@ -0,0 +1,838 @@
/*
* Copyright (C) 2008 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.
*/
#define LOG_TAG "KeyCharacterMap"
#include <stdlib.h>
#include <string.h>
#include <android/keycodes.h>
#include "Keyboard.h"
#include "KeyCharacterMap.h"
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
#include <utils/Timers.h>
// Enables debug output for the parser.
#define DEBUG_PARSER 0
// Enables debug output for parser performance.
#define DEBUG_PARSER_PERFORMANCE 0
// Enables debug output for mapping.
#define DEBUG_MAPPING 0
namespace android {
static const char* WHITESPACE = " \t\r";
static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:";
struct Modifier {
const char* label;
int32_t metaState;
};
static const Modifier modifiers[] = {
{ "shift", AMETA_SHIFT_ON },
{ "lshift", AMETA_SHIFT_LEFT_ON },
{ "rshift", AMETA_SHIFT_RIGHT_ON },
{ "alt", AMETA_ALT_ON },
{ "lalt", AMETA_ALT_LEFT_ON },
{ "ralt", AMETA_ALT_RIGHT_ON },
{ "ctrl", AMETA_CTRL_ON },
{ "lctrl", AMETA_CTRL_LEFT_ON },
{ "rctrl", AMETA_CTRL_RIGHT_ON },
{ "meta", AMETA_META_ON },
{ "lmeta", AMETA_META_LEFT_ON },
{ "rmeta", AMETA_META_RIGHT_ON },
{ "sym", AMETA_SYM_ON },
{ "fn", AMETA_FUNCTION_ON },
{ "capslock", AMETA_CAPS_LOCK_ON },
{ "numlock", AMETA_NUM_LOCK_ON },
{ "scrolllock", AMETA_SCROLL_LOCK_ON },
};
#if DEBUG_MAPPING
static String8 toString(const char16_t* chars, size_t numChars) {
String8 result;
for (size_t i = 0; i < numChars; i++) {
result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]);
}
return result;
}
#endif
// --- KeyCharacterMap ---
KeyCharacterMap::KeyCharacterMap() :
mType(KEYBOARD_TYPE_UNKNOWN) {
}
KeyCharacterMap::~KeyCharacterMap() {
for (size_t i = 0; i < mKeys.size(); i++) {
Key* key = mKeys.editValueAt(i);
delete key;
}
}
status_t KeyCharacterMap::load(const String8& filename, KeyCharacterMap** outMap) {
*outMap = NULL;
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
if (status) {
ALOGE("Error %d opening key character map file %s.", status, filename.string());
} else {
KeyCharacterMap* map = new KeyCharacterMap();
if (!map) {
ALOGE("Error allocating key character map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
Parser parser(map, tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (status) {
delete map;
} else {
*outMap = map;
}
}
delete tokenizer;
}
return status;
}
int32_t KeyCharacterMap::getKeyboardType() const {
return mType;
}
char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const {
char16_t result = 0;
const Key* key;
if (getKey(keyCode, &key)) {
result = key->label;
}
#if DEBUG_MAPPING
ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result);
#endif
return result;
}
char16_t KeyCharacterMap::getNumber(int32_t keyCode) const {
char16_t result = 0;
const Key* key;
if (getKey(keyCode, &key)) {
result = key->number;
}
#if DEBUG_MAPPING
ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result);
#endif
return result;
}
char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
char16_t result = 0;
const Key* key;
const Behavior* behavior;
if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
result = behavior->character;
}
#if DEBUG_MAPPING
ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result);
#endif
return result;
}
bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState,
FallbackAction* outFallbackAction) const {
outFallbackAction->keyCode = 0;
outFallbackAction->metaState = 0;
bool result = false;
const Key* key;
const Behavior* behavior;
if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
if (behavior->fallbackKeyCode) {
outFallbackAction->keyCode = behavior->fallbackKeyCode;
outFallbackAction->metaState = metaState & ~behavior->metaState;
result = true;
}
}
#if DEBUG_MAPPING
ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, "
"fallback keyCode=%d, fallback metaState=0x%08x.",
keyCode, metaState, result ? "true" : "false",
outFallbackAction->keyCode, outFallbackAction->metaState);
#endif
return result;
}
char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars,
int32_t metaState) const {
char16_t result = 0;
const Key* key;
if (getKey(keyCode, &key)) {
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
// However, if we find a perfect meta state match for one behavior then use that one.
for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
if (behavior->character) {
for (size_t i = 0; i < numChars; i++) {
if (behavior->character == chars[i]) {
result = behavior->character;
if ((behavior->metaState & metaState) == behavior->metaState) {
goto ExactMatch;
}
break;
}
}
}
}
ExactMatch: ;
}
#if DEBUG_MAPPING
ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
keyCode, toString(chars, numChars).string(), metaState, result);
#endif
return result;
}
bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
Vector<KeyEvent>& outEvents) const {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
for (size_t i = 0; i < numChars; i++) {
int32_t keyCode, metaState;
char16_t ch = chars[i];
if (!findKey(ch, &keyCode, &metaState)) {
#if DEBUG_MAPPING
ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.",
deviceId, toString(chars, numChars).string(), ch);
#endif
return false;
}
int32_t currentMetaState = 0;
addMetaKeys(outEvents, deviceId, metaState, true, now, &currentMetaState);
addKey(outEvents, deviceId, keyCode, currentMetaState, true, now);
addKey(outEvents, deviceId, keyCode, currentMetaState, false, now);
addMetaKeys(outEvents, deviceId, metaState, false, now, &currentMetaState);
}
#if DEBUG_MAPPING
ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.",
deviceId, toString(chars, numChars).string(), int32_t(outEvents.size()));
for (size_t i = 0; i < outEvents.size(); i++) {
ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.",
outEvents[i].getKeyCode(), outEvents[i].getMetaState(),
outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up");
}
#endif
return true;
}
bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
ssize_t index = mKeys.indexOfKey(keyCode);
if (index >= 0) {
*outKey = mKeys.valueAt(index);
return true;
}
return false;
}
bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
const Key** outKey, const Behavior** outBehavior) const {
const Key* key;
if (getKey(keyCode, &key)) {
const Behavior* behavior = key->firstBehavior;
while (behavior) {
if ((behavior->metaState & metaState) == behavior->metaState) {
*outKey = key;
*outBehavior = behavior;
return true;
}
behavior = behavior->next;
}
}
return false;
}
bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const {
if (!ch) {
return false;
}
for (size_t i = 0; i < mKeys.size(); i++) {
const Key* key = mKeys.valueAt(i);
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
const Behavior* found = NULL;
for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
if (behavior->character == ch) {
found = behavior;
}
}
if (found) {
*outKeyCode = mKeys.keyAt(i);
*outMetaState = found->metaState;
return true;
}
}
return false;
}
void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
outEvents.push();
KeyEvent& event = outEvents.editTop();
event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
0, keyCode, 0, metaState, 0, time, time);
}
void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
int32_t* currentMetaState) {
// Add and remove meta keys symmetrically.
if (down) {
addLockedMetaKey(outEvents, deviceId, metaState, time,
AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
addLockedMetaKey(outEvents, deviceId, metaState, time,
AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
addLockedMetaKey(outEvents, deviceId, metaState, time,
AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
AMETA_SHIFT_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
AMETA_ALT_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
AMETA_CTRL_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
AMETA_META_ON, currentMetaState);
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time,
AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
} else {
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState);
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
AKEYCODE_META_LEFT, AMETA_META_LEFT_ON,
AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON,
AMETA_META_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON,
AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON,
AMETA_CTRL_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON,
AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON,
AMETA_ALT_ON, currentMetaState);
addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time,
AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON,
AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON,
AMETA_SHIFT_ON, currentMetaState);
addLockedMetaKey(outEvents, deviceId, metaState, time,
AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState);
addLockedMetaKey(outEvents, deviceId, metaState, time,
AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState);
addLockedMetaKey(outEvents, deviceId, metaState, time,
AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState);
}
}
bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState) {
if ((metaState & keyMetaState) == keyMetaState) {
*currentMetaState = updateMetaState(keyCode, down, *currentMetaState);
addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time);
return true;
}
return false;
}
void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
int32_t leftKeyCode, int32_t leftKeyMetaState,
int32_t rightKeyCode, int32_t rightKeyMetaState,
int32_t eitherKeyMetaState,
int32_t* currentMetaState) {
bool specific = false;
specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
leftKeyCode, leftKeyMetaState, currentMetaState);
specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
rightKeyCode, rightKeyMetaState, currentMetaState);
if (!specific) {
addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time,
leftKeyCode, eitherKeyMetaState, currentMetaState);
}
}
void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState) {
if ((metaState & keyMetaState) == keyMetaState) {
*currentMetaState = updateMetaState(keyCode, true, *currentMetaState);
addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time);
*currentMetaState = updateMetaState(keyCode, false, *currentMetaState);
addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time);
}
}
// --- KeyCharacterMap::Key ---
KeyCharacterMap::Key::Key() :
label(0), number(0), firstBehavior(NULL) {
}
KeyCharacterMap::Key::~Key() {
Behavior* behavior = firstBehavior;
while (behavior) {
Behavior* next = behavior->next;
delete behavior;
behavior = next;
}
}
// --- KeyCharacterMap::Behavior ---
KeyCharacterMap::Behavior::Behavior() :
next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
}
// --- KeyCharacterMap::Parser ---
KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer) :
mMap(map), mTokenizer(tokenizer), mState(STATE_TOP) {
}
KeyCharacterMap::Parser::~Parser() {
}
status_t KeyCharacterMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
switch (mState) {
case STATE_TOP: {
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
if (keywordToken == "type") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseType();
if (status) return status;
} else if (keywordToken == "key") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseKey();
if (status) return status;
} else {
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
keywordToken.string());
return BAD_VALUE;
}
break;
}
case STATE_KEY: {
status_t status = parseKeyProperty();
if (status) return status;
break;
}
}
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol()) {
ALOGE("%s: Expected end of line, got '%s'.",
mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
return BAD_VALUE;
}
}
mTokenizer->nextLine();
}
if (mState != STATE_TOP) {
ALOGE("%s: Unterminated key description at end of file.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
ALOGE("%s: Missing required keyboard 'type' declaration.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseType() {
if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
ALOGE("%s: Duplicate keyboard 'type' declaration.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
KeyboardType type;
String8 typeToken = mTokenizer->nextToken(WHITESPACE);
if (typeToken == "NUMERIC") {
type = KEYBOARD_TYPE_NUMERIC;
} else if (typeToken == "PREDICTIVE") {
type = KEYBOARD_TYPE_PREDICTIVE;
} else if (typeToken == "ALPHA") {
type = KEYBOARD_TYPE_ALPHA;
} else if (typeToken == "FULL") {
type = KEYBOARD_TYPE_FULL;
} else if (typeToken == "SPECIAL_FUNCTION") {
type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
} else {
ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
typeToken.string());
return BAD_VALUE;
}
#if DEBUG_PARSER
ALOGD("Parsed type: type=%d.", type);
#endif
mMap->mType = type;
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseKey() {
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
if (!keyCode) {
ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
keyCodeToken.string());
return BAD_VALUE;
}
if (mMap->mKeys.indexOfKey(keyCode) >= 0) {
ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
keyCodeToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 openBraceToken = mTokenizer->nextToken(WHITESPACE);
if (openBraceToken != "{") {
ALOGE("%s: Expected '{' after key code label, got '%s'.",
mTokenizer->getLocation().string(), openBraceToken.string());
return BAD_VALUE;
}
#if DEBUG_PARSER
ALOGD("Parsed beginning of key: keyCode=%d.", keyCode);
#endif
mKeyCode = keyCode;
mMap->mKeys.add(keyCode, new Key());
mState = STATE_KEY;
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseKeyProperty() {
String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
if (token == "}") {
mState = STATE_TOP;
return NO_ERROR;
}
Vector<Property> properties;
// Parse all comma-delimited property names up to the first colon.
for (;;) {
if (token == "label") {
properties.add(Property(PROPERTY_LABEL));
} else if (token == "number") {
properties.add(Property(PROPERTY_NUMBER));
} else {
int32_t metaState;
status_t status = parseModifier(token, &metaState);
if (status) {
ALOGE("%s: Expected a property name or modifier, got '%s'.",
mTokenizer->getLocation().string(), token.string());
return status;
}
properties.add(Property(PROPERTY_META, metaState));
}
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol()) {
char ch = mTokenizer->nextChar();
if (ch == ':') {
break;
} else if (ch == ',') {
mTokenizer->skipDelimiters(WHITESPACE);
token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
continue;
}
}
ALOGE("%s: Expected ',' or ':' after property name.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
// Parse behavior after the colon.
mTokenizer->skipDelimiters(WHITESPACE);
Behavior behavior;
bool haveCharacter = false;
bool haveFallback = false;
do {
char ch = mTokenizer->peekChar();
if (ch == '\'') {
char16_t character;
status_t status = parseCharacterLiteral(&character);
if (status || !character) {
ALOGE("%s: Invalid character literal for key.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
if (haveCharacter) {
ALOGE("%s: Cannot combine multiple character literals or 'none'.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
behavior.character = character;
haveCharacter = true;
} else {
token = mTokenizer->nextToken(WHITESPACE);
if (token == "none") {
if (haveCharacter) {
ALOGE("%s: Cannot combine multiple character literals or 'none'.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
haveCharacter = true;
} else if (token == "fallback") {
mTokenizer->skipDelimiters(WHITESPACE);
token = mTokenizer->nextToken(WHITESPACE);
int32_t keyCode = getKeyCodeByLabel(token.string());
if (!keyCode) {
ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.",
mTokenizer->getLocation().string(),
token.string());
return BAD_VALUE;
}
if (haveFallback) {
ALOGE("%s: Cannot combine multiple fallback key codes.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
behavior.fallbackKeyCode = keyCode;
haveFallback = true;
} else {
ALOGE("%s: Expected a key behavior after ':'.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
}
mTokenizer->skipDelimiters(WHITESPACE);
} while (!mTokenizer->isEol());
// Add the behavior.
Key* key = mMap->mKeys.valueFor(mKeyCode);
for (size_t i = 0; i < properties.size(); i++) {
const Property& property = properties.itemAt(i);
switch (property.property) {
case PROPERTY_LABEL:
if (key->label) {
ALOGE("%s: Duplicate label for key.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
key->label = behavior.character;
#if DEBUG_PARSER
ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
#endif
break;
case PROPERTY_NUMBER:
if (key->number) {
ALOGE("%s: Duplicate number for key.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
key->number = behavior.character;
#if DEBUG_PARSER
ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
#endif
break;
case PROPERTY_META: {
for (Behavior* b = key->firstBehavior; b; b = b->next) {
if (b->metaState == property.metaState) {
ALOGE("%s: Duplicate key behavior for modifier.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
}
Behavior* newBehavior = new Behavior(behavior);
newBehavior->metaState = property.metaState;
newBehavior->next = key->firstBehavior;
key->firstBehavior = newBehavior;
#if DEBUG_PARSER
ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
#endif
break;
}
}
}
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) {
if (token == "base") {
*outMetaState = 0;
return NO_ERROR;
}
int32_t combinedMeta = 0;
const char* str = token.string();
const char* start = str;
for (const char* cur = str; ; cur++) {
char ch = *cur;
if (ch == '+' || ch == '\0') {
size_t len = cur - start;
int32_t metaState = 0;
for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) {
if (strlen(modifiers[i].label) == len
&& strncmp(modifiers[i].label, start, len) == 0) {
metaState = modifiers[i].metaState;
break;
}
}
if (!metaState) {
return BAD_VALUE;
}
if (combinedMeta & metaState) {
ALOGE("%s: Duplicate modifier combination '%s'.",
mTokenizer->getLocation().string(), token.string());
return BAD_VALUE;
}
combinedMeta |= metaState;
start = cur + 1;
if (ch == '\0') {
break;
}
}
}
*outMetaState = combinedMeta;
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) {
char ch = mTokenizer->nextChar();
if (ch != '\'') {
goto Error;
}
ch = mTokenizer->nextChar();
if (ch == '\\') {
// Escape sequence.
ch = mTokenizer->nextChar();
if (ch == 'n') {
*outCharacter = '\n';
} else if (ch == 't') {
*outCharacter = '\t';
} else if (ch == '\\') {
*outCharacter = '\\';
} else if (ch == '\'') {
*outCharacter = '\'';
} else if (ch == '"') {
*outCharacter = '"';
} else if (ch == 'u') {
*outCharacter = 0;
for (int i = 0; i < 4; i++) {
ch = mTokenizer->nextChar();
int digit;
if (ch >= '0' && ch <= '9') {
digit = ch - '0';
} else if (ch >= 'A' && ch <= 'F') {
digit = ch - 'A' + 10;
} else if (ch >= 'a' && ch <= 'f') {
digit = ch - 'a' + 10;
} else {
goto Error;
}
*outCharacter = (*outCharacter << 4) | digit;
}
} else {
goto Error;
}
} else if (ch >= 32 && ch <= 126 && ch != '\'') {
// ASCII literal character.
*outCharacter = ch;
} else {
goto Error;
}
ch = mTokenizer->nextChar();
if (ch != '\'') {
goto Error;
}
// Ensure that we consumed the entire token.
if (mTokenizer->nextToken(WHITESPACE).isEmpty()) {
return NO_ERROR;
}
Error:
ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string());
return BAD_VALUE;
}
} // namespace android

Просмотреть файл

@ -0,0 +1,199 @@
/*
* Copyright (C) 2008 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_KEY_CHARACTER_MAP_H
#define _UI_KEY_CHARACTER_MAP_H
#include <stdint.h>
#include "Input.h"
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
#include <utils/String8.h>
#include <utils/Unicode.h>
namespace android {
/**
* Describes a mapping from Android key codes to characters.
* Also specifies other functions of the keyboard such as the keyboard type
* and key modifier semantics.
*/
class KeyCharacterMap {
public:
enum KeyboardType {
KEYBOARD_TYPE_UNKNOWN = 0,
KEYBOARD_TYPE_NUMERIC = 1,
KEYBOARD_TYPE_PREDICTIVE = 2,
KEYBOARD_TYPE_ALPHA = 3,
KEYBOARD_TYPE_FULL = 4,
KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
};
// Substitute key code and meta state for fallback action.
struct FallbackAction {
int32_t keyCode;
int32_t metaState;
};
~KeyCharacterMap();
static status_t load(const String8& filename, KeyCharacterMap** outMap);
/* Gets the keyboard type. */
int32_t getKeyboardType() const;
/* Gets the primary character for this key as in the label physically printed on it.
* Returns 0 if none (eg. for non-printing keys). */
char16_t getDisplayLabel(int32_t keyCode) const;
/* Gets the Unicode character for the number or symbol generated by the key
* when the keyboard is used as a dialing pad.
* Returns 0 if no number or symbol is generated.
*/
char16_t getNumber(int32_t keyCode) const;
/* Gets the Unicode character generated by the key and meta key modifiers.
* Returns 0 if no character is generated.
*/
char16_t getCharacter(int32_t keyCode, int32_t metaState) const;
/* Gets the fallback action to use by default if the application does not
* handle the specified key.
* Returns true if an action was available, false if none.
*/
bool getFallbackAction(int32_t keyCode, int32_t metaState,
FallbackAction* outFallbackAction) const;
/* Gets the first matching Unicode character that can be generated by the key,
* preferring the one with the specified meta key modifiers.
* Returns 0 if no matching character is generated.
*/
char16_t getMatch(int32_t keyCode, const char16_t* chars,
size_t numChars, int32_t metaState) const;
/* Gets a sequence of key events that could plausibly generate the specified
* character sequence. Returns false if some of the characters cannot be generated.
*/
bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
Vector<KeyEvent>& outEvents) const;
private:
struct Behavior {
Behavior();
/* The next behavior in the list, or NULL if none. */
Behavior* next;
/* The meta key modifiers for this behavior. */
int32_t metaState;
/* The character to insert. */
char16_t character;
/* The fallback keycode if the key is not handled. */
int32_t fallbackKeyCode;
};
struct Key {
Key();
~Key();
/* The single character label printed on the key, or 0 if none. */
char16_t label;
/* The number or symbol character generated by the key, or 0 if none. */
char16_t number;
/* The list of key behaviors sorted from most specific to least specific
* meta key binding. */
Behavior* firstBehavior;
};
class Parser {
enum State {
STATE_TOP = 0,
STATE_KEY = 1,
};
enum {
PROPERTY_LABEL = 1,
PROPERTY_NUMBER = 2,
PROPERTY_META = 3,
};
struct Property {
inline Property(int32_t property = 0, int32_t metaState = 0) :
property(property), metaState(metaState) { }
int32_t property;
int32_t metaState;
};
KeyCharacterMap* mMap;
Tokenizer* mTokenizer;
State mState;
int32_t mKeyCode;
public:
Parser(KeyCharacterMap* map, Tokenizer* tokenizer);
~Parser();
status_t parse();
private:
status_t parseType();
status_t parseKey();
status_t parseKeyProperty();
status_t parseModifier(const String8& token, int32_t* outMetaState);
status_t parseCharacterLiteral(char16_t* outCharacter);
};
KeyedVector<int32_t, Key*> mKeys;
int mType;
KeyCharacterMap();
bool getKey(int32_t keyCode, const Key** outKey) const;
bool getKeyBehavior(int32_t keyCode, int32_t metaState,
const Key** outKey, const Behavior** outBehavior) const;
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
static void addKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
static void addMetaKeys(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
int32_t* currentMetaState);
static bool addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState);
static void addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, bool down, nsecs_t time,
int32_t leftKeyCode, int32_t leftKeyMetaState,
int32_t rightKeyCode, int32_t rightKeyMetaState,
int32_t eitherKeyMetaState,
int32_t* currentMetaState);
static void addLockedMetaKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t metaState, nsecs_t time,
int32_t keyCode, int32_t keyMetaState,
int32_t* currentMetaState);
};
} // namespace android
#endif // _UI_KEY_CHARACTER_MAP_H

Просмотреть файл

@ -0,0 +1,341 @@
/*
* Copyright (C) 2008 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.
*/
#define LOG_TAG "KeyLayoutMap"
#include <stdlib.h>
#include <android/keycodes.h>
#include "Keyboard.h"
#include "KeyLayoutMap.h"
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
#include <utils/Timers.h>
// Enables debug output for the parser.
#define DEBUG_PARSER 0
// Enables debug output for parser performance.
#define DEBUG_PARSER_PERFORMANCE 0
// Enables debug output for mapping.
#define DEBUG_MAPPING 0
namespace android {
static const char* WHITESPACE = " \t\r";
// --- KeyLayoutMap ---
KeyLayoutMap::KeyLayoutMap() {
}
KeyLayoutMap::~KeyLayoutMap() {
}
status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) {
*outMap = NULL;
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
if (status) {
ALOGE("Error %d opening key layout map file %s.", status, filename.string());
} else {
KeyLayoutMap* map = new KeyLayoutMap();
if (!map) {
ALOGE("Error allocating key layout map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
Parser parser(map, tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (status) {
delete map;
} else {
*outMap = map;
}
}
delete tokenizer;
}
return status;
}
status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
ssize_t index = mKeys.indexOfKey(scanCode);
if (index < 0) {
#if DEBUG_MAPPING
ALOGD("mapKey: scanCode=%d ~ Failed.", scanCode);
#endif
*keyCode = AKEYCODE_UNKNOWN;
*flags = 0;
return NAME_NOT_FOUND;
}
const Key& k = mKeys.valueAt(index);
*keyCode = k.keyCode;
*flags = k.flags;
#if DEBUG_MAPPING
ALOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
#endif
return NO_ERROR;
}
status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
const size_t N = mKeys.size();
for (size_t i=0; i<N; i++) {
if (mKeys.valueAt(i).keyCode == keyCode) {
outScanCodes->add(mKeys.keyAt(i));
}
}
return NO_ERROR;
}
status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
ssize_t index = mAxes.indexOfKey(scanCode);
if (index < 0) {
#if DEBUG_MAPPING
ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
#endif
return NAME_NOT_FOUND;
}
*outAxisInfo = mAxes.valueAt(index);
#if DEBUG_MAPPING
ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
"splitValue=%d, flatOverride=%d.",
scanCode,
outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
outAxisInfo->splitValue, outAxisInfo->flatOverride);
#endif
return NO_ERROR;
}
// --- KeyLayoutMap::Parser ---
KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
mMap(map), mTokenizer(tokenizer) {
}
KeyLayoutMap::Parser::~Parser() {
}
status_t KeyLayoutMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
if (keywordToken == "key") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseKey();
if (status) return status;
} else if (keywordToken == "axis") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseAxis();
if (status) return status;
} else {
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
keywordToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol()) {
ALOGE("%s: Expected end of line, got '%s'.",
mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
return BAD_VALUE;
}
}
mTokenizer->nextLine();
}
return NO_ERROR;
}
status_t KeyLayoutMap::Parser::parseKey() {
String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
char* end;
int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
if (*end) {
ALOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
}
if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
ALOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
if (!keyCode) {
ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
keyCodeToken.string());
return BAD_VALUE;
}
uint32_t flags = 0;
for (;;) {
mTokenizer->skipDelimiters(WHITESPACE);
if (mTokenizer->isEol()) break;
String8 flagToken = mTokenizer->nextToken(WHITESPACE);
uint32_t flag = getKeyFlagByLabel(flagToken.string());
if (!flag) {
ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
flagToken.string());
return BAD_VALUE;
}
if (flags & flag) {
ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
flagToken.string());
return BAD_VALUE;
}
flags |= flag;
}
#if DEBUG_PARSER
ALOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
#endif
Key key;
key.keyCode = keyCode;
key.flags = flags;
mMap->mKeys.add(scanCode, key);
return NO_ERROR;
}
status_t KeyLayoutMap::Parser::parseAxis() {
String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
char* end;
int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
if (*end) {
ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
}
if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
scanCodeToken.string());
return BAD_VALUE;
}
AxisInfo axisInfo;
mTokenizer->skipDelimiters(WHITESPACE);
String8 token = mTokenizer->nextToken(WHITESPACE);
if (token == "invert") {
axisInfo.mode = AxisInfo::MODE_INVERT;
mTokenizer->skipDelimiters(WHITESPACE);
String8 axisToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.axis = getAxisByLabel(axisToken.string());
if (axisInfo.axis < 0) {
ALOGE("%s: Expected inverted axis label, got '%s'.",
mTokenizer->getLocation().string(), axisToken.string());
return BAD_VALUE;
}
} else if (token == "split") {
axisInfo.mode = AxisInfo::MODE_SPLIT;
mTokenizer->skipDelimiters(WHITESPACE);
String8 splitToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
if (*end) {
ALOGE("%s: Expected split value, got '%s'.",
mTokenizer->getLocation().string(), splitToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.axis = getAxisByLabel(lowAxisToken.string());
if (axisInfo.axis < 0) {
ALOGE("%s: Expected low axis label, got '%s'.",
mTokenizer->getLocation().string(), lowAxisToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
if (axisInfo.highAxis < 0) {
ALOGE("%s: Expected high axis label, got '%s'.",
mTokenizer->getLocation().string(), highAxisToken.string());
return BAD_VALUE;
}
} else {
axisInfo.axis = getAxisByLabel(token.string());
if (axisInfo.axis < 0) {
ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
mTokenizer->getLocation().string(), token.string());
return BAD_VALUE;
}
}
for (;;) {
mTokenizer->skipDelimiters(WHITESPACE);
if (mTokenizer->isEol()) {
break;
}
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
if (keywordToken == "flat") {
mTokenizer->skipDelimiters(WHITESPACE);
String8 flatToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
if (*end) {
ALOGE("%s: Expected flat value, got '%s'.",
mTokenizer->getLocation().string(), flatToken.string());
return BAD_VALUE;
}
} else {
ALOGE("%s: Expected keyword 'flat', got '%s'.",
mTokenizer->getLocation().string(), keywordToken.string());
return BAD_VALUE;
}
}
#if DEBUG_PARSER
ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
"splitValue=%d, flatOverride=%d.",
scanCode,
axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
axisInfo.splitValue, axisInfo.flatOverride);
#endif
mMap->mAxes.add(scanCode, axisInfo);
return NO_ERROR;
}
};

Просмотреть файл

@ -0,0 +1,99 @@
/*
* Copyright (C) 2008 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_KEY_LAYOUT_MAP_H
#define _UI_KEY_LAYOUT_MAP_H
#include <stdint.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
namespace android {
struct AxisInfo {
enum Mode {
// Axis value is reported directly.
MODE_NORMAL = 0,
// Axis value should be inverted before reporting.
MODE_INVERT = 1,
// Axis value should be split into two axes
MODE_SPLIT = 2,
};
// Axis mode.
Mode mode;
// Axis id.
// When split, this is the axis used for values smaller than the split position.
int32_t axis;
// When split, this is the axis used for values after higher than the split position.
int32_t highAxis;
// The split value, or 0 if not split.
int32_t splitValue;
// The flat value, or -1 if none.
int32_t flatOverride;
AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
}
};
/**
* Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
*/
class KeyLayoutMap {
public:
~KeyLayoutMap();
static status_t load(const String8& filename, KeyLayoutMap** outMap);
status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
private:
struct Key {
int32_t keyCode;
uint32_t flags;
};
KeyedVector<int32_t, Key> mKeys;
KeyedVector<int32_t, AxisInfo> mAxes;
KeyLayoutMap();
class Parser {
KeyLayoutMap* mMap;
Tokenizer* mTokenizer;
public:
Parser(KeyLayoutMap* map, Tokenizer* tokenizer);
~Parser();
status_t parse();
private:
status_t parseKey();
status_t parseAxis();
};
};
} // namespace android
#endif // _UI_KEY_LAYOUT_MAP_H

Просмотреть файл

@ -0,0 +1,303 @@
/*
* 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.
*/
#define LOG_TAG "Keyboard"
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include "Keyboard.h"
#include "KeycodeLabels.h"
#include "KeyLayoutMap.h"
#include "KeyCharacterMap.h"
#include <utils/Errors.h>
#include <utils/Log.h>
#include <cutils/properties.h>
namespace android {
// --- KeyMap ---
KeyMap::KeyMap() :
keyLayoutMap(NULL), keyCharacterMap(NULL) {
}
KeyMap::~KeyMap() {
delete keyLayoutMap;
delete keyCharacterMap;
}
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
if (isComplete()) {
return OK;
}
}
// Try searching by device identifier.
if (probeKeyMap(deviceIdenfifier, String8::empty())) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
return OK;
}
// Try the Virtual key map as a last resort.
if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
return OK;
}
// Give up!
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
deviceIdenfifier.name.string());
return NAME_NOT_FOUND;
}
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
const String8& keyMapName) {
if (!haveKeyLayout()) {
loadKeyLayout(deviceIdentifier, keyMapName);
}
if (!haveKeyCharacterMap()) {
loadKeyCharacterMap(deviceIdentifier, keyMapName);
}
return isComplete();
}
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
const String8& name) {
String8 path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
if (path.isEmpty()) {
return NAME_NOT_FOUND;
}
KeyLayoutMap* map;
status_t status = KeyLayoutMap::load(path, &map);
if (status) {
return status;
}
keyLayoutFile.setTo(path);
keyLayoutMap = map;
return OK;
}
status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
const String8& name) {
String8 path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
if (path.isEmpty()) {
return NAME_NOT_FOUND;
}
KeyCharacterMap* map;
status_t status = KeyCharacterMap::load(path, &map);
if (status) {
return status;
}
keyCharacterMapFile.setTo(path);
keyCharacterMap = map;
return OK;
}
String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
const String8& name, InputDeviceConfigurationFileType type) {
return name.isEmpty()
? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
: getInputDeviceConfigurationFilePathByName(name, type);
}
// --- Global functions ---
bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
if (!keyMap->haveKeyCharacterMap()
|| keyMap->keyCharacterMap->getKeyboardType()
== KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
return false;
}
if (deviceConfiguration) {
bool builtIn = false;
if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
&& builtIn) {
return true;
}
}
return strstr(deviceIdentifier.name.string(), "-keypad");
}
static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
while (list->literal) {
if (strcmp(literal, list->literal) == 0) {
return list->value;
}
list++;
}
return list->value;
}
static const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
while (list->literal) {
if (list->value == value) {
return list->literal;
}
list++;
}
return NULL;
}
int32_t getKeyCodeByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, KEYCODES));
}
uint32_t getKeyFlagByLabel(const char* label) {
return uint32_t(lookupValueByLabel(label, FLAGS));
}
int32_t getAxisByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, AXES));
}
const char* getAxisLabel(int32_t axisId) {
return lookupLabelByValue(axisId, AXES);
}
static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
int32_t newMetaState;
if (down) {
newMetaState = oldMetaState | mask;
} else {
newMetaState = oldMetaState &
~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
}
if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
newMetaState |= AMETA_ALT_ON;
}
if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
newMetaState |= AMETA_SHIFT_ON;
}
if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
newMetaState |= AMETA_CTRL_ON;
}
if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
newMetaState |= AMETA_META_ON;
}
return newMetaState;
}
static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
if (down) {
return oldMetaState;
} else {
return oldMetaState ^ mask;
}
}
int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
int32_t mask;
switch (keyCode) {
case AKEYCODE_ALT_LEFT:
return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
case AKEYCODE_ALT_RIGHT:
return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
case AKEYCODE_SHIFT_LEFT:
return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
case AKEYCODE_SHIFT_RIGHT:
return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
case AKEYCODE_SYM:
return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
case AKEYCODE_FUNCTION:
return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
case AKEYCODE_CTRL_LEFT:
return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
case AKEYCODE_CTRL_RIGHT:
return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
case AKEYCODE_META_LEFT:
return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
case AKEYCODE_META_RIGHT:
return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
case AKEYCODE_CAPS_LOCK:
return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
case AKEYCODE_NUM_LOCK:
return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
case AKEYCODE_SCROLL_LOCK:
return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
default:
return oldMetaState;
}
}
bool isMetaKey(int32_t keyCode) {
switch (keyCode) {
case AKEYCODE_ALT_LEFT:
case AKEYCODE_ALT_RIGHT:
case AKEYCODE_SHIFT_LEFT:
case AKEYCODE_SHIFT_RIGHT:
case AKEYCODE_SYM:
case AKEYCODE_FUNCTION:
case AKEYCODE_CTRL_LEFT:
case AKEYCODE_CTRL_RIGHT:
case AKEYCODE_META_LEFT:
case AKEYCODE_META_RIGHT:
case AKEYCODE_CAPS_LOCK:
case AKEYCODE_NUM_LOCK:
case AKEYCODE_SCROLL_LOCK:
return true;
default:
return false;
}
}
} // namespace android

Просмотреть файл

@ -0,0 +1,119 @@
/*
* 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_KEYBOARD_H
#define _UI_KEYBOARD_H
#include "Input.h"
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/PropertyMap.h>
namespace android {
enum {
/* Device id of the built in keyboard. */
DEVICE_ID_BUILT_IN_KEYBOARD = 0,
/* Device id of a generic virtual keyboard with a full layout that can be used
* to synthesize key events. */
DEVICE_ID_VIRTUAL_KEYBOARD = -1,
};
class KeyLayoutMap;
class KeyCharacterMap;
/**
* Loads the key layout map and key character map for a keyboard device.
*/
class KeyMap {
public:
String8 keyLayoutFile;
KeyLayoutMap* keyLayoutMap;
String8 keyCharacterMapFile;
KeyCharacterMap* keyCharacterMap;
KeyMap();
~KeyMap();
status_t load(const InputDeviceIdentifier& deviceIdenfier,
const PropertyMap* deviceConfiguration);
inline bool haveKeyLayout() const {
return !keyLayoutFile.isEmpty();
}
inline bool haveKeyCharacterMap() const {
return !keyCharacterMapFile.isEmpty();
}
inline bool isComplete() const {
return haveKeyLayout() && haveKeyCharacterMap();
}
private:
bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name);
status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
const String8& name);
String8 getPath(const InputDeviceIdentifier& deviceIdentifier,
const String8& name, InputDeviceConfigurationFileType type);
};
/**
* Returns true if the keyboard is eligible for use as a built-in keyboard.
*/
extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
/**
* Gets a key code by its short form label, eg. "HOME".
* Returns 0 if unknown.
*/
extern int32_t getKeyCodeByLabel(const char* label);
/**
* Gets a key flag by its short form label, eg. "WAKE".
* Returns 0 if unknown.
*/
extern uint32_t getKeyFlagByLabel(const char* label);
/**
* Gets a axis by its short form label, eg. "X".
* Returns -1 if unknown.
*/
extern int32_t getAxisByLabel(const char* label);
/**
* Gets a axis label by its id.
* Returns NULL if unknown.
*/
extern const char* getAxisLabel(int32_t axisId);
/**
* Updates a meta state field when a key is pressed or released.
*/
extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
/**
* Returns true if a key is a meta key like ALT or CAPS_LOCK.
*/
extern bool isMetaKey(int32_t keyCode);
} // namespace android
#endif // _UI_KEYBOARD_H

Просмотреть файл

@ -0,0 +1,310 @@
/*
* Copyright (C) 2008 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_KEYCODE_LABELS_H
#define _UI_KEYCODE_LABELS_H
#include <android/keycodes.h>
struct KeycodeLabel {
const char *literal;
int value;
};
static const KeycodeLabel KEYCODES[] = {
{ "SOFT_LEFT", 1 },
{ "SOFT_RIGHT", 2 },
{ "HOME", 3 },
{ "BACK", 4 },
{ "CALL", 5 },
{ "ENDCALL", 6 },
{ "0", 7 },
{ "1", 8 },
{ "2", 9 },
{ "3", 10 },
{ "4", 11 },
{ "5", 12 },
{ "6", 13 },
{ "7", 14 },
{ "8", 15 },
{ "9", 16 },
{ "STAR", 17 },
{ "POUND", 18 },
{ "DPAD_UP", 19 },
{ "DPAD_DOWN", 20 },
{ "DPAD_LEFT", 21 },
{ "DPAD_RIGHT", 22 },
{ "DPAD_CENTER", 23 },
{ "VOLUME_UP", 24 },
{ "VOLUME_DOWN", 25 },
{ "POWER", 26 },
{ "CAMERA", 27 },
{ "CLEAR", 28 },
{ "A", 29 },
{ "B", 30 },
{ "C", 31 },
{ "D", 32 },
{ "E", 33 },
{ "F", 34 },
{ "G", 35 },
{ "H", 36 },
{ "I", 37 },
{ "J", 38 },
{ "K", 39 },
{ "L", 40 },
{ "M", 41 },
{ "N", 42 },
{ "O", 43 },
{ "P", 44 },
{ "Q", 45 },
{ "R", 46 },
{ "S", 47 },
{ "T", 48 },
{ "U", 49 },
{ "V", 50 },
{ "W", 51 },
{ "X", 52 },
{ "Y", 53 },
{ "Z", 54 },
{ "COMMA", 55 },
{ "PERIOD", 56 },
{ "ALT_LEFT", 57 },
{ "ALT_RIGHT", 58 },
{ "SHIFT_LEFT", 59 },
{ "SHIFT_RIGHT", 60 },
{ "TAB", 61 },
{ "SPACE", 62 },
{ "SYM", 63 },
{ "EXPLORER", 64 },
{ "ENVELOPE", 65 },
{ "ENTER", 66 },
{ "DEL", 67 },
{ "GRAVE", 68 },
{ "MINUS", 69 },
{ "EQUALS", 70 },
{ "LEFT_BRACKET", 71 },
{ "RIGHT_BRACKET", 72 },
{ "BACKSLASH", 73 },
{ "SEMICOLON", 74 },
{ "APOSTROPHE", 75 },
{ "SLASH", 76 },
{ "AT", 77 },
{ "NUM", 78 },
{ "HEADSETHOOK", 79 },
{ "FOCUS", 80 },
{ "PLUS", 81 },
{ "MENU", 82 },
{ "NOTIFICATION", 83 },
{ "SEARCH", 84 },
{ "MEDIA_PLAY_PAUSE", 85 },
{ "MEDIA_STOP", 86 },
{ "MEDIA_NEXT", 87 },
{ "MEDIA_PREVIOUS", 88 },
{ "MEDIA_REWIND", 89 },
{ "MEDIA_FAST_FORWARD", 90 },
{ "MUTE", 91 },
{ "PAGE_UP", 92 },
{ "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 },
{ "ESCAPE", 111 },
{ "FORWARD_DEL", 112 },
{ "CTRL_LEFT", 113 },
{ "CTRL_RIGHT", 114 },
{ "CAPS_LOCK", 115 },
{ "SCROLL_LOCK", 116 },
{ "META_LEFT", 117 },
{ "META_RIGHT", 118 },
{ "FUNCTION", 119 },
{ "SYSRQ", 120 },
{ "BREAK", 121 },
{ "MOVE_HOME", 122 },
{ "MOVE_END", 123 },
{ "INSERT", 124 },
{ "FORWARD", 125 },
{ "MEDIA_PLAY", 126 },
{ "MEDIA_PAUSE", 127 },
{ "MEDIA_CLOSE", 128 },
{ "MEDIA_EJECT", 129 },
{ "MEDIA_RECORD", 130 },
{ "F1", 131 },
{ "F2", 132 },
{ "F3", 133 },
{ "F4", 134 },
{ "F5", 135 },
{ "F6", 136 },
{ "F7", 137 },
{ "F8", 138 },
{ "F9", 139 },
{ "F10", 140 },
{ "F11", 141 },
{ "F12", 142 },
{ "NUM_LOCK", 143 },
{ "NUMPAD_0", 144 },
{ "NUMPAD_1", 145 },
{ "NUMPAD_2", 146 },
{ "NUMPAD_3", 147 },
{ "NUMPAD_4", 148 },
{ "NUMPAD_5", 149 },
{ "NUMPAD_6", 150 },
{ "NUMPAD_7", 151 },
{ "NUMPAD_8", 152 },
{ "NUMPAD_9", 153 },
{ "NUMPAD_DIVIDE", 154 },
{ "NUMPAD_MULTIPLY", 155 },
{ "NUMPAD_SUBTRACT", 156 },
{ "NUMPAD_ADD", 157 },
{ "NUMPAD_DOT", 158 },
{ "NUMPAD_COMMA", 159 },
{ "NUMPAD_ENTER", 160 },
{ "NUMPAD_EQUALS", 161 },
{ "NUMPAD_LEFT_PAREN", 162 },
{ "NUMPAD_RIGHT_PAREN", 163 },
{ "VOLUME_MUTE", 164 },
{ "INFO", 165 },
{ "CHANNEL_UP", 166 },
{ "CHANNEL_DOWN", 167 },
{ "ZOOM_IN", 168 },
{ "ZOOM_OUT", 169 },
{ "TV", 170 },
{ "WINDOW", 171 },
{ "GUIDE", 172 },
{ "DVR", 173 },
{ "BOOKMARK", 174 },
{ "CAPTIONS", 175 },
{ "SETTINGS", 176 },
{ "TV_POWER", 177 },
{ "TV_INPUT", 178 },
{ "STB_POWER", 179 },
{ "STB_INPUT", 180 },
{ "AVR_POWER", 181 },
{ "AVR_INPUT", 182 },
{ "PROG_RED", 183 },
{ "PROG_GREEN", 184 },
{ "PROG_YELLOW", 185 },
{ "PROG_BLUE", 186 },
{ "APP_SWITCH", 187 },
{ "BUTTON_1", 188 },
{ "BUTTON_2", 189 },
{ "BUTTON_3", 190 },
{ "BUTTON_4", 191 },
{ "BUTTON_5", 192 },
{ "BUTTON_6", 193 },
{ "BUTTON_7", 194 },
{ "BUTTON_8", 195 },
{ "BUTTON_9", 196 },
{ "BUTTON_10", 197 },
{ "BUTTON_11", 198 },
{ "BUTTON_12", 199 },
{ "BUTTON_13", 200 },
{ "BUTTON_14", 201 },
{ "BUTTON_15", 202 },
{ "BUTTON_16", 203 },
{ "LANGUAGE_SWITCH", 204 },
{ "MANNER_MODE", 205 },
{ "3D_MODE", 206 },
{ "CONTACTS", 207 },
{ "CALENDAR", 208 },
{ "MUSIC", 209 },
{ "CALCULATOR", 210 },
// 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 }
};
// NOTE: If you edit these flags, also edit policy flags in Input.h.
static const KeycodeLabel FLAGS[] = {
{ "WAKE", 0x00000001 },
{ "WAKE_DROPPED", 0x00000002 },
{ "SHIFT", 0x00000004 },
{ "CAPS_LOCK", 0x00000008 },
{ "ALT", 0x00000010 },
{ "ALT_GR", 0x00000020 },
{ "MENU", 0x00000040 },
{ "LAUNCHER", 0x00000080 },
{ "VIRTUAL", 0x00000100 },
{ "FUNCTION", 0x00000200 },
{ NULL, 0 }
};
static const KeycodeLabel AXES[] = {
{ "X", 0 },
{ "Y", 1 },
{ "PRESSURE", 2 },
{ "SIZE", 3 },
{ "TOUCH_MAJOR", 4 },
{ "TOUCH_MINOR", 5 },
{ "TOOL_MAJOR", 6 },
{ "TOOL_MINOR", 7 },
{ "ORIENTATION", 8 },
{ "VSCROLL", 9 },
{ "HSCROLL", 10 },
{ "Z", 11 },
{ "RX", 12 },
{ "RY", 13 },
{ "RZ", 14 },
{ "HAT_X", 15 },
{ "HAT_Y", 16 },
{ "LTRIGGER", 17 },
{ "RTRIGGER", 18 },
{ "THROTTLE", 19 },
{ "RUDDER", 20 },
{ "WHEEL", 21 },
{ "GAS", 22 },
{ "BRAKE", 23 },
{ "DISTANCE", 24 },
{ "TILT", 25 },
{ "GENERIC_1", 32 },
{ "GENERIC_2", 33 },
{ "GENERIC_3", 34 },
{ "GENERIC_4", 35 },
{ "GENERIC_5", 36 },
{ "GENERIC_6", 37 },
{ "GENERIC_7", 38 },
{ "GENERIC_8", 39 },
{ "GENERIC_9", 40 },
{ "GENERIC_10", 41 },
{ "GENERIC_11", 42 },
{ "GENERIC_12", 43 },
{ "GENERIC_13", 44 },
{ "GENERIC_14", 45 },
{ "GENERIC_15", 46 },
{ "GENERIC_16", 47 },
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
{ NULL, -1 }
};
#endif // _UI_KEYCODE_LABELS_H

Просмотреть файл

@ -0,0 +1,119 @@
/*
* Copyright (C) 2007 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.
*/
#include "PixelFormat.h"
#include <pixelflinger/format.h>
#include <hardware/hardware.h>
namespace android {
static const int COMPONENT_YUV = 0xFF;
size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
{
size_t size;
if (components == COMPONENT_YUV) {
// YCbCr formats are different.
size = (width * bitsPerPixel)>>3;
} else {
size = width * bytesPerPixel;
}
return size;
}
#ifdef HAVE_ANDROID_OS
ssize_t bytesPerPixel(PixelFormat format)
{
PixelFormatInfo info;
status_t err = getPixelFormatInfo(format, &info);
return (err < 0) ? err : info.bytesPerPixel;
}
ssize_t bitsPerPixel(PixelFormat format)
{
PixelFormatInfo info;
status_t err = getPixelFormatInfo(format, &info);
return (err < 0) ? err : info.bitsPerPixel;
}
status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info)
{
if (format < 0)
return BAD_VALUE;
if (info->version != sizeof(PixelFormatInfo))
return INVALID_OPERATION;
// YUV format from the HAL are handled here
switch (format) {
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCbCr_422_I:
info->bitsPerPixel = 16;
goto done;
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
case HAL_PIXEL_FORMAT_YV12:
info->bitsPerPixel = 12;
done:
info->format = format;
info->components = COMPONENT_YUV;
info->bytesPerPixel = 1;
info->h_alpha = 0;
info->l_alpha = 0;
info->h_red = info->h_green = info->h_blue = 8;
info->l_red = info->l_green = info->l_blue = 0;
return NO_ERROR;
}
size_t numEntries;
const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format;
bool valid = uint32_t(format) < numEntries;
if (!valid) {
return BAD_INDEX;
}
#define COMPONENT(name) \
case GGL_##name: info->components = PixelFormatInfo::name; break;
switch (i->components) {
COMPONENT(ALPHA)
COMPONENT(RGB)
COMPONENT(RGBA)
COMPONENT(LUMINANCE)
COMPONENT(LUMINANCE_ALPHA)
default:
return BAD_INDEX;
}
#undef COMPONENT
info->format = format;
info->bytesPerPixel = i->size;
info->bitsPerPixel = i->bitsPerPixel;
info->h_alpha = i->ah;
info->l_alpha = i->al;
info->h_red = i->rh;
info->l_red = i->rl;
info->h_green = i->gh;
info->l_green = i->gl;
info->h_blue = i->bh;
info->l_blue = i->bl;
return NO_ERROR;
}
#endif // HAVE_ANDROID_OS
}; // namespace android

Просмотреть файл

@ -0,0 +1,139 @@
/*
* Copyright (C) 2005 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.
*/
//
// Pixel formats used across the system.
// These formats might not all be supported by all renderers, for instance
// skia or SurfaceFlinger are not required to support all of these formats
// (either as source or destination)
// XXX: we should consolidate these formats and skia's
#ifndef UI_PIXELFORMAT_H
#define UI_PIXELFORMAT_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <pixelflinger/format.h>
#include <hardware/hardware.h>
namespace android {
enum {
//
// these constants need to match those
// in graphics/PixelFormat.java & pixelflinger/format.h
//
PIXEL_FORMAT_UNKNOWN = 0,
PIXEL_FORMAT_NONE = 0,
// logical pixel formats used by the SurfaceFlinger -----------------------
PIXEL_FORMAT_CUSTOM = -4,
// Custom pixel-format described by a PixelFormatInfo structure
PIXEL_FORMAT_TRANSLUCENT = -3,
// System chooses a format that supports translucency (many alpha bits)
PIXEL_FORMAT_TRANSPARENT = -2,
// System chooses a format that supports transparency
// (at least 1 alpha bit)
PIXEL_FORMAT_OPAQUE = -1,
// System chooses an opaque format (no alpha bits required)
// real pixel formats supported for rendering -----------------------------
PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
PIXEL_FORMAT_RGBX_8888 = HAL_PIXEL_FORMAT_RGBX_8888, // 4x8-bit RGB0
PIXEL_FORMAT_RGB_888 = HAL_PIXEL_FORMAT_RGB_888, // 3x8-bit RGB
PIXEL_FORMAT_RGB_565 = HAL_PIXEL_FORMAT_RGB_565, // 16-bit RGB
PIXEL_FORMAT_BGRA_8888 = HAL_PIXEL_FORMAT_BGRA_8888, // 4x8-bit BGRA
PIXEL_FORMAT_RGBA_5551 = HAL_PIXEL_FORMAT_RGBA_5551, // 16-bit ARGB
PIXEL_FORMAT_RGBA_4444 = HAL_PIXEL_FORMAT_RGBA_4444, // 16-bit ARGB
PIXEL_FORMAT_A_8 = GGL_PIXEL_FORMAT_A_8, // 8-bit A
PIXEL_FORMAT_L_8 = GGL_PIXEL_FORMAT_L_8, // 8-bit L (R=G=B=L)
PIXEL_FORMAT_LA_88 = GGL_PIXEL_FORMAT_LA_88, // 16-bit LA
PIXEL_FORMAT_RGB_332 = GGL_PIXEL_FORMAT_RGB_332, // 8-bit RGB
// New formats can be added if they're also defined in
// pixelflinger/format.h
};
typedef int32_t PixelFormat;
struct PixelFormatInfo
{
enum {
INDEX_ALPHA = 0,
INDEX_RED = 1,
INDEX_GREEN = 2,
INDEX_BLUE = 3
};
enum { // components
ALPHA = 1,
RGB = 2,
RGBA = 3,
LUMINANCE = 4,
LUMINANCE_ALPHA = 5,
OTHER = 0xFF
};
struct szinfo {
uint8_t h;
uint8_t l;
};
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
size_t getScanlineSize(unsigned int width) const;
size_t getSize(size_t ci) const {
return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
}
size_t version;
PixelFormat format;
size_t bytesPerPixel;
size_t bitsPerPixel;
union {
szinfo cinfo[4];
struct {
uint8_t h_alpha;
uint8_t l_alpha;
uint8_t h_red;
uint8_t l_red;
uint8_t h_green;
uint8_t l_green;
uint8_t h_blue;
uint8_t l_blue;
};
};
uint8_t components;
uint8_t reserved0[3];
uint32_t reserved1;
};
#ifdef HAVE_ANDROID_OS
// Consider caching the results of these functions are they're not
// guaranteed to be fast.
ssize_t bytesPerPixel(PixelFormat format);
ssize_t bitsPerPixel(PixelFormat format);
status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info);
#endif
}; // namespace android
#endif // UI_PIXELFORMAT_H

Просмотреть файл

@ -0,0 +1,601 @@
/*
* 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.
*/
#define LOG_TAG "PointerController"
//#define LOG_NDEBUG 0
// Log debug messages about pointer updates
#define DEBUG_POINTER_UPDATES 0
#include "PointerController.h"
#include <cutils/log.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkColor.h>
#include <SkPaint.h>
#include <SkXfermode.h>
namespace android {
// --- PointerController ---
// Time to wait before starting the fade when the pointer is inactive.
static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
// Time to wait between animation frames.
static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60;
// Time to spend fading out the spot completely.
static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
// Time to spend fading out the pointer completely.
static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
// --- PointerController ---
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
mHandler = new WeakMessageHandler(this);
AutoMutex _l(mLock);
mLocked.animationPending = false;
mLocked.displayWidth = -1;
mLocked.displayHeight = -1;
mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
mLocked.presentation = PRESENTATION_POINTER;
mLocked.presentationChanged = false;
mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
mLocked.pointerFadeDirection = 0;
mLocked.pointerX = 0;
mLocked.pointerY = 0;
mLocked.pointerAlpha = 0.0f; // pointer is initially faded
mLocked.pointerSprite = mSpriteController->createSprite();
mLocked.pointerIconChanged = false;
mLocked.buttonState = 0;
loadResources();
}
PointerController::~PointerController() {
mLooper->removeMessages(mHandler);
AutoMutex _l(mLock);
mLocked.pointerSprite.clear();
for (size_t i = 0; i < mLocked.spots.size(); i++) {
delete mLocked.spots.itemAt(i);
}
mLocked.spots.clear();
mLocked.recycledSprites.clear();
}
bool PointerController::getBounds(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const {
AutoMutex _l(mLock);
return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
}
bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const {
if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
return false;
}
*outMinX = 0;
*outMinY = 0;
switch (mLocked.displayOrientation) {
case DISPLAY_ORIENTATION_90:
case DISPLAY_ORIENTATION_270:
*outMaxX = mLocked.displayHeight - 1;
*outMaxY = mLocked.displayWidth - 1;
break;
default:
*outMaxX = mLocked.displayWidth - 1;
*outMaxY = mLocked.displayHeight - 1;
break;
}
return true;
}
void PointerController::move(float deltaX, float deltaY) {
#if DEBUG_POINTER_UPDATES
ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
#endif
if (deltaX == 0.0f && deltaY == 0.0f) {
return;
}
AutoMutex _l(mLock);
setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
}
void PointerController::setButtonState(int32_t buttonState) {
#if DEBUG_POINTER_UPDATES
ALOGD("Set button state 0x%08x", buttonState);
#endif
AutoMutex _l(mLock);
if (mLocked.buttonState != buttonState) {
mLocked.buttonState = buttonState;
}
}
int32_t PointerController::getButtonState() const {
AutoMutex _l(mLock);
return mLocked.buttonState;
}
void PointerController::setPosition(float x, float y) {
#if DEBUG_POINTER_UPDATES
ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
#endif
AutoMutex _l(mLock);
setPositionLocked(x, y);
}
void PointerController::setPositionLocked(float x, float y) {
float minX, minY, maxX, maxY;
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
if (x <= minX) {
mLocked.pointerX = minX;
} else if (x >= maxX) {
mLocked.pointerX = maxX;
} else {
mLocked.pointerX = x;
}
if (y <= minY) {
mLocked.pointerY = minY;
} else if (y >= maxY) {
mLocked.pointerY = maxY;
} else {
mLocked.pointerY = y;
}
updatePointerLocked();
}
}
void PointerController::getPosition(float* outX, float* outY) const {
AutoMutex _l(mLock);
*outX = mLocked.pointerX;
*outY = mLocked.pointerY;
}
void PointerController::fade(Transition transition) {
AutoMutex _l(mLock);
// Remove the inactivity timeout, since we are fading now.
removeInactivityTimeoutLocked();
// Start fading.
if (transition == TRANSITION_IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
mLocked.pointerAlpha = 0.0f;
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = -1;
startAnimationLocked();
}
}
void PointerController::unfade(Transition transition) {
AutoMutex _l(mLock);
// Always reset the inactivity timer.
resetInactivityTimeoutLocked();
// Start unfading.
if (transition == TRANSITION_IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
mLocked.pointerAlpha = 1.0f;
updatePointerLocked();
} else {
mLocked.pointerFadeDirection = 1;
startAnimationLocked();
}
}
void PointerController::setPresentation(Presentation presentation) {
AutoMutex _l(mLock);
if (mLocked.presentation != presentation) {
mLocked.presentation = presentation;
mLocked.presentationChanged = true;
if (presentation != PRESENTATION_SPOT) {
fadeOutAndReleaseAllSpotsLocked();
}
updatePointerLocked();
}
}
void PointerController::setSpots(const PointerCoords* spotCoords,
const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
#if DEBUG_POINTER_UPDATES
ALOGD("setSpots: idBits=%08x", spotIdBits.value);
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.firstMarkedBit();
idBits.clearBit(id);
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
c.getAxisValue(AMOTION_EVENT_AXIS_X),
c.getAxisValue(AMOTION_EVENT_AXIS_Y),
c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
}
#endif
AutoMutex _l(mLock);
mSpriteController->openTransaction();
// Add or move spots for fingers that are down.
for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
uint32_t id = idBits.clearFirstMarkedBit();
const PointerCoords& c = spotCoords[spotIdToIndex[id]];
const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
? mResources.spotTouch : mResources.spotHover;
float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
Spot* spot = getSpotLocked(id);
if (!spot) {
spot = createAndAddSpotLocked(id);
}
spot->updateSprite(&icon, x, y);
}
// Remove spots for fingers that went up.
for (size_t i = 0; i < mLocked.spots.size(); i++) {
Spot* spot = mLocked.spots.itemAt(i);
if (spot->id != Spot::INVALID_ID
&& !spotIdBits.hasBit(spot->id)) {
fadeOutAndReleaseSpotLocked(spot);
}
}
mSpriteController->closeTransaction();
}
void PointerController::clearSpots() {
#if DEBUG_POINTER_UPDATES
ALOGD("clearSpots");
#endif
AutoMutex _l(mLock);
fadeOutAndReleaseAllSpotsLocked();
}
void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
AutoMutex _l(mLock);
if (mLocked.inactivityTimeout != inactivityTimeout) {
mLocked.inactivityTimeout = inactivityTimeout;
resetInactivityTimeoutLocked();
}
}
void PointerController::setDisplaySize(int32_t width, int32_t height) {
AutoMutex _l(mLock);
if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
mLocked.displayWidth = width;
mLocked.displayHeight = height;
float minX, minY, maxX, maxY;
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
mLocked.pointerX = (minX + maxX) * 0.5f;
mLocked.pointerY = (minY + maxY) * 0.5f;
} else {
mLocked.pointerX = 0;
mLocked.pointerY = 0;
}
fadeOutAndReleaseAllSpotsLocked();
updatePointerLocked();
}
}
void PointerController::setDisplayOrientation(int32_t orientation) {
AutoMutex _l(mLock);
if (mLocked.displayOrientation != orientation) {
// Apply offsets to convert from the pixel top-left corner position to the pixel center.
// This creates an invariant frame of reference that we can easily rotate when
// taking into account that the pointer may be located at fractional pixel offsets.
float x = mLocked.pointerX + 0.5f;
float y = mLocked.pointerY + 0.5f;
float temp;
// Undo the previous rotation.
switch (mLocked.displayOrientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
x = mLocked.displayWidth - y;
y = temp;
break;
case DISPLAY_ORIENTATION_180:
x = mLocked.displayWidth - x;
y = mLocked.displayHeight - y;
break;
case DISPLAY_ORIENTATION_270:
temp = x;
x = y;
y = mLocked.displayHeight - temp;
break;
}
// Perform the new rotation.
switch (orientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
x = y;
y = mLocked.displayWidth - temp;
break;
case DISPLAY_ORIENTATION_180:
x = mLocked.displayWidth - x;
y = mLocked.displayHeight - y;
break;
case DISPLAY_ORIENTATION_270:
temp = x;
x = mLocked.displayHeight - y;
y = temp;
break;
}
// Apply offsets to convert from the pixel center to the pixel top-left corner position
// and save the results.
mLocked.pointerX = x - 0.5f;
mLocked.pointerY = y - 0.5f;
mLocked.displayOrientation = orientation;
updatePointerLocked();
}
}
void PointerController::setPointerIcon(const SpriteIcon& icon) {
AutoMutex _l(mLock);
mLocked.pointerIcon = icon.copy();
mLocked.pointerIconChanged = true;
updatePointerLocked();
}
void PointerController::handleMessage(const Message& message) {
switch (message.what) {
case MSG_ANIMATE:
doAnimate();
break;
case MSG_INACTIVITY_TIMEOUT:
doInactivityTimeout();
break;
}
}
void PointerController::doAnimate() {
AutoMutex _l(mLock);
bool keepAnimating = false;
mLocked.animationPending = false;
nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;
// Animate pointer fade.
if (mLocked.pointerFadeDirection < 0) {
mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
if (mLocked.pointerAlpha <= 0.0f) {
mLocked.pointerAlpha = 0.0f;
mLocked.pointerFadeDirection = 0;
} else {
keepAnimating = true;
}
updatePointerLocked();
} else if (mLocked.pointerFadeDirection > 0) {
mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
if (mLocked.pointerAlpha >= 1.0f) {
mLocked.pointerAlpha = 1.0f;
mLocked.pointerFadeDirection = 0;
} else {
keepAnimating = true;
}
updatePointerLocked();
}
// Animate spots that are fading out and being removed.
for (size_t i = 0; i < mLocked.spots.size(); i++) {
Spot* spot = mLocked.spots.itemAt(i);
if (spot->id == Spot::INVALID_ID) {
spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
if (spot->alpha <= 0) {
mLocked.spots.removeAt(i--);
releaseSpotLocked(spot);
} else {
spot->sprite->setAlpha(spot->alpha);
keepAnimating = true;
}
}
}
if (keepAnimating) {
startAnimationLocked();
}
}
void PointerController::doInactivityTimeout() {
fade(TRANSITION_GRADUAL);
}
void PointerController::startAnimationLocked() {
if (!mLocked.animationPending) {
mLocked.animationPending = true;
mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE));
}
}
void PointerController::resetInactivityTimeoutLocked() {
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
}
void PointerController::removeInactivityTimeoutLocked() {
mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
}
void PointerController::updatePointerLocked() {
mSpriteController->openTransaction();
mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
if (mLocked.pointerAlpha > 0) {
mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
mLocked.pointerSprite->setVisible(true);
} else {
mLocked.pointerSprite->setVisible(false);
}
if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER
? mLocked.pointerIcon : mResources.spotAnchor);
mLocked.pointerIconChanged = false;
mLocked.presentationChanged = false;
}
mSpriteController->closeTransaction();
}
PointerController::Spot* PointerController::getSpotLocked(uint32_t id) {
for (size_t i = 0; i < mLocked.spots.size(); i++) {
Spot* spot = mLocked.spots.itemAt(i);
if (spot->id == id) {
return spot;
}
}
return NULL;
}
PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) {
// Remove spots until we have fewer than MAX_SPOTS remaining.
while (mLocked.spots.size() >= MAX_SPOTS) {
Spot* spot = removeFirstFadingSpotLocked();
if (!spot) {
spot = mLocked.spots.itemAt(0);
mLocked.spots.removeAt(0);
}
releaseSpotLocked(spot);
}
// Obtain a sprite from the recycled pool.
sp<Sprite> sprite;
if (! mLocked.recycledSprites.isEmpty()) {
sprite = mLocked.recycledSprites.top();
mLocked.recycledSprites.pop();
} else {
sprite = mSpriteController->createSprite();
}
// Return the new spot.
Spot* spot = new Spot(id, sprite);
mLocked.spots.push(spot);
return spot;
}
PointerController::Spot* PointerController::removeFirstFadingSpotLocked() {
for (size_t i = 0; i < mLocked.spots.size(); i++) {
Spot* spot = mLocked.spots.itemAt(i);
if (spot->id == Spot::INVALID_ID) {
mLocked.spots.removeAt(i);
return spot;
}
}
return NULL;
}
void PointerController::releaseSpotLocked(Spot* spot) {
spot->sprite->clearIcon();
if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
mLocked.recycledSprites.push(spot->sprite);
}
delete spot;
}
void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
if (spot->id != Spot::INVALID_ID) {
spot->id = Spot::INVALID_ID;
startAnimationLocked();
}
}
void PointerController::fadeOutAndReleaseAllSpotsLocked() {
for (size_t i = 0; i < mLocked.spots.size(); i++) {
Spot* spot = mLocked.spots.itemAt(i);
fadeOutAndReleaseSpotLocked(spot);
}
}
void PointerController::loadResources() {
mPolicy->loadPointerResources(&mResources);
}
// --- PointerController::Spot ---
void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) {
sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
sprite->setAlpha(alpha);
sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
sprite->setPosition(x, y);
this->x = x;
this->y = y;
if (icon != lastIcon) {
lastIcon = icon;
if (icon) {
sprite->setIcon(*icon);
sprite->setVisible(true);
} else {
sprite->setVisible(false);
}
}
}
} // namespace android

Просмотреть файл

@ -0,0 +1,266 @@
/*
* 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_POINTER_CONTROLLER_H
#define _UI_POINTER_CONTROLLER_H
#include "SpriteController.h"
#include "DisplayInfo.h"
#include "Input.h"
#include <utils/RefBase.h>
#include <utils/Looper.h>
#include <utils/String8.h>
#include <SkBitmap.h>
namespace android {
/**
* Interface for tracking a mouse / touch pad pointer and touch pad spots.
*
* The spots are sprites on screen that visually represent the positions of
* fingers
*
* The pointer controller is responsible for providing synchronization and for tracking
* display orientation changes if needed.
*/
class PointerControllerInterface : public virtual RefBase {
protected:
PointerControllerInterface() { }
virtual ~PointerControllerInterface() { }
public:
/* Gets the bounds of the region that the pointer can traverse.
* Returns true if the bounds are available. */
virtual bool getBounds(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const = 0;
/* Move the pointer. */
virtual void move(float deltaX, float deltaY) = 0;
/* Sets a mask that indicates which buttons are pressed. */
virtual void setButtonState(int32_t buttonState) = 0;
/* Gets a mask that indicates which buttons are pressed. */
virtual int32_t getButtonState() const = 0;
/* Sets the absolute location of the pointer. */
virtual void setPosition(float x, float y) = 0;
/* Gets the absolute location of the pointer. */
virtual void getPosition(float* outX, float* outY) const = 0;
enum Transition {
// Fade/unfade immediately.
TRANSITION_IMMEDIATE,
// Fade/unfade gradually.
TRANSITION_GRADUAL,
};
/* Fades the pointer out now. */
virtual void fade(Transition transition) = 0;
/* Makes the pointer visible if it has faded out.
* The pointer never unfades itself automatically. This method must be called
* by the client whenever the pointer is moved or a button is pressed and it
* wants to ensure that the pointer becomes visible again. */
virtual void unfade(Transition transition) = 0;
enum Presentation {
// Show the mouse pointer.
PRESENTATION_POINTER,
// Show spots and a spot anchor in place of the mouse pointer.
PRESENTATION_SPOT,
};
/* Sets the mode of the pointer controller. */
virtual void setPresentation(Presentation presentation) = 0;
/* Sets the spots for the current gesture.
* The spots are not subject to the inactivity timeout like the pointer
* itself it since they are expected to remain visible for so long as
* the fingers are on the touch pad.
*
* The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant.
* For spotCoords, pressure != 0 indicates that the spot's location is being
* pressed (not hovering).
*/
virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
BitSet32 spotIdBits) = 0;
/* Removes all spots. */
virtual void clearSpots() = 0;
};
/*
* Pointer resources.
*/
struct PointerResources {
SpriteIcon spotHover;
SpriteIcon spotTouch;
SpriteIcon spotAnchor;
};
/*
* Pointer controller policy interface.
*
* The pointer controller policy is used by the pointer controller 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 PointerControllerPolicyInterface : public virtual RefBase {
protected:
PointerControllerPolicyInterface() { }
virtual ~PointerControllerPolicyInterface() { }
public:
virtual void loadPointerResources(PointerResources* outResources) = 0;
};
/*
* Tracks pointer movements and draws the pointer sprite to a surface.
*
* Handles pointer acceleration and animation.
*/
class PointerController : public PointerControllerInterface, public MessageHandler {
protected:
virtual ~PointerController();
public:
enum InactivityTimeout {
INACTIVITY_TIMEOUT_NORMAL = 0,
INACTIVITY_TIMEOUT_SHORT = 1,
};
PointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper, const sp<SpriteController>& spriteController);
virtual bool getBounds(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const;
virtual void move(float deltaX, float deltaY);
virtual void setButtonState(int32_t buttonState);
virtual int32_t getButtonState() const;
virtual void setPosition(float x, float y);
virtual void getPosition(float* outX, float* outY) const;
virtual void fade(Transition transition);
virtual void unfade(Transition transition);
virtual void setPresentation(Presentation presentation);
virtual void setSpots(const PointerCoords* spotCoords,
const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
virtual void clearSpots();
void setDisplaySize(int32_t width, int32_t height);
void setDisplayOrientation(int32_t orientation);
void setPointerIcon(const SpriteIcon& icon);
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
private:
static const size_t MAX_RECYCLED_SPRITES = 12;
static const size_t MAX_SPOTS = 12;
enum {
MSG_ANIMATE,
MSG_INACTIVITY_TIMEOUT,
};
struct Spot {
static const uint32_t INVALID_ID = 0xffffffff;
uint32_t id;
sp<Sprite> sprite;
float alpha;
float scale;
float x, y;
inline Spot(uint32_t id, const sp<Sprite>& sprite)
: id(id), sprite(sprite), alpha(1.0f), scale(1.0f),
x(0.0f), y(0.0f), lastIcon(NULL) { }
void updateSprite(const SpriteIcon* icon, float x, float y);
private:
const SpriteIcon* lastIcon;
};
mutable Mutex mLock;
sp<PointerControllerPolicyInterface> mPolicy;
sp<Looper> mLooper;
sp<SpriteController> mSpriteController;
sp<WeakMessageHandler> mHandler;
PointerResources mResources;
struct Locked {
bool animationPending;
nsecs_t animationTime;
int32_t displayWidth;
int32_t displayHeight;
int32_t displayOrientation;
InactivityTimeout inactivityTimeout;
Presentation presentation;
bool presentationChanged;
int32_t pointerFadeDirection;
float pointerX;
float pointerY;
float pointerAlpha;
sp<Sprite> pointerSprite;
SpriteIcon pointerIcon;
bool pointerIconChanged;
int32_t buttonState;
Vector<Spot*> spots;
Vector<sp<Sprite> > recycledSprites;
} mLocked;
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
void setPositionLocked(float x, float y);
void handleMessage(const Message& message);
void doAnimate();
void doInactivityTimeout();
void startAnimationLocked();
void resetInactivityTimeoutLocked();
void removeInactivityTimeoutLocked();
void updatePointerLocked();
Spot* getSpotLocked(uint32_t id);
Spot* createAndAddSpotLocked(uint32_t id);
Spot* removeFirstFadingSpotLocked();
void releaseSpotLocked(Spot* spot);
void fadeOutAndReleaseSpotLocked(Spot* spot);
void fadeOutAndReleaseAllSpotsLocked();
void loadResources();
};
} // namespace android
#endif // _UI_POINTER_CONTROLLER_H

Просмотреть файл

@ -0,0 +1,481 @@
/*
* Copyright (C) 2011 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.
*/
#define LOG_TAG "Sprites"
//#define LOG_NDEBUG 0
#include "SpriteController.h"
#include <cutils/log.h>
#include <utils/String8.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
#include <SkColor.h>
#include <SkPaint.h>
#include <SkXfermode.h>
namespace android {
// --- SpriteController ---
SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) :
mLooper(looper), mOverlayLayer(overlayLayer) {
mHandler = new WeakMessageHandler(this);
mLocked.transactionNestingCount = 0;
mLocked.deferredSpriteUpdate = false;
}
SpriteController::~SpriteController() {
mLooper->removeMessages(mHandler);
if (mSurfaceComposerClient != NULL) {
mSurfaceComposerClient->dispose();
mSurfaceComposerClient.clear();
}
}
sp<Sprite> SpriteController::createSprite() {
return new SpriteImpl(this);
}
void SpriteController::openTransaction() {
AutoMutex _l(mLock);
mLocked.transactionNestingCount += 1;
}
void SpriteController::closeTransaction() {
AutoMutex _l(mLock);
LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0,
"Sprite closeTransaction() called but there is no open sprite transaction");
mLocked.transactionNestingCount -= 1;
if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
mLocked.deferredSpriteUpdate = false;
mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
}
}
void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
mLocked.invalidatedSprites.push(sprite);
if (wasEmpty) {
if (mLocked.transactionNestingCount != 0) {
mLocked.deferredSpriteUpdate = true;
} else {
mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
}
}
}
void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
mLocked.disposedSurfaces.push(surfaceControl);
if (wasEmpty) {
mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
}
}
void SpriteController::handleMessage(const Message& message) {
switch (message.what) {
case MSG_UPDATE_SPRITES:
doUpdateSprites();
break;
case MSG_DISPOSE_SURFACES:
doDisposeSurfaces();
break;
}
}
void SpriteController::doUpdateSprites() {
// Collect information about sprite updates.
// Each sprite update record includes a reference to its associated sprite so we can
// be certain the sprites will not be deleted while this function runs. Sprites
// may invalidate themselves again during this time but we will handle those changes
// in the next iteration.
Vector<SpriteUpdate> updates;
size_t numSprites;
{ // acquire lock
AutoMutex _l(mLock);
numSprites = mLocked.invalidatedSprites.size();
for (size_t i = 0; i < numSprites; i++) {
const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
sprite->resetDirtyLocked();
}
mLocked.invalidatedSprites.clear();
} // release lock
// Create missing surfaces.
bool surfaceChanged = false;
for (size_t i = 0; i < numSprites; i++) {
SpriteUpdate& update = updates.editItemAt(i);
if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
update.state.surfaceWidth = update.state.icon.bitmap.width();
update.state.surfaceHeight = update.state.icon.bitmap.height();
update.state.surfaceDrawn = false;
update.state.surfaceVisible = false;
update.state.surfaceControl = obtainSurface(
update.state.surfaceWidth, update.state.surfaceHeight);
if (update.state.surfaceControl != NULL) {
update.surfaceChanged = surfaceChanged = true;
}
}
}
// Resize sprites if needed, inside a global transaction.
bool haveGlobalTransaction = false;
for (size_t i = 0; i < numSprites; i++) {
SpriteUpdate& update = updates.editItemAt(i);
if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
int32_t desiredWidth = update.state.icon.bitmap.width();
int32_t desiredHeight = update.state.icon.bitmap.height();
if (update.state.surfaceWidth < desiredWidth
|| update.state.surfaceHeight < desiredHeight) {
if (!haveGlobalTransaction) {
SurfaceComposerClient::openGlobalTransaction();
haveGlobalTransaction = true;
}
status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);
if (status) {
ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d",
status, update.state.surfaceWidth, update.state.surfaceHeight,
desiredWidth, desiredHeight);
} else {
update.state.surfaceWidth = desiredWidth;
update.state.surfaceHeight = desiredHeight;
update.state.surfaceDrawn = false;
update.surfaceChanged = surfaceChanged = true;
if (update.state.surfaceVisible) {
status = update.state.surfaceControl->hide();
if (status) {
ALOGE("Error %d hiding sprite surface after resize.", status);
} else {
update.state.surfaceVisible = false;
}
}
}
}
}
}
if (haveGlobalTransaction) {
SurfaceComposerClient::closeGlobalTransaction();
}
// Redraw sprites if needed.
for (size_t i = 0; i < numSprites; i++) {
SpriteUpdate& update = updates.editItemAt(i);
if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
update.state.surfaceDrawn = false;
update.surfaceChanged = surfaceChanged = true;
}
if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
&& update.state.wantSurfaceVisible()) {
sp<Surface> surface = update.state.surfaceControl->getSurface();
Surface::SurfaceInfo surfaceInfo;
status_t status = surface->lock(&surfaceInfo);
if (status) {
ALOGE("Error %d locking sprite surface before drawing.", status);
} else {
SkBitmap surfaceBitmap;
ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format);
surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
surfaceInfo.w, surfaceInfo.h, bpr);
surfaceBitmap.setPixels(surfaceInfo.bits);
SkCanvas surfaceCanvas;
surfaceCanvas.setBitmapDevice(surfaceBitmap);
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
if (surfaceInfo.w > uint32_t(update.state.icon.bitmap.width())) {
paint.setColor(0); // transparent fill color
surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0,
surfaceInfo.w, update.state.icon.bitmap.height(), paint);
}
if (surfaceInfo.h > uint32_t(update.state.icon.bitmap.height())) {
paint.setColor(0); // transparent fill color
surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(),
surfaceInfo.w, surfaceInfo.h, paint);
}
status = surface->unlockAndPost();
if (status) {
ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
} else {
update.state.surfaceDrawn = true;
update.surfaceChanged = surfaceChanged = true;
}
}
}
}
// Set sprite surface properties and make them visible.
bool haveTransaction = false;
for (size_t i = 0; i < numSprites; i++) {
SpriteUpdate& update = updates.editItemAt(i);
bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
&& update.state.surfaceDrawn;
bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
|| (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
| DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
| DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
status_t status;
if (!haveTransaction) {
SurfaceComposerClient::openGlobalTransaction();
haveTransaction = true;
}
if (wantSurfaceVisibleAndDrawn
&& (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
status = update.state.surfaceControl->setAlpha(update.state.alpha);
if (status) {
ALOGE("Error %d setting sprite surface alpha.", status);
}
}
if (wantSurfaceVisibleAndDrawn
&& (becomingVisible || (update.state.dirty & (DIRTY_POSITION
| DIRTY_HOTSPOT)))) {
status = update.state.surfaceControl->setPosition(
update.state.positionX - update.state.icon.hotSpotX,
update.state.positionY - update.state.icon.hotSpotY);
if (status) {
ALOGE("Error %d setting sprite surface position.", status);
}
}
if (wantSurfaceVisibleAndDrawn
&& (becomingVisible
|| (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
status = update.state.surfaceControl->setMatrix(
update.state.transformationMatrix.dsdx,
update.state.transformationMatrix.dtdx,
update.state.transformationMatrix.dsdy,
update.state.transformationMatrix.dtdy);
if (status) {
ALOGE("Error %d setting sprite surface transformation matrix.", status);
}
}
int32_t surfaceLayer = mOverlayLayer + update.state.layer;
if (wantSurfaceVisibleAndDrawn
&& (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
status = update.state.surfaceControl->setLayer(surfaceLayer);
if (status) {
ALOGE("Error %d setting sprite surface layer.", status);
}
}
if (becomingVisible) {
status = update.state.surfaceControl->show(surfaceLayer);
if (status) {
ALOGE("Error %d showing sprite surface.", status);
} else {
update.state.surfaceVisible = true;
update.surfaceChanged = surfaceChanged = true;
}
} else if (becomingHidden) {
status = update.state.surfaceControl->hide();
if (status) {
ALOGE("Error %d hiding sprite surface.", status);
} else {
update.state.surfaceVisible = false;
update.surfaceChanged = surfaceChanged = true;
}
}
}
}
if (haveTransaction) {
SurfaceComposerClient::closeGlobalTransaction();
}
// If any surfaces were changed, write back the new surface properties to the sprites.
if (surfaceChanged) { // acquire lock
AutoMutex _l(mLock);
for (size_t i = 0; i < numSprites; i++) {
const SpriteUpdate& update = updates.itemAt(i);
if (update.surfaceChanged) {
update.sprite->setSurfaceLocked(update.state.surfaceControl,
update.state.surfaceWidth, update.state.surfaceHeight,
update.state.surfaceDrawn, update.state.surfaceVisible);
}
}
} // release lock
// Clear the sprite update vector outside the lock. It is very important that
// we do not clear sprite references inside the lock since we could be releasing
// the last remaining reference to the sprite here which would result in the
// sprite being deleted and the lock being reacquired by the sprite destructor
// while already held.
updates.clear();
}
void SpriteController::doDisposeSurfaces() {
// Collect disposed surfaces.
Vector<sp<SurfaceControl> > disposedSurfaces;
{ // acquire lock
AutoMutex _l(mLock);
disposedSurfaces = mLocked.disposedSurfaces;
mLocked.disposedSurfaces.clear();
} // release lock
// Release the last reference to each surface outside of the lock.
// We don't want the surfaces to be deleted while we are holding our lock.
disposedSurfaces.clear();
}
void SpriteController::ensureSurfaceComposerClient() {
if (mSurfaceComposerClient == NULL) {
mSurfaceComposerClient = new SurfaceComposerClient();
}
}
sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
ensureSurfaceComposerClient();
sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888);
if (surfaceControl == NULL || !surfaceControl->isValid()
|| !surfaceControl->getSurface()->isValid()) {
ALOGE("Error creating sprite surface.");
return NULL;
}
return surfaceControl;
}
// --- SpriteController::SpriteImpl ---
SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
mController(controller) {
}
SpriteController::SpriteImpl::~SpriteImpl() {
AutoMutex _m(mController->mLock);
// Let the controller take care of deleting the last reference to sprite
// surfaces so that we do not block the caller on an IPC here.
if (mLocked.state.surfaceControl != NULL) {
mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
mLocked.state.surfaceControl.clear();
}
}
void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
AutoMutex _l(mController->mLock);
uint32_t dirty;
if (icon.isValid()) {
icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config);
if (!mLocked.state.icon.isValid()
|| mLocked.state.icon.hotSpotX != icon.hotSpotX
|| mLocked.state.icon.hotSpotY != icon.hotSpotY) {
mLocked.state.icon.hotSpotX = icon.hotSpotX;
mLocked.state.icon.hotSpotY = icon.hotSpotY;
dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
} else {
dirty = DIRTY_BITMAP;
}
} else if (mLocked.state.icon.isValid()) {
mLocked.state.icon.bitmap.reset();
dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
} else {
return; // setting to invalid icon and already invalid so nothing to do
}
invalidateLocked(dirty);
}
void SpriteController::SpriteImpl::setVisible(bool visible) {
AutoMutex _l(mController->mLock);
if (mLocked.state.visible != visible) {
mLocked.state.visible = visible;
invalidateLocked(DIRTY_VISIBILITY);
}
}
void SpriteController::SpriteImpl::setPosition(float x, float y) {
AutoMutex _l(mController->mLock);
if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
mLocked.state.positionX = x;
mLocked.state.positionY = y;
invalidateLocked(DIRTY_POSITION);
}
}
void SpriteController::SpriteImpl::setLayer(int32_t layer) {
AutoMutex _l(mController->mLock);
if (mLocked.state.layer != layer) {
mLocked.state.layer = layer;
invalidateLocked(DIRTY_LAYER);
}
}
void SpriteController::SpriteImpl::setAlpha(float alpha) {
AutoMutex _l(mController->mLock);
if (mLocked.state.alpha != alpha) {
mLocked.state.alpha = alpha;
invalidateLocked(DIRTY_ALPHA);
}
}
void SpriteController::SpriteImpl::setTransformationMatrix(
const SpriteTransformationMatrix& matrix) {
AutoMutex _l(mController->mLock);
if (mLocked.state.transformationMatrix != matrix) {
mLocked.state.transformationMatrix = matrix;
invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
}
}
void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
bool wasDirty = mLocked.state.dirty;
mLocked.state.dirty |= dirty;
if (!wasDirty) {
mController->invalidateSpriteLocked(this);
}
}
} // namespace android

Просмотреть файл

@ -0,0 +1,295 @@
/*
* Copyright (C) 2011 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_SPRITES_H
#define _UI_SPRITES_H
#include <utils/RefBase.h>
#include <utils/Looper.h>
#include <surfaceflinger/Surface.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <SkBitmap.h>
namespace android {
/*
* Transformation matrix for a sprite.
*/
struct SpriteTransformationMatrix {
inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { }
inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) :
dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { }
float dsdx;
float dtdx;
float dsdy;
float dtdy;
inline bool operator== (const SpriteTransformationMatrix& other) {
return dsdx == other.dsdx
&& dtdx == other.dtdx
&& dsdy == other.dsdy
&& dtdy == other.dtdy;
}
inline bool operator!= (const SpriteTransformationMatrix& other) {
return !(*this == other);
}
};
/*
* Icon that a sprite displays, including its hotspot.
*/
struct SpriteIcon {
inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
SkBitmap bitmap;
float hotSpotX;
float hotSpotY;
inline SpriteIcon copy() const {
SkBitmap bitmapCopy;
bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config);
return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
}
inline void reset() {
bitmap.reset();
hotSpotX = 0;
hotSpotY = 0;
}
inline bool isValid() const {
return !bitmap.isNull() && !bitmap.empty();
}
};
/*
* A sprite is a simple graphical object that is displayed on-screen above other layers.
* The basic sprite class is an interface.
* The implementation is provided by the sprite controller.
*/
class Sprite : public RefBase {
protected:
Sprite() { }
virtual ~Sprite() { }
public:
enum {
// The base layer for pointer sprites.
BASE_LAYER_POINTER = 0, // reserve space for 1 pointer
// The base layer for spot sprites.
BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots
};
/* Sets the bitmap that is drawn by the sprite.
* The sprite retains a copy of the bitmap for subsequent rendering. */
virtual void setIcon(const SpriteIcon& icon) = 0;
inline void clearIcon() {
setIcon(SpriteIcon());
}
/* Sets whether the sprite is visible. */
virtual void setVisible(bool visible) = 0;
/* Sets the sprite position on screen, relative to the sprite's hot spot. */
virtual void setPosition(float x, float y) = 0;
/* Sets the layer of the sprite, relative to the system sprite overlay layer.
* Layer 0 is the overlay layer, > 0 appear above this layer. */
virtual void setLayer(int32_t layer) = 0;
/* Sets the sprite alpha blend ratio between 0.0 and 1.0. */
virtual void setAlpha(float alpha) = 0;
/* Sets the sprite transformation matrix. */
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
};
/*
* Displays sprites on the screen.
*
* This interface is used by PointerController and SpotController to draw pointers or
* spot representations of fingers. It is not intended for general purpose use
* by other components.
*
* All sprite position updates and rendering is performed asynchronously.
*
* Clients are responsible for animating sprites by periodically updating their properties.
*/
class SpriteController : public MessageHandler {
protected:
virtual ~SpriteController();
public:
SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
/* Creates a new sprite, initially invisible. */
sp<Sprite> createSprite();
/* Opens or closes a transaction to perform a batch of sprite updates as part of
* a single operation such as setPosition and setAlpha. It is not necessary to
* open a transaction when updating a single property.
* Calls to openTransaction() nest and must be matched by an equal number
* of calls to closeTransaction(). */
void openTransaction();
void closeTransaction();
private:
enum {
MSG_UPDATE_SPRITES,
MSG_DISPOSE_SURFACES,
};
enum {
DIRTY_BITMAP = 1 << 0,
DIRTY_ALPHA = 1 << 1,
DIRTY_POSITION = 1 << 2,
DIRTY_TRANSFORMATION_MATRIX = 1 << 3,
DIRTY_LAYER = 1 << 4,
DIRTY_VISIBILITY = 1 << 5,
DIRTY_HOTSPOT = 1 << 6,
};
/* Describes the state of a sprite.
* This structure is designed so that it can be copied during updates so that
* surfaces can be resized and redrawn without blocking the client by holding a lock
* on the sprites for a long time.
* Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */
struct SpriteState {
inline SpriteState() :
dirty(0), visible(false),
positionX(0), positionY(0), layer(0), alpha(1.0f),
surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
}
uint32_t dirty;
SpriteIcon icon;
bool visible;
float positionX;
float positionY;
int32_t layer;
float alpha;
SpriteTransformationMatrix transformationMatrix;
sp<SurfaceControl> surfaceControl;
int32_t surfaceWidth;
int32_t surfaceHeight;
bool surfaceDrawn;
bool surfaceVisible;
inline bool wantSurfaceVisible() const {
return visible && alpha > 0.0f && icon.isValid();
}
};
/* Client interface for a sprite.
* Requests acquire a lock on the controller, update local state and request the
* controller to invalidate the sprite.
* The real heavy lifting of creating, resizing and redrawing surfaces happens
* asynchronously with no locks held except in short critical section to copy
* the sprite state before the work and update the sprite surface control afterwards.
*/
class SpriteImpl : public Sprite {
protected:
virtual ~SpriteImpl();
public:
SpriteImpl(const sp<SpriteController> controller);
virtual void setIcon(const SpriteIcon& icon);
virtual void setVisible(bool visible);
virtual void setPosition(float x, float y);
virtual void setLayer(int32_t layer);
virtual void setAlpha(float alpha);
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
inline const SpriteState& getStateLocked() const {
return mLocked.state;
}
inline void resetDirtyLocked() {
mLocked.state.dirty = 0;
}
inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl,
int32_t width, int32_t height, bool drawn, bool visible) {
mLocked.state.surfaceControl = surfaceControl;
mLocked.state.surfaceWidth = width;
mLocked.state.surfaceHeight = height;
mLocked.state.surfaceDrawn = drawn;
mLocked.state.surfaceVisible = visible;
}
private:
sp<SpriteController> mController;
struct Locked {
SpriteState state;
} mLocked; // guarded by mController->mLock
void invalidateLocked(uint32_t dirty);
};
/* Stores temporary information collected during the sprite update cycle. */
struct SpriteUpdate {
inline SpriteUpdate() : surfaceChanged(false) { }
inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) :
sprite(sprite), state(state), surfaceChanged(false) {
}
sp<SpriteImpl> sprite;
SpriteState state;
bool surfaceChanged;
};
mutable Mutex mLock;
sp<Looper> mLooper;
const int32_t mOverlayLayer;
sp<WeakMessageHandler> mHandler;
sp<SurfaceComposerClient> mSurfaceComposerClient;
struct Locked {
Vector<sp<SpriteImpl> > invalidatedSprites;
Vector<sp<SurfaceControl> > disposedSurfaces;
uint32_t transactionNestingCount;
bool deferredSpriteUpdate;
} mLocked; // guarded by mLock
void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
void handleMessage(const Message& message);
void doUpdateSprites();
void doDisposeSurfaces();
void ensureSurfaceComposerClient();
sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
};
} // namespace android
#endif // _UI_SPRITES_H

Просмотреть файл

@ -0,0 +1,171 @@
/*
* 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.
*/
#define LOG_TAG "VirtualKeyMap"
#include <stdlib.h>
#include <string.h>
#include "VirtualKeyMap.h"
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/Tokenizer.h>
#include <utils/Timers.h>
// Enables debug output for the parser.
#define DEBUG_PARSER 0
// Enables debug output for parser performance.
#define DEBUG_PARSER_PERFORMANCE 0
namespace android {
static const char* WHITESPACE = " \t\r";
static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:";
// --- VirtualKeyMap ---
VirtualKeyMap::VirtualKeyMap() {
}
VirtualKeyMap::~VirtualKeyMap() {
}
status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
*outMap = NULL;
Tokenizer* tokenizer;
status_t status = Tokenizer::open(filename, &tokenizer);
if (status) {
ALOGE("Error %d opening virtual key map file %s.", status, filename.string());
} else {
VirtualKeyMap* map = new VirtualKeyMap();
if (!map) {
ALOGE("Error allocating virtual key map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
Parser parser(map, tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (status) {
delete map;
} else {
*outMap = map;
}
}
delete tokenizer;
}
return status;
}
// --- VirtualKeyMap::Parser ---
VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) :
mMap(map), mTokenizer(tokenizer) {
}
VirtualKeyMap::Parser::~Parser() {
}
status_t VirtualKeyMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
// Multiple keys can appear on one line or they can be broken up across multiple lines.
do {
String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
if (token != "0x01") {
ALOGE("%s: Unknown virtual key type, expected 0x01.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
VirtualKeyDefinition defn;
bool success = parseNextIntField(&defn.scanCode)
&& parseNextIntField(&defn.centerX)
&& parseNextIntField(&defn.centerY)
&& parseNextIntField(&defn.width)
&& parseNextIntField(&defn.height);
if (!success) {
ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
#if DEBUG_PARSER
ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, "
"width=%d, height=%d",
defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
#endif
mMap->mVirtualKeys.push(defn);
} while (consumeFieldDelimiterAndSkipWhitespace());
if (!mTokenizer->isEol()) {
ALOGE("%s: Expected end of line, got '%s'.",
mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
return BAD_VALUE;
}
}
mTokenizer->nextLine();
}
return NO_ERROR;
}
bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() {
mTokenizer->skipDelimiters(WHITESPACE);
if (mTokenizer->peekChar() == ':') {
mTokenizer->nextChar();
mTokenizer->skipDelimiters(WHITESPACE);
return true;
}
return false;
}
bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) {
if (!consumeFieldDelimiterAndSkipWhitespace()) {
return false;
}
String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER);
char* end;
*outValue = strtol(token.string(), &end, 0);
if (token.isEmpty() || *end != '\0') {
ALOGE("Expected an integer, got '%s'.", token.string());
return false;
}
return true;
}
} // namespace android

Просмотреть файл

@ -0,0 +1,79 @@
/*
* 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_VIRTUAL_KEY_MAP_H
#define _UI_VIRTUAL_KEY_MAP_H
#include <stdint.h>
#include "Input.h"
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
#include <utils/String8.h>
#include <utils/Unicode.h>
namespace android {
/* 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;
};
/**
* Describes a collection of virtual keys on a touch screen in terms of
* virtual scan codes and hit rectangles.
*/
class VirtualKeyMap {
public:
~VirtualKeyMap();
static status_t load(const String8& filename, VirtualKeyMap** outMap);
inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
return mVirtualKeys;
}
private:
class Parser {
VirtualKeyMap* mMap;
Tokenizer* mTokenizer;
public:
Parser(VirtualKeyMap* map, Tokenizer* tokenizer);
~Parser();
status_t parse();
private:
bool consumeFieldDelimiterAndSkipWhitespace();
bool parseNextIntField(int32_t* outValue);
};
Vector<VirtualKeyDefinition> mVirtualKeys;
VirtualKeyMap();
};
} // namespace android
#endif // _UI_KEY_CHARACTER_MAP_H