diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/camera/CameraParameters.cpp | 9 | ||||
-rw-r--r-- | libs/hwui/Patch.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/SkiaColorFilter.cpp | 5 | ||||
-rw-r--r-- | libs/ui/Android.mk | 1 | ||||
-rw-r--r-- | libs/ui/EventHub.cpp | 598 | ||||
-rw-r--r-- | libs/ui/Input.cpp | 114 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 59 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 249 | ||||
-rw-r--r-- | libs/ui/Keyboard.cpp | 224 | ||||
-rw-r--r-- | libs/ui/VirtualKeyMap.cpp | 171 | ||||
-rw-r--r-- | libs/ui/tests/InputDispatcher_test.cpp | 4 | ||||
-rw-r--r-- | libs/ui/tests/InputReader_test.cpp | 251 | ||||
-rw-r--r-- | libs/utils/Android.mk | 1 | ||||
-rw-r--r-- | libs/utils/FileMap.cpp | 8 | ||||
-rw-r--r-- | libs/utils/PropertyMap.cpp | 212 | ||||
-rw-r--r-- | libs/utils/String8.cpp | 18 | ||||
-rw-r--r-- | libs/utils/Tokenizer.cpp | 45 |
17 files changed, 1342 insertions, 640 deletions
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index 45b1b9a..e9a5f8c 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -75,6 +75,7 @@ const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances"; const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format"; const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size"; const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values"; +const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video"; const char CameraParameters::TRUE[] = "true"; const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity"; @@ -333,6 +334,14 @@ void CameraParameters::getPreviewSize(int *width, int *height) const parse_pair(p, width, height, 'x'); } +void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const +{ + *width = *height = -1; + const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO); + if (p == 0) return; + parse_pair(p, width, height, 'x'); +} + void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const { const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES); diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp index 7ca289d..ebffd34 100644 --- a/libs/hwui/Patch.cpp +++ b/libs/hwui/Patch.cpp @@ -42,6 +42,9 @@ Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQua mXDivs = new int32_t[mXCount]; mYDivs = new int32_t[mYCount]; + PATCH_LOGD(" patch: xCount = %d, yCount = %d, emptyQuads = %d, vertices = %d", + xCount, yCount, emptyQuads, verticesCount); + glGenBuffers(1, &meshBuffer); } @@ -208,7 +211,15 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1, float v1, float u2, float v2, uint32_t& quadCount) { - if (((mColorKey >> quadCount++) & 0x1) == 1) { + uint32_t oldQuadCount = quadCount; + + // Degenerate quads are an artifact of our implementation and should not + // be taken into account when checking for transparent quads + if (x2 - x1 > 0.999f && y2 - y1 > 0.999f) { + quadCount++; + } + + if (((mColorKey >> oldQuadCount) & 0x1) == 1) { return; } diff --git a/libs/hwui/SkiaColorFilter.cpp b/libs/hwui/SkiaColorFilter.cpp index 91b1c32..b86bbc5 100644 --- a/libs/hwui/SkiaColorFilter.cpp +++ b/libs/hwui/SkiaColorFilter.cpp @@ -36,6 +36,11 @@ SkiaColorFilter::~SkiaColorFilter() { SkiaColorMatrixFilter::SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector): SkiaColorFilter(skFilter, kColorMatrix, true), mMatrix(matrix), mVector(vector) { + // Skia uses the range [0..255] for the addition vector, but we need + // the [0..1] range to apply the vector in GLSL + for (int i = 0; i < 4; i++) { + mVector[i] /= 255.0f; + } } SkiaColorMatrixFilter::~SkiaColorMatrixFilter() { diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 5948e04..d0e041a 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -21,6 +21,7 @@ commonSources:= \ Keyboard.cpp \ KeyLayoutMap.cpp \ KeyCharacterMap.cpp \ + VirtualKeyMap.cpp # For the host # ===================================================== diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index f468217..8f4bac6 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -33,6 +33,8 @@ #include <assert.h> #include <ui/KeyLayoutMap.h> +#include <ui/KeyCharacterMap.h> +#include <ui/VirtualKeyMap.h> #include <string.h> #include <stdint.h> @@ -56,10 +58,6 @@ /* this macro computes the number of bytes needed to represent a bit array of the specified size */ #define sizeof_bit_array(bits) ((bits + 7) / 8) -#define ID_MASK 0x0000ffff -#define SEQ_MASK 0x7fff0000 -#define SEQ_SHIFT 16 - #ifndef ABS_MT_TOUCH_MAJOR #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ #endif @@ -72,6 +70,9 @@ #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ #endif +// Fd at index 0 is always reserved for inotify +#define FIRST_ACTUAL_DEVICE_INDEX 1 + #define INDENT " " #define INDENT2 " " #define INDENT3 " " @@ -79,7 +80,7 @@ namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *device_path = "/dev/input"; +static const char *DEVICE_PATH = "/dev/input"; /* return the larger integer */ static inline int max(int v1, int v2) @@ -91,72 +92,89 @@ static inline const char* toString(bool value) { return value ? "true" : "false"; } -EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name) - : id(_id), path(_path), name(name), classes(0) - , keyBitmask(NULL), layoutMap(NULL), fd(-1), next(NULL) { +// --- EventHub::Device --- + +EventHub::Device::Device(int fd, int32_t id, const String8& path, + const InputDeviceIdentifier& identifier) : + next(NULL), + fd(fd), id(id), path(path), identifier(identifier), + classes(0), keyBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) { } -EventHub::device_t::~device_t() { - delete [] keyBitmask; - delete layoutMap; +EventHub::Device::~Device() { + close(); + delete[] keyBitmask; + delete configuration; + delete virtualKeyMap; } -EventHub::EventHub(void) - : mError(NO_INIT), mHaveFirstKeyboard(false), mFirstKeyboardId(-1) - , mDevicesById(0), mNumDevicesById(0) - , mOpeningDevices(0), mClosingDevices(0) - , mDevices(0), mFDs(0), mFDCount(0), mOpened(false), mNeedToSendFinishedDeviceScan(false) - , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0) -{ +void EventHub::Device::close() { + if (fd >= 0) { + ::close(fd); + fd = -1; + } +} + + +// --- EventHub --- + +EventHub::EventHub(void) : + mError(NO_INIT), mBuiltInKeyboardId(-1), mNextDeviceId(1), + mOpeningDevices(0), mClosingDevices(0), + mOpened(false), mNeedToSendFinishedDeviceScan(false), + mInputBufferIndex(0), mInputBufferCount(0), mInputFdIndex(0) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); #ifdef EV_SW memset(mSwitches, 0, sizeof(mSwitches)); #endif } -/* - * Clean up. - */ -EventHub::~EventHub(void) -{ +EventHub::~EventHub(void) { release_wake_lock(WAKE_LOCK_ID); // we should free stuff here... } -status_t EventHub::errorCheck() const -{ +status_t EventHub::errorCheck() const { return mError; } -String8 EventHub::getDeviceName(int32_t deviceId) const -{ +String8 EventHub::getDeviceName(int32_t deviceId) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device == NULL) return String8(); - return device->name; + return device->identifier.name; } -uint32_t EventHub::getDeviceClasses(int32_t deviceId) const -{ +uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device == NULL) return 0; return device->classes; } +void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device && device->configuration) { + *outConfiguration = *device->configuration; + } else { + outConfiguration->clear(); + } +} + status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device == NULL) return -1; struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { LOGW("Error reading absolute controller %d for device %s fd %d\n", - axis, device->name.string(), device->fd); + axis, device->identifier.name.string(), device->fd); return -errno; } @@ -174,7 +192,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { if (scanCode >= 0 && scanCode <= KEY_MAX) { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return getScanCodeStateLocked(device, scanCode); } @@ -182,7 +200,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { return AKEY_STATE_UNKNOWN; } -int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const { +int32_t EventHub::getScanCodeStateLocked(Device* device, int32_t scanCode) const { uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(device->fd, @@ -195,20 +213,20 @@ int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) con int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return getKeyCodeStateLocked(device, keyCode); } return AKEY_STATE_UNKNOWN; } -int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const { - if (!device->layoutMap) { +int32_t EventHub::getKeyCodeStateLocked(Device* device, int32_t keyCode) const { + if (!device->keyMap.haveKeyLayout()) { return AKEY_STATE_UNKNOWN; } Vector<int32_t> scanCodes; - device->layoutMap->findScanCodes(keyCode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodes(keyCode, &scanCodes); uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); @@ -236,7 +254,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { if (sw >= 0 && sw <= SW_MAX) { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return getSwitchStateLocked(device, sw); } @@ -245,7 +263,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { return AKEY_STATE_UNKNOWN; } -int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const { +int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const { uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(device->fd, @@ -259,16 +277,16 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device != NULL) { return markSupportedKeyCodesLocked(device, numCodes, keyCodes, outFlags); } return false; } -bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes, +bool EventHub::markSupportedKeyCodesLocked(Device* device, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { - if (device->layoutMap == NULL || device->keyBitmask == NULL) { + if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { return false; } @@ -276,7 +294,7 @@ bool EventHub::markSupportedKeyCodesLocked(device_t* device, size_t numCodes, for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); - status_t err = device->layoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes); + status_t err = device->keyMap.keyLayoutMap->findScanCodes(keyCodes[codeIndex], &scanCodes); if (! err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver @@ -295,20 +313,20 @@ status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); - if (device != NULL && device->layoutMap != NULL) { - status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); + if (device && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); if (err == NO_ERROR) { return NO_ERROR; } } - if (mHaveFirstKeyboard) { - device = getDeviceLocked(mFirstKeyboardId); + if (mBuiltInKeyboardId != -1) { + device = getDeviceLocked(mBuiltInKeyboardId); - if (device != NULL && device->layoutMap != NULL) { - status_t err = device->layoutMap->map(scancode, outKeycode, outFlags); + if (device && device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->map(scancode, outKeycode, outFlags); if (err == NO_ERROR) { return NO_ERROR; } @@ -330,7 +348,7 @@ void EventHub::addExcludedDevice(const char* deviceName) bool EventHub::hasLed(int32_t deviceId, int32_t led) const { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device) { uint8_t bitmask[sizeof_bit_array(LED_MAX + 1)]; memset(bitmask, 0, sizeof(bitmask)); @@ -345,7 +363,7 @@ bool EventHub::hasLed(int32_t deviceId, int32_t led) const { void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { AutoMutex _l(mLock); - device_t* device = getDeviceLocked(deviceId); + Device* device = getDeviceLocked(deviceId); if (device) { struct input_event ev; ev.time.tv_sec = 0; @@ -361,21 +379,33 @@ void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { } } -EventHub::device_t* EventHub::getDeviceLocked(int32_t deviceId) const -{ - if (deviceId == 0) deviceId = mFirstKeyboardId; - int32_t id = deviceId & ID_MASK; - if (id >= mNumDevicesById || id < 0) return NULL; - device_t* dev = mDevicesById[id].device; - if (dev == NULL) return NULL; - if (dev->id == deviceId) { - return dev; +void EventHub::getVirtualKeyDefinitions(int32_t deviceId, + Vector<VirtualKeyDefinition>& outVirtualKeys) const { + outVirtualKeys.clear(); + + AutoMutex _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device && device->virtualKeyMap) { + outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); + } +} + +EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { + if (deviceId == 0) { + deviceId = mBuiltInKeyboardId; + } + + size_t numDevices = mDevices.size(); + for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < numDevices; i++) { + Device* device = mDevices[i]; + if (device->id == deviceId) { + return device; + } } return NULL; } -bool EventHub::getEvent(RawEvent* outEvent) -{ +bool EventHub::getEvent(RawEvent* outEvent) { outEvent->deviceId = 0; outEvent->type = 0; outEvent->scanCode = 0; @@ -396,11 +426,11 @@ bool EventHub::getEvent(RawEvent* outEvent) for (;;) { // Report any devices that had last been added/removed. if (mClosingDevices != NULL) { - device_t* device = mClosingDevices; - LOGV("Reporting device closed: id=0x%x, name=%s\n", + Device* device = mClosingDevices; + LOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.string()); mClosingDevices = device->next; - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { outEvent->deviceId = 0; } else { outEvent->deviceId = device->id; @@ -413,11 +443,11 @@ bool EventHub::getEvent(RawEvent* outEvent) } if (mOpeningDevices != NULL) { - device_t* device = mOpeningDevices; - LOGV("Reporting device opened: id=0x%x, name=%s\n", + Device* device = mOpeningDevices; + LOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.string()); mOpeningDevices = device->next; - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { outEvent->deviceId = 0; } else { outEvent->deviceId = device->id; @@ -440,11 +470,11 @@ bool EventHub::getEvent(RawEvent* outEvent) // Consume buffered input events, if any. if (mInputBufferIndex < mInputBufferCount) { const struct input_event& iev = mInputBufferData[mInputBufferIndex++]; - const device_t* device = mDevices[mInputDeviceIndex]; + const Device* device = mDevices[mInputFdIndex]; LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(), (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { outEvent->deviceId = 0; } else { outEvent->deviceId = device->id; @@ -454,8 +484,8 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->flags = 0; if (iev.type == EV_KEY) { outEvent->keyCode = AKEYCODE_UNKNOWN; - if (device->layoutMap) { - status_t err = device->layoutMap->map(iev.code, + if (device->keyMap.haveKeyLayout()) { + status_t err = device->keyMap.keyLayoutMap->map(iev.code, &outEvent->keyCode, &outEvent->flags); LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", iev.code, outEvent->keyCode, outEvent->flags, err); @@ -475,13 +505,13 @@ bool EventHub::getEvent(RawEvent* outEvent) // Finish reading all events from devices identified in previous poll(). // This code assumes that mInputDeviceIndex is initially 0 and that the // revents member of pollfd is initialized to 0 when the device is first added. - // Since mFDs[0] is used for inotify, we process regular events starting at index 1. - mInputDeviceIndex += 1; - if (mInputDeviceIndex >= mFDCount) { + // Since mFds[0] is used for inotify, we process regular events starting at index 1. + mInputFdIndex += 1; + if (mInputFdIndex >= mFds.size()) { break; } - const struct pollfd& pfd = mFDs[mInputDeviceIndex]; + const struct pollfd& pfd = mFds[mInputFdIndex]; if (pfd.revents & POLLIN) { int32_t readSize = read(pfd.fd, mInputBufferData, sizeof(struct input_event) * INPUT_BUFFER_SIZE); @@ -492,7 +522,7 @@ bool EventHub::getEvent(RawEvent* outEvent) } else if ((readSize % sizeof(struct input_event)) != 0) { LOGE("could not get event (wrong size: %d)", readSize); } else { - mInputBufferCount = readSize / sizeof(struct input_event); + mInputBufferCount = size_t(readSize) / sizeof(struct input_event); mInputBufferIndex = 0; } } @@ -501,14 +531,14 @@ bool EventHub::getEvent(RawEvent* outEvent) #if HAVE_INOTIFY // readNotify() will modify mFDs and mFDCount, so this must be done after // processing all other events. - if(mFDs[0].revents & POLLIN) { - readNotify(mFDs[0].fd); - mFDs[0].revents = 0; + if(mFds[0].revents & POLLIN) { + readNotify(mFds[0].fd); + mFds.editItemAt(0).revents = 0; continue; // report added or removed devices immediately } #endif - mInputDeviceIndex = 0; + mInputFdIndex = 0; // Poll for events. Mind the wake lock dance! // We hold a wake lock at all times except during poll(). This works due to some @@ -520,7 +550,7 @@ bool EventHub::getEvent(RawEvent* outEvent) // pending or currently being processed. release_wake_lock(WAKE_LOCK_ID); - int pollResult = poll(mFDs, mFDCount, -1); + int pollResult = poll(mFds.editArray(), mFds.size(), -1); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); @@ -536,36 +566,37 @@ bool EventHub::getEvent(RawEvent* outEvent) /* * Open the platform-specific input device. */ -bool EventHub::openPlatformInput(void) -{ +bool EventHub::openPlatformInput(void) { /* * Open platform-specific input device(s). */ - int res; + int res, fd; - mFDCount = 1; - mFDs = (pollfd *)calloc(1, sizeof(mFDs[0])); - mDevices = (device_t **)calloc(1, sizeof(mDevices[0])); - mFDs[0].events = POLLIN; - mFDs[0].revents = 0; - mDevices[0] = NULL; #ifdef HAVE_INOTIFY - mFDs[0].fd = inotify_init(); - res = inotify_add_watch(mFDs[0].fd, device_path, IN_DELETE | IN_CREATE); + fd = inotify_init(); + res = inotify_add_watch(fd, DEVICE_PATH, IN_DELETE | IN_CREATE); if(res < 0) { - LOGE("could not add watch for %s, %s\n", device_path, strerror(errno)); + LOGE("could not add watch for %s, %s\n", DEVICE_PATH, strerror(errno)); } #else /* * The code in EventHub::getEvent assumes that mFDs[0] is an inotify fd. * We allocate space for it and set it to something invalid. */ - mFDs[0].fd = -1; + fd = -1; #endif - res = scanDir(device_path); + // Reserve fd index 0 for inotify. + struct pollfd pollfd; + pollfd.fd = fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + mFds.push(pollfd); + mDevices.push(NULL); + + res = scanDir(DEVICE_PATH); if(res < 0) { - LOGE("scan dir failed for %s\n", device_path); + LOGE("scan dir failed for %s\n", DEVICE_PATH); } return true; @@ -593,128 +624,104 @@ static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE }; -int EventHub::openDevice(const char *deviceName) { - int version; - int fd; - struct pollfd *new_mFDs; - device_t **new_devices; - char **new_device_names; - char name[80]; - char location[80]; - char idstr[80]; - struct input_id id; +int EventHub::openDevice(const char *devicePath) { + char buffer[80]; - LOGV("Opening device: %s", deviceName); + LOGV("Opening device: %s", devicePath); AutoMutex _l(mLock); - fd = open(deviceName, O_RDWR); + int fd = open(devicePath, O_RDWR); if(fd < 0) { - LOGE("could not open %s, %s\n", deviceName, strerror(errno)); + LOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } - if(ioctl(fd, EVIOCGVERSION, &version)) { - LOGE("could not get driver version for %s, %s\n", deviceName, strerror(errno)); - return -1; - } - if(ioctl(fd, EVIOCGID, &id)) { - LOGE("could not get driver id for %s, %s\n", deviceName, strerror(errno)); - return -1; - } - name[sizeof(name) - 1] = '\0'; - location[sizeof(location) - 1] = '\0'; - idstr[sizeof(idstr) - 1] = '\0'; - if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { - //fprintf(stderr, "could not get device name for %s, %s\n", deviceName, strerror(errno)); - name[0] = '\0'; + InputDeviceIdentifier identifier; + + // Get device name. + if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); + } else { + buffer[sizeof(buffer) - 1] = '\0'; + identifier.name.setTo(buffer); } - // check to see if the device is on our excluded list + // Check to see if the device is on our excluded list List<String8>::iterator iter = mExcludedDevices.begin(); List<String8>::iterator end = mExcludedDevices.end(); for ( ; iter != end; iter++) { const char* test = *iter; - if (strcmp(name, test) == 0) { - LOGI("ignoring event id %s driver %s\n", deviceName, test); + if (identifier.name == test) { + LOGI("ignoring event id %s driver %s\n", devicePath, test); close(fd); return -1; } } - if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", deviceName, strerror(errno)); - location[0] = '\0'; - } - if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", deviceName, strerror(errno)); - idstr[0] = '\0'; - } - - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - LOGE("Error %d making device file descriptor non-blocking.", errno); + // Get device driver version. + int driverVersion; + if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { + LOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } - int devid = 0; - while (devid < mNumDevicesById) { - if (mDevicesById[devid].device == NULL) { - break; - } - devid++; + // Get device identifier. + struct input_id inputId; + if(ioctl(fd, EVIOCGID, &inputId)) { + LOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); + close(fd); + return -1; } - if (devid >= mNumDevicesById) { - device_ent* new_devids = (device_ent*)realloc(mDevicesById, - sizeof(mDevicesById[0]) * (devid + 1)); - if (new_devids == NULL) { - LOGE("out of memory"); - return -1; - } - mDevicesById = new_devids; - mNumDevicesById = devid+1; - mDevicesById[devid].device = NULL; - mDevicesById[devid].seq = 0; + identifier.bus = inputId.bustype; + identifier.product = inputId.product; + identifier.vendor = inputId.vendor; + identifier.version = inputId.version; + + // Get device physical location. + if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); + } else { + buffer[sizeof(buffer) - 1] = '\0'; + identifier.location.setTo(buffer); } - mDevicesById[devid].seq = (mDevicesById[devid].seq+(1<<SEQ_SHIFT))&SEQ_MASK; - if (mDevicesById[devid].seq == 0) { - mDevicesById[devid].seq = 1<<SEQ_SHIFT; + // Get device unique id. + if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { + //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); + } else { + buffer[sizeof(buffer) - 1] = '\0'; + identifier.uniqueId.setTo(buffer); } - new_mFDs = (pollfd*)realloc(mFDs, sizeof(mFDs[0]) * (mFDCount + 1)); - new_devices = (device_t**)realloc(mDevices, sizeof(mDevices[0]) * (mFDCount + 1)); - if (new_mFDs == NULL || new_devices == NULL) { - LOGE("out of memory"); + // Make file descriptor non-blocking for use with poll(). + if (fcntl(fd, F_SETFL, O_NONBLOCK)) { + LOGE("Error %d making device file descriptor non-blocking.", errno); + close(fd); return -1; } - mFDs = new_mFDs; - mDevices = new_devices; + + // Allocate device. (The device object takes ownership of the fd at this point.) + int32_t deviceId = mNextDeviceId++; + Device* device = new Device(fd, deviceId, String8(devicePath), identifier); #if 0 - LOGI("add device %d: %s\n", mFDCount, deviceName); - LOGI(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - id.bustype, id.vendor, id.product, id.version); - LOGI(" name: \"%s\"\n", name); - LOGI(" location: \"%s\"\n" - " id: \"%s\"\n", location, idstr); - LOGI(" version: %d.%d.%d\n", - version >> 16, (version >> 8) & 0xff, version & 0xff); + LOGI("add device %d: %s\n", deviceId, devicePath); + LOGI(" bus: %04x\n" + " vendor %04x\n" + " product %04x\n" + " version %04x\n", + identifier.bus, identifier.vendor, identifier.product, identifier.version); + LOGI(" name: \"%s\"\n", identifier.name.string()); + LOGI(" location: \"%s\"\n", identifier.location.string()); + LOGI(" unique id: \"%s\"\n", identifier.uniqueId.string()); + LOGI(" driver: v%d.%d.%d\n", + driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); #endif - device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name); - if (device == NULL) { - LOGE("out of memory"); - return -1; - } - - device->fd = fd; - mFDs[mFDCount].fd = fd; - mFDs[mFDCount].events = POLLIN; - mFDs[mFDCount].revents = 0; + // Load the configuration file for the device. + loadConfiguration(device); // Figure out the kinds of events the device reports. @@ -784,7 +791,7 @@ int EventHub::openDevice(const char *deviceName) { bool hasSwitches = false; if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; i<EV_SW; i++) { - //LOGI("Device 0x%x sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); + //LOGI("Device %d sw %d: has=%d", device->id, i, test_bit(i, sw_bitmask)); if (test_bit(i, sw_bitmask)) { hasSwitches = true; if (mSwitches[i] == 0) { @@ -798,38 +805,29 @@ int EventHub::openDevice(const char *deviceName) { } #endif - if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { - // a more descriptive name - device->name = name; - - // Configure the keymap for the device. + if ((device->classes & INPUT_DEVICE_CLASS_TOUCHSCREEN)) { + // Load the virtual keys for the touch screen, if any. + // We do this now so that we can make sure to load the keymap if necessary. + status_t status = loadVirtualKeyMap(device); + if (!status) { + device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; + } + } - configureKeyMap(device); + if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { + // Load the keymap for the device. + status_t status = loadKeyMap(device); - // Tell the world about the devname (the descriptive name) - if (!mHaveFirstKeyboard && !device->keyMapInfo.isDefaultKeyMap && strstr(name, "-keypad")) { - // the built-in keyboard has a well-known device ID of 0, - // this device better not go away. - mHaveFirstKeyboard = true; - mFirstKeyboardId = device->id; - setKeyboardProperties(device, true); - } else { - // ensure mFirstKeyboardId is set to -something-. - if (mFirstKeyboardId == -1) { - mFirstKeyboardId = device->id; - setKeyboardProperties(device, true); - } - } + // Set system properties for the keyboard. setKeyboardProperties(device, false); - // Load the keylayout. - if (!device->keyMapInfo.keyLayoutFile.isEmpty()) { - status_t status = KeyLayoutMap::load(device->keyMapInfo.keyLayoutFile, - &device->layoutMap); - if (status) { - LOGE("Error %d loading key layout file '%s'.", status, - device->keyMapInfo.keyLayoutFile.string()); - } + // Register the keyboard as a built-in keyboard if it is eligible. + if (!status + && mBuiltInKeyboardId == -1 + && isEligibleBuiltInKeyboard(device->identifier, + device->configuration, &device->keyMap)) { + mBuiltInKeyboardId = device->id; + setKeyboardProperties(device, true); } // 'Q' key support = cheap test of whether this is an alpha-capable kbd @@ -853,58 +851,87 @@ int EventHub::openDevice(const char *deviceName) { break; } } - - LOGI("New keyboard: device->id=0x%x devname='%s' keylayout='%s' keycharactermap='%s'\n", - device->id, name, - device->keyMapInfo.keyLayoutFile.string(), - device->keyMapInfo.keyCharacterMapFile.string()); } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { - LOGV("Dropping device %s %p, id = %d\n", deviceName, device, devid); - close(fd); + LOGV("Dropping device: id=%d, path='%s', name='%s'", + deviceId, devicePath, device->identifier.name.string()); delete device; return -1; } - LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", - deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes); - - LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n", - deviceName, device, mFDCount, devid, device->classes); + LOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " + "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s", + deviceId, fd, devicePath, device->identifier.name.string(), + device->classes, + device->configurationFile.string(), + device->keyMap.keyLayoutFile.string(), + device->keyMap.keyCharacterMapFile.string(), + toString(mBuiltInKeyboardId == deviceId)); + + struct pollfd pollfd; + pollfd.fd = fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + mFds.push(pollfd); + mDevices.push(device); - mDevicesById[devid].device = device; device->next = mOpeningDevices; mOpeningDevices = device; - mDevices[mFDCount] = device; - - mFDCount++; return 0; } -void EventHub::configureKeyMap(device_t* device) { - android::resolveKeyMap(device->name, device->keyMapInfo); +void EventHub::loadConfiguration(Device* device) { + device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( + device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); + if (device->configurationFile.isEmpty()) { + LOGD("No input device configuration file found for device '%s'.", + device->identifier.name.string()); + } else { + status_t status = PropertyMap::load(device->configurationFile, + &device->configuration); + if (status) { + LOGE("Error loading input device configuration file for device '%s'. " + "Using default configuration.", + device->identifier.name.string()); + } + } +} + +status_t EventHub::loadVirtualKeyMap(Device* device) { + // The virtual key map is supplied by the kernel as a system board property file. + String8 path; + path.append("/sys/board_properties/virtualkeys."); + path.append(device->identifier.name); + if (access(path.string(), R_OK)) { + return NAME_NOT_FOUND; + } + return VirtualKeyMap::load(path, &device->virtualKeyMap); +} + +status_t EventHub::loadKeyMap(Device* device) { + return device->keyMap.load(device->identifier, device->configuration); } -void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) { - int32_t id = firstKeyboard ? 0 : device->id; - android::setKeyboardProperties(id, device->name, device->keyMapInfo); +void EventHub::setKeyboardProperties(Device* device, bool builtInKeyboard) { + int32_t id = builtInKeyboard ? 0 : device->id; + android::setKeyboardProperties(id, device->identifier, + device->keyMap.keyLayoutFile, device->keyMap.keyCharacterMapFile); } -void EventHub::clearKeyboardProperties(device_t* device, bool firstKeyboard) { - int32_t id = firstKeyboard ? 0 : device->id; +void EventHub::clearKeyboardProperties(Device* device, bool builtInKeyboard) { + int32_t id = builtInKeyboard ? 0 : device->id; android::clearKeyboardProperties(id); } -bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const -{ - if (device->keyBitmask == NULL || device->layoutMap == NULL) { +bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { + if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { return false; } Vector<int32_t> scanCodes; - device->layoutMap->findScanCodes(keycode, &scanCodes); + device->keyMap.keyLayoutMap->findScanCodes(keycode, &scanCodes); const size_t N = scanCodes.size(); for (size_t i=0; i<N && i<=KEY_MAX; i++) { int32_t sc = scanCodes.itemAt(i); @@ -916,29 +943,15 @@ bool EventHub::hasKeycodeLocked(device_t* device, int keycode) const return false; } -int EventHub::closeDevice(const char *deviceName) { +int EventHub::closeDevice(const char *devicePath) { AutoMutex _l(mLock); - int i; - for(i = 1; i < mFDCount; i++) { - if(strcmp(mDevices[i]->path.string(), deviceName) == 0) { - //LOGD("remove device %d: %s\n", i, deviceName); - device_t* device = mDevices[i]; - - LOGI("Removed device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n", - device->path.string(), device->name.string(), device->id, - mNumDevicesById, mFDCount, mFDs[i].fd, device->classes); - - // Clear this device's entry. - int index = (device->id&ID_MASK); - mDevicesById[index].device = NULL; - - // Close the file descriptor and compact the fd array. - close(mFDs[i].fd); - int count = mFDCount - i - 1; - memmove(mDevices + i, mDevices + i + 1, sizeof(mDevices[0]) * count); - memmove(mFDs + i, mFDs + i + 1, sizeof(mFDs[0]) * count); - mFDCount--; + for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) { + Device* device = mDevices[i]; + if (device->path == devicePath) { + LOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", + device->path.string(), device->identifier.name.string(), device->id, + device->fd, device->classes); #ifdef EV_SW for (int j=0; j<EV_SW; j++) { @@ -947,21 +960,25 @@ int EventHub::closeDevice(const char *deviceName) { } } #endif - - device->next = mClosingDevices; - mClosingDevices = device; - if (device->id == mFirstKeyboardId) { + if (device->id == mBuiltInKeyboardId) { LOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.string(), mFirstKeyboardId); - mFirstKeyboardId = -1; + device->path.string(), mBuiltInKeyboardId); + mBuiltInKeyboardId = -1; clearKeyboardProperties(device, true); } clearKeyboardProperties(device, false); + + mFds.removeAt(i); + mDevices.removeAt(i); + device->close(); + + device->next = mClosingDevices; + mClosingDevices = device; return 0; } } - LOGE("remove device: %s not found\n", deviceName); + LOGE("remove device: %s not found\n", devicePath); return -1; } @@ -985,7 +1002,7 @@ int EventHub::readNotify(int nfd) { } //printf("got %d bytes of event information\n", res); - strcpy(devname, device_path); + strcpy(devname, DEVICE_PATH); filename = devname + strlen(devname); *filename++ = '/'; @@ -1009,7 +1026,6 @@ int EventHub::readNotify(int nfd) { return 0; } - int EventHub::scanDir(const char *dirname) { char devname[PATH_MAX]; @@ -1040,30 +1056,34 @@ void EventHub::dump(String8& dump) { { // acquire lock AutoMutex _l(mLock); - dump.appendFormat(INDENT "HaveFirstKeyboard: %s\n", toString(mHaveFirstKeyboard)); - dump.appendFormat(INDENT "FirstKeyboardId: 0x%x\n", mFirstKeyboardId); + dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); dump.append(INDENT "Devices:\n"); - for (int i = 0; i < mNumDevicesById; i++) { - const device_t* device = mDevicesById[i].device; + for (size_t i = FIRST_ACTUAL_DEVICE_INDEX; i < mDevices.size(); i++) { + const Device* device = mDevices[i]; if (device) { - if (mFirstKeyboardId == device->id) { - dump.appendFormat(INDENT2 "0x%x: %s (aka device 0 - first keyboard)\n", - device->id, device->name.string()); + if (mBuiltInKeyboardId == device->id) { + dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", + device->id, device->identifier.name.string()); } else { - dump.appendFormat(INDENT2 "0x%x: %s\n", device->id, device->name.string()); + dump.appendFormat(INDENT2 "%d: %s\n", device->id, + device->identifier.name.string()); } dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "IsDefaultKeyMap: %s\n", - toString(device->keyMapInfo.isDefaultKeyMap)); - dump.appendFormat(INDENT3 "KeyMapName: %s\n", - device->keyMapInfo.keyMapName.string()); + dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); + dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); + dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " + "product=0x%04x, version=0x%04x\n", + device->identifier.bus, device->identifier.vendor, + device->identifier.product, device->identifier.version); dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", - device->keyMapInfo.keyLayoutFile.string()); + device->keyMap.keyLayoutFile.string()); dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMapInfo.keyCharacterMapFile.string()); + device->keyMap.keyCharacterMapFile.string()); + dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", + device->configurationFile.string()); } } } // release lock diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index 944a79b..b8d59e6 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -7,11 +7,117 @@ //#define LOG_NDEBUG 0 +#define DEBUG_PROBE 0 + +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> + #include <ui/Input.h> namespace android { -// class InputEvent +static const char* CONFIGURATION_FILE_DIR[] = { + "idc/", + "keylayout/", + "keychars/", +}; + +static const char* CONFIGURATION_FILE_EXTENSION[] = { + ".idc", + ".kl", + ".kcm", +}; + +static bool isValidNameChar(char ch) { + return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); +} + +static void appendInputDeviceConfigurationFileRelativePath(String8& path, + const String8& name, InputDeviceConfigurationFileType type) { + path.append(CONFIGURATION_FILE_DIR[type]); + for (size_t i = 0; i < name.length(); i++) { + char ch = name[i]; + if (!isValidNameChar(ch)) { + ch = '_'; + } + path.append(&ch, 1); + } + path.append(CONFIGURATION_FILE_EXTENSION[type]); +} + +String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( + const InputDeviceIdentifier& deviceIdentifier, + InputDeviceConfigurationFileType type) { + if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { + if (deviceIdentifier.version != 0) { + // Try vendor product version. + String8 versionPath(getInputDeviceConfigurationFilePathByName( + String8::format("Vendor_%04x_Product_%04x_Version_%04x", + deviceIdentifier.vendor, deviceIdentifier.product, + deviceIdentifier.version), + type)); + if (!versionPath.isEmpty()) { + return versionPath; + } + } + + // Try vendor product. + String8 productPath(getInputDeviceConfigurationFilePathByName( + String8::format("Vendor_%04x_Product_%04x", + deviceIdentifier.vendor, deviceIdentifier.product), + type)); + if (!productPath.isEmpty()) { + return productPath; + } + } + + // Try device name. + return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); +} + +String8 getInputDeviceConfigurationFilePathByName( + const String8& name, InputDeviceConfigurationFileType type) { + // Search system repository. + String8 path; + path.setTo(getenv("ANDROID_ROOT")); + path.append("/usr/"); + appendInputDeviceConfigurationFileRelativePath(path, name, type); +#if DEBUG_PROBE + LOGD("Probing for system provided input device configuration file: path='%s'", path.string()); +#endif + if (!access(path.string(), R_OK)) { +#if DEBUG_PROBE + LOGD("Found"); +#endif + return path; + } + + // Search user repository. + // TODO Should only look here if not in safe mode. + path.setTo(getenv("ANDROID_DATA")); + path.append("/system/devices/"); + appendInputDeviceConfigurationFileRelativePath(path, name, type); +#if DEBUG_PROBE + LOGD("Probing for system user input device configuration file: path='%s'", path.string()); +#endif + if (!access(path.string(), R_OK)) { +#if DEBUG_PROBE + LOGD("Found"); +#endif + return path; + } + + // Not found. +#if DEBUG_PROBE + LOGD("Probe failed to find input device configuration file: name='%s', type=%d", + name.string(), type); +#endif + return String8(); +} + + +// --- InputEvent --- void InputEvent::initialize(int32_t deviceId, int32_t source) { mDeviceId = deviceId; @@ -23,7 +129,7 @@ void InputEvent::initialize(const InputEvent& from) { mSource = from.mSource; } -// class KeyEvent +// --- KeyEvent --- bool KeyEvent::hasDefaultAction(int32_t keyCode) { switch (keyCode) { @@ -131,7 +237,7 @@ void KeyEvent::initialize(const KeyEvent& from) { mEventTime = from.mEventTime; } -// class MotionEvent +// --- MotionEvent --- void MotionEvent::initialize( int32_t deviceId, @@ -178,7 +284,7 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) { mYOffset += yOffset; } -// class InputDeviceInfo +// --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { initialize(-1, String8("uninitialized device info")); diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index db7d448..f1223f1 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -315,7 +315,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t keyRepeatTimeout, // Throttle it! #if DEBUG_THROTTLING LOGD("Throttling - Delaying motion event for " - "device 0x%x, source 0x%08x by up to %0.3fms.", + "device %d, source 0x%08x by up to %0.3fms.", deviceId, source, (nextTime - currentTime) * 0.000001); #endif if (nextTime < *nextWakeupTime) { @@ -704,7 +704,7 @@ bool InputDispatcher::dispatchKeyLocked( void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " + LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " "repeatCount=%d, downTime=%lld", prefix, @@ -767,7 +767,7 @@ bool InputDispatcher::dispatchMotionLocked( void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS - LOGD("%seventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " + LOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, " "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, @@ -2072,7 +2072,7 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) { #if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyKey - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, " + LOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", eventTime, deviceId, source, policyFlags, action, flags, keyCode, scanCode, metaState, downTime); @@ -2081,9 +2081,22 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou return; } + if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { + policyFlags |= POLICY_FLAG_VIRTUAL; + flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; + } + policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags, - keyCode, scanCode, /*byref*/ policyFlags); + + KeyEvent event; + event.initialize(deviceId, source, action, flags, keyCode, scanCode, + metaState, 0, downTime, eventTime); + + mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); + + if (policyFlags & POLICY_FLAG_WOKE_HERE) { + flags |= AKEY_EVENT_FLAG_WOKE_HERE; + } bool needWake; { // acquire lock @@ -2107,7 +2120,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) { #if DEBUG_INBOUND_EVENT_DETAILS - LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, " + LOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, metaState=0x%x, edgeFlags=0x%x, " "xPrecision=%f, yPrecision=%f, downTime=%lld", eventTime, deviceId, source, policyFlags, action, flags, metaState, edgeFlags, @@ -2289,17 +2302,22 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, return INPUT_EVENT_INJECTION_FAILED; } - nsecs_t eventTime = keyEvent->getEventTime(); - int32_t deviceId = keyEvent->getDeviceId(); int32_t flags = keyEvent->getFlags(); - int32_t keyCode = keyEvent->getKeyCode(); - int32_t scanCode = keyEvent->getScanCode(); - mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags, - keyCode, scanCode, /*byref*/ policyFlags); + if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { + policyFlags |= POLICY_FLAG_VIRTUAL; + } + + mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); + + if (policyFlags & POLICY_FLAG_WOKE_HERE) { + flags |= AKEY_EVENT_FLAG_WOKE_HERE; + } mLock.lock(); - injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(), - policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(), + injectedEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(), + keyEvent->getDeviceId(), keyEvent->getSource(), + policyFlags, action, flags, + keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), keyEvent->getRepeatCount(), keyEvent->getDownTime()); break; } @@ -2999,12 +3017,14 @@ void InputDispatcher::doNotifyANRLockedInterruptible( void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; - initializeKeyEvent(&mReusableKeyEvent, entry); + + KeyEvent event; + initializeKeyEvent(&event, entry); mLock.unlock(); bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel, - & mReusableKeyEvent, entry->policyFlags); + &event, entry->policyFlags); mLock.lock(); @@ -3025,12 +3045,13 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( && dispatchEntry->hasForegroundTarget() && dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - initializeKeyEvent(&mReusableKeyEvent, keyEntry); + KeyEvent event; + initializeKeyEvent(&event, keyEntry); mLock.unlock(); mPolicy->dispatchUnhandledKey(connection->inputChannel, - & mReusableKeyEvent, keyEntry->policyFlags); + &event, keyEntry->policyFlags); mLock.lock(); } diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index daff2d0..9cc96ad 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -25,6 +25,7 @@ #include <cutils/log.h> #include <ui/InputReader.h> #include <ui/Keyboard.h> +#include <ui/VirtualKeyMap.h> #include <stddef.h> #include <stdlib.h> @@ -98,64 +99,6 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { } -// --- InputDeviceCalibration --- - -InputDeviceCalibration::InputDeviceCalibration() { -} - -void InputDeviceCalibration::clear() { - mProperties.clear(); -} - -void InputDeviceCalibration::addProperty(const String8& key, const String8& value) { - mProperties.add(key, value); -} - -bool InputDeviceCalibration::tryGetProperty(const String8& key, String8& outValue) const { - ssize_t index = mProperties.indexOfKey(key); - if (index < 0) { - return false; - } - - outValue = mProperties.valueAt(index); - return true; -} - -bool InputDeviceCalibration::tryGetProperty(const String8& key, int32_t& outValue) const { - String8 stringValue; - if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { - return false; - } - - char* end; - int value = strtol(stringValue.string(), & end, 10); - if (*end != '\0') { - LOGW("Input device calibration key '%s' has invalid value '%s'. Expected an integer.", - key.string(), stringValue.string()); - return false; - } - outValue = value; - return true; -} - -bool InputDeviceCalibration::tryGetProperty(const String8& key, float& outValue) const { - String8 stringValue; - if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { - return false; - } - - char* end; - float value = strtof(stringValue.string(), & end); - if (*end != '\0') { - LOGW("Input device calibration key '%s' has invalid value '%s'. Expected a float.", - key.string(), stringValue.string()); - return false; - } - outValue = value; - return true; -} - - // --- InputReader --- InputReader::InputReader(const sp<EventHubInterface>& eventHub, @@ -179,7 +122,7 @@ void InputReader::loopOnce() { mEventHub->getEvent(& rawEvent); #if DEBUG_RAW_EVENTS - LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d", + LOGD("Input event: device=%d type=0x%x scancode=%d keycode=%d value=%d", rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode, rawEvent.value); #endif @@ -215,9 +158,9 @@ void InputReader::addDevice(int32_t deviceId) { device->configure(); if (device->isIgnored()) { - LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", deviceId, name.string()); + LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string()); } else { - LOGI("Device added: id=0x%x, name=%s, sources=%08x", deviceId, name.string(), + LOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, name.string(), device->getSources()); } @@ -259,10 +202,10 @@ void InputReader::removeDevice(int32_t deviceId) { } if (device->isIgnored()) { - LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", + LOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), device->getName().string()); } else { - LOGI("Device removed: id=0x%x, name=%s, sources=%08x", + LOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), device->getName().string(), device->getSources()); } @@ -274,8 +217,6 @@ void InputReader::removeDevice(int32_t deviceId) { InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) { InputDevice* device = new InputDevice(this, deviceId, name); - const int32_t associatedDisplayId = 0; // FIXME: hardcoded for current single-display devices - // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); @@ -295,20 +236,19 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui } if (keyboardSources != 0) { - device->addMapper(new KeyboardInputMapper(device, - associatedDisplayId, keyboardSources, keyboardType)); + device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType)); } // Trackball-like devices. if (classes & INPUT_DEVICE_CLASS_TRACKBALL) { - device->addMapper(new TrackballInputMapper(device, associatedDisplayId)); + device->addMapper(new TrackballInputMapper(device)); } // Touchscreen-like devices. if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) { - device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId)); + device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) { - device->addMapper(new SingleTouchInputMapper(device, associatedDisplayId)); + device->addMapper(new SingleTouchInputMapper(device)); } return device; @@ -596,7 +536,7 @@ void InputDevice::dump(String8& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); - dump.appendFormat(INDENT "Device 0x%x: %s\n", deviceInfo.getId(), + dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), deviceInfo.getName().string()); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -626,7 +566,7 @@ void InputDevice::addMapper(InputMapper* mapper) { void InputDevice::configure() { if (! isIgnored()) { - mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration); + mContext->getEventHub()->getConfiguration(mId, &mConfiguration); } mSources = 0; @@ -792,9 +732,9 @@ int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCod // --- KeyboardInputMapper --- -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId, +KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t sources, int32_t keyboardType) : - InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources), + InputMapper(device), mSources(sources), mKeyboardType(keyboardType) { initializeLocked(); } @@ -832,7 +772,7 @@ void KeyboardInputMapper::dump(String8& dump) { { // acquire lock AutoMutex _l(mLock); dump.append(INDENT2 "Keyboard Input Mapper:\n"); - dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId); + dumpParameters(dump); dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mLocked.keyDowns.size()); dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mLocked.metaState); @@ -840,6 +780,30 @@ void KeyboardInputMapper::dump(String8& dump) { } // release lock } + +void KeyboardInputMapper::configure() { + InputMapper::configure(); + + // Configure basic parameters. + configureParameters(); +} + +void KeyboardInputMapper::configureParameters() { + mParameters.orientationAware = false; + getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), + mParameters.orientationAware); + + mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1; +} + +void KeyboardInputMapper::dumpParameters(String8& dump) { + dump.append(INDENT3 "Parameters:\n"); + dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", + mParameters.associatedDisplayId); + dump.appendFormat(INDENT4 "OrientationAware: %s\n", + toString(mParameters.orientationAware)); +} + void KeyboardInputMapper::reset() { for (;;) { int32_t keyCode, scanCode; @@ -896,9 +860,10 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, if (down) { // Rotate key codes according to orientation if needed. // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. - if (mAssociatedDisplayId >= 0) { + if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { int32_t orientation; - if (!getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) { + if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, + NULL, NULL, & orientation)) { orientation = InputReaderPolicyInterface::ROTATION_0; } @@ -1011,8 +976,8 @@ void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState& // --- TrackballInputMapper --- -TrackballInputMapper::TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId) : - InputMapper(device), mAssociatedDisplayId(associatedDisplayId) { +TrackballInputMapper::TrackballInputMapper(InputDevice* device) : + InputMapper(device) { mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; @@ -1039,7 +1004,7 @@ void TrackballInputMapper::dump(String8& dump) { { // acquire lock AutoMutex _l(mLock); dump.append(INDENT2 "Trackball Input Mapper:\n"); - dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId); + dumpParameters(dump); dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down)); @@ -1047,6 +1012,29 @@ void TrackballInputMapper::dump(String8& dump) { } // release lock } +void TrackballInputMapper::configure() { + InputMapper::configure(); + + // Configure basic parameters. + configureParameters(); +} + +void TrackballInputMapper::configureParameters() { + mParameters.orientationAware = false; + getDevice()->getConfiguration().tryGetProperty(String8("trackball.orientationAware"), + mParameters.orientationAware); + + mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1; +} + +void TrackballInputMapper::dumpParameters(String8& dump) { + dump.append(INDENT3 "Parameters:\n"); + dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", + mParameters.associatedDisplayId); + dump.appendFormat(INDENT4 "OrientationAware: %s\n", + toString(mParameters.orientationAware)); +} + void TrackballInputMapper::initializeLocked() { mAccumulator.clear(); @@ -1155,11 +1143,13 @@ void TrackballInputMapper::sync(nsecs_t when) { pointerCoords.toolMinor = 0; pointerCoords.orientation = 0; - if (mAssociatedDisplayId >= 0 && (x != 0.0f || y != 0.0f)) { + if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0 + && (x != 0.0f || y != 0.0f)) { // Rotate motion based on display orientation if needed. // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. int32_t orientation; - if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) { + if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, + NULL, NULL, & orientation)) { orientation = InputReaderPolicyInterface::ROTATION_0; } @@ -1205,8 +1195,8 @@ int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scan // --- TouchInputMapper --- -TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) : - InputMapper(device), mAssociatedDisplayId(associatedDisplayId) { +TouchInputMapper::TouchInputMapper(InputDevice* device) : + InputMapper(device) { mLocked.surfaceOrientation = -1; mLocked.surfaceWidth = -1; mLocked.surfaceHeight = -1; @@ -1218,7 +1208,15 @@ TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { - return mAssociatedDisplayId >= 0 ? AINPUT_SOURCE_TOUCHSCREEN : AINPUT_SOURCE_TOUCHPAD; + switch (mParameters.deviceType) { + case Parameters::DEVICE_TYPE_TOUCH_SCREEN: + return AINPUT_SOURCE_TOUCHSCREEN; + case Parameters::DEVICE_TYPE_TOUCH_PAD: + return AINPUT_SOURCE_TOUCHPAD; + default: + assert(false); + return AINPUT_SOURCE_UNKNOWN; + } } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { @@ -1269,7 +1267,6 @@ void TouchInputMapper::dump(String8& dump) { { // acquire lock AutoMutex _l(mLock); dump.append(INDENT2 "Touch Input Mapper:\n"); - dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId); dumpParameters(dump); dumpVirtualKeysLocked(dump); dumpRawAxes(dump); @@ -1339,14 +1336,50 @@ void TouchInputMapper::configureParameters() { mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); + + String8 deviceTypeString; + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; + if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), + deviceTypeString)) { + if (deviceTypeString == "touchPad") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else if (deviceTypeString != "touchScreen") { + LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + } + } + bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; + + mParameters.orientationAware = isTouchScreen; + getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), + mParameters.orientationAware); + + mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1; } void TouchInputMapper::dumpParameters(String8& dump) { - dump.appendFormat(INDENT3 "UseBadTouchFilter: %s\n", + dump.append(INDENT3 "Parameters:\n"); + + switch (mParameters.deviceType) { + case Parameters::DEVICE_TYPE_TOUCH_SCREEN: + dump.append(INDENT4 "DeviceType: touchScreen\n"); + break; + case Parameters::DEVICE_TYPE_TOUCH_PAD: + dump.append(INDENT4 "DeviceType: touchPad\n"); + break; + default: + assert(false); + } + + dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", + mParameters.associatedDisplayId); + dump.appendFormat(INDENT4 "OrientationAware: %s\n", + toString(mParameters.orientationAware)); + + dump.appendFormat(INDENT4 "UseBadTouchFilter: %s\n", toString(mParameters.useBadTouchFilter)); - dump.appendFormat(INDENT3 "UseAveragingTouchFilter: %s\n", + dump.appendFormat(INDENT4 "UseAveragingTouchFilter: %s\n", toString(mParameters.useAveragingTouchFilter)); - dump.appendFormat(INDENT3 "UseJumpyTouchFilter: %s\n", + dump.appendFormat(INDENT4 "UseJumpyTouchFilter: %s\n", toString(mParameters.useJumpyTouchFilter)); } @@ -1384,17 +1417,20 @@ void TouchInputMapper::dumpRawAxes(String8& dump) { bool TouchInputMapper::configureSurfaceLocked() { // Update orientation and dimensions if needed. - int32_t orientation; - int32_t width, height; - if (mAssociatedDisplayId >= 0) { + int32_t orientation = InputReaderPolicyInterface::ROTATION_0; + int32_t width = mRawAxes.x.getRange(); + int32_t height = mRawAxes.y.getRange(); + + if (mParameters.associatedDisplayId >= 0) { + bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; + bool wantOrientation = mParameters.orientationAware; + // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. - if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) { + if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, + wantSize ? &width : NULL, wantSize ? &height : NULL, + wantOrientation ? &orientation : NULL)) { return false; } - } else { - orientation = InputReaderPolicyInterface::ROTATION_0; - width = mRawAxes.x.getRange(); - height = mRawAxes.y.getRange(); } bool orientationChanged = mLocked.surfaceOrientation != orientation; @@ -1404,7 +1440,7 @@ bool TouchInputMapper::configureSurfaceLocked() { bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { - LOGI("Device reconfigured: id=0x%x, name=%s, display size is now %dx%d", + LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d", getDeviceId(), getDeviceName().string(), width, height); mLocked.surfaceWidth = width; @@ -1616,9 +1652,8 @@ void TouchInputMapper::dumpSurfaceLocked(String8& dump) { void TouchInputMapper::configureVirtualKeysLocked() { assert(mRawAxes.x.valid && mRawAxes.y.valid); - // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock. Vector<VirtualKeyDefinition> virtualKeyDefinitions; - getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions); + getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); mLocked.virtualKeys.clear(); @@ -1686,7 +1721,7 @@ void TouchInputMapper::dumpVirtualKeysLocked(String8& dump) { } void TouchInputMapper::parseCalibration() { - const InputDeviceCalibration& in = getDevice()->getCalibration(); + const PropertyMap& in = getDevice()->getConfiguration(); Calibration& out = mCalibration; // Position @@ -1972,8 +2007,8 @@ void TouchInputMapper::dumpCalibration(String8& dump) { } if (mCalibration.haveToolSizeIsSummed) { - dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %d\n", - mCalibration.toolSizeIsSummed); + dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %s\n", + toString(mCalibration.toolSizeIsSummed)); } // Pressure @@ -3157,8 +3192,8 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode // --- SingleTouchInputMapper --- -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) : - TouchInputMapper(device, associatedDisplayId) { +SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : + TouchInputMapper(device) { initialize(); } @@ -3286,8 +3321,8 @@ void SingleTouchInputMapper::configureRawAxes() { // --- MultiTouchInputMapper --- -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) : - TouchInputMapper(device, associatedDisplayId) { +MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : + TouchInputMapper(device) { initialize(); } diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp index de76e25..6faa600 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -22,102 +22,173 @@ #include <ui/Keyboard.h> #include <ui/KeycodeLabels.h> +#include <ui/KeyLayoutMap.h> +#include <ui/KeyCharacterMap.h> #include <utils/Errors.h> #include <utils/Log.h> #include <cutils/properties.h> namespace android { -static void selectKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) { - if (keyMapInfo.keyMapName.isEmpty()) { - keyMapInfo.keyMapName.setTo(keyMapName); - keyMapInfo.isDefaultKeyMap = defaultKeyMap; - } +// --- KeyMap --- + +KeyMap::KeyMap() : + keyLayoutMap(NULL), keyCharacterMap(NULL) { +} + +KeyMap::~KeyMap() { + delete keyLayoutMap; + delete keyCharacterMap; } -static bool probeKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) { - const char* root = getenv("ANDROID_ROOT"); +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) { + LOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " + "it was not found.", + deviceIdenfifier.name.string(), keyLayoutName.string()); + } + } - // TODO Consider also looking somewhere in a writeable partition like /data for a - // custom keymap supplied by the user for this device. - bool haveKeyLayout = !keyMapInfo.keyLayoutFile.isEmpty(); - if (!haveKeyLayout) { - keyMapInfo.keyLayoutFile.setTo(root); - keyMapInfo.keyLayoutFile.append("/usr/keylayout/"); - keyMapInfo.keyLayoutFile.append(keyMapName); - keyMapInfo.keyLayoutFile.append(".kl"); - if (access(keyMapInfo.keyLayoutFile.string(), R_OK)) { - keyMapInfo.keyLayoutFile.clear(); - } else { - haveKeyLayout = true; + String8 keyCharacterMapName; + if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), + keyCharacterMapName)) { + status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); + if (status == NAME_NOT_FOUND) { + LOGE("Configuration for keyboard device '%s' requested keyboard character " + "map '%s' but it was not found.", + deviceIdenfifier.name.string(), keyLayoutName.string()); + } } - } - bool haveKeyCharacterMap = !keyMapInfo.keyCharacterMapFile.isEmpty(); - if (!haveKeyCharacterMap) { - keyMapInfo.keyCharacterMapFile.setTo(root); - keyMapInfo.keyCharacterMapFile.append("/usr/keychars/"); - keyMapInfo.keyCharacterMapFile.append(keyMapName); - keyMapInfo.keyCharacterMapFile.append(".kcm"); - if (access(keyMapInfo.keyCharacterMapFile.string(), R_OK)) { - keyMapInfo.keyCharacterMapFile.clear(); - } else { - haveKeyCharacterMap = true; + if (isComplete()) { + return OK; } } - if (haveKeyLayout || haveKeyCharacterMap) { - selectKeyMap(keyMapInfo, keyMapName, defaultKeyMap); + // 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; } - return haveKeyLayout && haveKeyCharacterMap; + + // Give up! + LOGE("Could not determine key map for device '%s' and no default key maps were found!", + deviceIdenfifier.name.string()); + return NAME_NOT_FOUND; } -status_t resolveKeyMap(const String8& deviceName, KeyMapInfo& outKeyMapInfo) { - // As an initial key map name, try using the device name. - String8 keyMapName(deviceName); - char* p = keyMapName.lockBuffer(keyMapName.size()); - while (*p) { - if (*p == ' ') *p = '_'; - p++; +bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, + const String8& keyMapName) { + if (!haveKeyLayout()) { + loadKeyLayout(deviceIdentifier, keyMapName); } - keyMapName.unlockBuffer(); + if (!haveKeyCharacterMap()) { + loadKeyCharacterMap(deviceIdentifier, keyMapName); + } + return isComplete(); +} - if (probeKeyMap(outKeyMapInfo, keyMapName, false)) return OK; +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; + } - // TODO Consider allowing the user to configure a specific key map somehow. + KeyLayoutMap* map; + status_t status = KeyLayoutMap::load(path, &map); + if (status) { + return status; + } - // Try the Generic key map. - // TODO Apply some additional heuristics here to figure out what kind of - // generic key map to use (US English, etc.). - keyMapName.setTo("Generic"); - if (probeKeyMap(outKeyMapInfo, keyMapName, true)) return OK; + keyLayoutFile.setTo(path); + keyLayoutMap = map; + return OK; +} - // Give up! - keyMapName.setTo("unknown"); - selectKeyMap(outKeyMapInfo, keyMapName, true); - LOGE("Could not determine key map for device '%s'.", deviceName.string()); - return NAME_NOT_FOUND; +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; } -void setKeyboardProperties(int32_t deviceId, const String8& deviceName, - const KeyMapInfo& keyMapInfo) { +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"); +} + +void setKeyboardProperties(int32_t deviceId, + const InputDeviceIdentifier& deviceIdentifier, + const String8& keyLayoutFile, const String8& keyCharacterMapFile) { char propName[PROPERTY_KEY_MAX]; snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId); - property_set(propName, deviceName.string()); - snprintf(propName, sizeof(propName), "hw.keyboards.%u.keymap", deviceId); - property_set(propName, keyMapInfo.keyMapName.string()); + property_set(propName, deviceIdentifier.name.string()); snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId); - property_set(propName, keyMapInfo.keyLayoutFile.string()); + property_set(propName, keyLayoutFile.string()); snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); - property_set(propName, keyMapInfo.keyCharacterMapFile.string()); + property_set(propName, keyCharacterMapFile.string()); } void clearKeyboardProperties(int32_t deviceId) { char propName[PROPERTY_KEY_MAX]; snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId); property_set(propName, ""); - snprintf(propName, sizeof(propName), "hw.keyboards.%u.keymap", deviceId); - property_set(propName, ""); snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId); property_set(propName, ""); snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); @@ -125,31 +196,24 @@ void clearKeyboardProperties(int32_t deviceId) { } status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) { - char propName[PROPERTY_KEY_MAX]; - char fn[PROPERTY_VALUE_MAX]; - snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); - if (property_get(propName, fn, "") > 0) { - outKeyCharacterMapFile.setTo(fn); - return OK; - } - - const char* root = getenv("ANDROID_ROOT"); - char path[PATH_MAX]; - if (deviceId == DEVICE_ID_VIRTUAL_KEYBOARD) { - snprintf(path, sizeof(path), "%s/usr/keychars/Virtual.kcm", root); - if (!access(path, R_OK)) { - outKeyCharacterMapFile.setTo(path); + if (deviceId != DEVICE_ID_VIRTUAL_KEYBOARD) { + char propName[PROPERTY_KEY_MAX]; + char fn[PROPERTY_VALUE_MAX]; + snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId); + if (property_get(propName, fn, "") > 0) { + outKeyCharacterMapFile.setTo(fn); return OK; } } - snprintf(path, sizeof(path), "%s/usr/keychars/Generic.kcm", root); - if (!access(path, R_OK)) { - outKeyCharacterMapFile.setTo(path); + // Default to Virtual since the keyboard does not appear to be installed. + outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePathByName(String8("Virtual"), + INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); + if (!outKeyCharacterMapFile.isEmpty()) { return OK; } - LOGE("Can't find any key character map files (also tried %s)", path); + LOGE("Can't find any key character map files including the Virtual key map!"); return NAME_NOT_FOUND; } diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/ui/VirtualKeyMap.cpp new file mode 100644 index 0000000..e756cdd --- /dev/null +++ b/libs/ui/VirtualKeyMap.cpp @@ -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 <ui/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) { + LOGE("Error %d opening virtual key map file %s.", status, filename.string()); + } else { + VirtualKeyMap* map = new VirtualKeyMap(); + if (!map) { + LOGE("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; + LOGD("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 + LOGD("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") { + LOGE("%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) { + LOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + +#if DEBUG_PARSER + LOGD("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()) { + LOGE("%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') { + LOGE("Expected an integer, got '%s'.", token.string()); + return false; + } + return true; +} + +} // namespace android diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp index f352dbf..68f9037 100644 --- a/libs/ui/tests/InputDispatcher_test.cpp +++ b/libs/ui/tests/InputDispatcher_test.cpp @@ -54,9 +54,7 @@ private: return 60; } - virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId, - int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode, - uint32_t& policyFlags) { + virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) { } virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp index ded0225..d6c2cbd 100644 --- a/libs/ui/tests/InputReader_test.cpp +++ b/libs/ui/tests/InputReader_test.cpp @@ -42,8 +42,6 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface { KeyedVector<int32_t, DisplayInfo> mDisplayInfos; bool mFilterTouchEvents; bool mFilterJumpyTouchEvents; - KeyedVector<String8, Vector<VirtualKeyDefinition> > mVirtualKeyDefinitions; - KeyedVector<String8, InputDeviceCalibration> mInputDeviceCalibrations; Vector<String8> mExcludedDeviceNames; protected: @@ -76,29 +74,6 @@ public: mFilterJumpyTouchEvents = enabled; } - void addInputDeviceCalibration(const String8& deviceName, - const InputDeviceCalibration& calibration) { - mInputDeviceCalibrations.add(deviceName, calibration); - } - - void addInputDeviceCalibrationProperty(const String8& deviceName, - const String8& key, const String8& value) { - ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName); - if (index < 0) { - index = mInputDeviceCalibrations.add(deviceName, InputDeviceCalibration()); - } - mInputDeviceCalibrations.editValueAt(index).addProperty(key, value); - } - - void addVirtualKeyDefinition(const String8& deviceName, - const VirtualKeyDefinition& definition) { - if (mVirtualKeyDefinitions.indexOfKey(deviceName) < 0) { - mVirtualKeyDefinitions.add(deviceName, Vector<VirtualKeyDefinition>()); - } - - mVirtualKeyDefinitions.editValueFor(deviceName).push(definition); - } - void addExcludedDeviceName(const String8& deviceName) { mExcludedDeviceNames.push(deviceName); } @@ -131,22 +106,6 @@ private: return mFilterJumpyTouchEvents; } - virtual void getVirtualKeyDefinitions(const String8& deviceName, - Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) { - ssize_t index = mVirtualKeyDefinitions.indexOfKey(deviceName); - if (index >= 0) { - outVirtualKeyDefinitions.appendVector(mVirtualKeyDefinitions.valueAt(index)); - } - } - - virtual void getInputDeviceCalibration(const String8& deviceName, - InputDeviceCalibration& outCalibration) { - ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName); - if (index >= 0) { - outCalibration = mInputDeviceCalibrations.valueAt(index); - } - } - virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) { outExcludedDeviceNames.appendVector(mExcludedDeviceNames); } @@ -371,12 +330,14 @@ class FakeEventHub : public EventHubInterface { struct Device { String8 name; uint32_t classes; + PropertyMap configuration; KeyedVector<int, RawAbsoluteAxisInfo> axes; KeyedVector<int32_t, int32_t> keyCodeStates; KeyedVector<int32_t, int32_t> scanCodeStates; KeyedVector<int32_t, int32_t> switchStates; KeyedVector<int32_t, KeyInfo> keys; KeyedVector<int32_t, bool> leds; + Vector<VirtualKeyDefinition> virtualKeys; Device(const String8& name, uint32_t classes) : name(name), classes(classes) { @@ -415,6 +376,11 @@ public: enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0, 0, 0); } + void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { + Device* device = getDevice(deviceId); + device->configuration.addProperty(key, value); + } + void addAxis(int32_t deviceId, int axis, int32_t minValue, int32_t maxValue, int flat, int fuzz) { Device* device = getDevice(deviceId); @@ -465,6 +431,11 @@ public: return mExcludedDevices; } + void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { + Device* device = getDevice(deviceId); + device->virtualKeys.push(definition); + } + void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type, int32_t scanCode, int32_t keyCode, int32_t value, uint32_t flags) { RawEvent event; @@ -499,6 +470,13 @@ private: return device ? device->name : String8("unknown"); } + virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { + Device* device = getDevice(deviceId); + if (device) { + *outConfiguration = device->configuration; + } + } + virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { Device* device = getDevice(deviceId); @@ -613,6 +591,16 @@ private: } } + virtual void getVirtualKeyDefinitions(int32_t deviceId, + Vector<VirtualKeyDefinition>& outVirtualKeys) const { + outVirtualKeys.clear(); + + Device* device = getDevice(deviceId); + if (device) { + outVirtualKeys.appendVector(device->virtualKeys); + } + } + virtual void dump(String8& dump) { } }; @@ -1208,9 +1196,7 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { // Configuration. - InputDeviceCalibration calibration; - calibration.addProperty(String8("key"), String8("value")); - mFakePolicy->addInputDeviceCalibration(String8(DEVICE_NAME), calibration); + mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); @@ -1231,8 +1217,8 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe mDevice->configure(); String8 propertyValue; - ASSERT_TRUE(mDevice->getCalibration().tryGetProperty(String8("key"), propertyValue)) - << "Device should have read calibration during configuration phase."; + ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) + << "Device should have read configuration during configuration phase."; ASSERT_STREQ("value", propertyValue.string()); ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); @@ -1329,9 +1315,8 @@ protected: mFakeEventHub.clear(); } - void prepareCalibration(const char* key, const char* value) { - mFakePolicy->addInputDeviceCalibrationProperty(String8(DEVICE_NAME), - String8(key), String8(value)); + void addConfigurationProperty(const char* key, const char* value) { + mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value)); } void addMapperAndConfigure(InputMapper* mapper) { @@ -1448,7 +1433,7 @@ void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, TEST_F(KeyboardInputMapperTest, GetSources) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1456,7 +1441,7 @@ TEST_F(KeyboardInputMapperTest, GetSources) { } TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1493,7 +1478,7 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { } TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1513,7 +1498,7 @@ TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) } TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1558,7 +1543,7 @@ TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) { } TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1597,11 +1582,14 @@ TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); } -TEST_F(KeyboardInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateDPad) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, +TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -1612,9 +1600,10 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotate KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); } -TEST_F(KeyboardInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateDPad) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, DISPLAY_ID, +TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + addConfigurationProperty("keyboard.orientationAware", "1"); addMapperAndConfigure(mapper); mFakePolicy->setDisplayInfo(DISPLAY_ID, @@ -1689,7 +1678,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateDPad) } TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1701,7 +1690,7 @@ TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { } TEST_F(KeyboardInputMapperTest, GetScanCodeState) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1713,7 +1702,7 @@ TEST_F(KeyboardInputMapperTest, GetScanCodeState) { } TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1731,7 +1720,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/); mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/); - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1, + KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); @@ -1830,14 +1819,14 @@ void TrackballInputMapperTest::testMotionRotation(TrackballInputMapper* mapper, } TEST_F(TrackballInputMapperTest, GetSources) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); } TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); InputDeviceInfo info; @@ -1850,7 +1839,7 @@ TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) { } TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -1898,7 +1887,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaS } TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1922,7 +1911,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { } TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1943,7 +1932,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { } TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1978,7 +1967,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) } TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -1998,7 +1987,7 @@ TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeBu } TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); FakeInputDispatcher::NotifyMotionArgs args; @@ -2016,10 +2005,13 @@ TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(TrackballInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateMotions) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1); +TEST_F(TrackballInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); addMapperAndConfigure(mapper); + mFakePolicy->setDisplayInfo(DISPLAY_ID, + DISPLAY_WIDTH, DISPLAY_HEIGHT, + InputReaderPolicyInterface::ROTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); @@ -2030,8 +2022,9 @@ TEST_F(TrackballInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotat ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); } -TEST_F(TrackballInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateMotions) { - TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, DISPLAY_ID); +TEST_F(TrackballInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { + TrackballInputMapper* mapper = new TrackballInputMapper(mDevice); + addConfigurationProperty("trackball.orientationAware", "1"); addMapperAndConfigure(mapper); mFakePolicy->setDisplayInfo(DISPLAY_ID, @@ -2152,8 +2145,8 @@ void TouchInputMapperTest::prepareDisplay(int32_t orientation) { } void TouchInputMapperTest::prepareVirtualKeys() { - mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[0]); - mFakePolicy->addVirtualKeyDefinition(String8(DEVICE_NAME), VIRTUAL_KEYS[1]); + mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); + mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, AKEYCODE_MENU, POLICY_FLAG_WAKE); } @@ -2232,24 +2225,26 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { } -TEST_F(SingleTouchInputMapperTest, GetSources_WhenNotAttachedToADisplay_ReturnsTouchPad) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, -1); +TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchPad_ReturnsTouchPad) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareAxes(POSITION); + addConfigurationProperty("touch.displayType", "touchPad"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); } -TEST_F(SingleTouchInputMapperTest, GetSources_WhenAttachedToADisplay_ReturnsTouchScreen) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); +TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchScreen_ReturnsTouchScreen) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareAxes(POSITION); + addConfigurationProperty("touch.displayType", "touchScreen"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2276,7 +2271,7 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { } TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2303,7 +2298,7 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { } TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2319,7 +2314,7 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) { // Note: Ideally we should send cancels but the implementation is more straightforward // with up and this will only happen if a device is forcibly removed. - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2352,7 +2347,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) { } TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2378,7 +2373,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2427,7 +2422,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2541,7 +2536,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB } TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2609,7 +2604,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves } TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -2691,8 +2686,30 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled()); } -TEST_F(SingleTouchInputMapperTest, Process_Rotation) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); +TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); + prepareAxes(POSITION); + addConfigurationProperty("touch.orientationAware", "0"); + addMapperAndConfigure(mapper); + + FakeInputDispatcher::NotifyMotionArgs args; + + // Rotation 90. + prepareDisplay(InputReaderPolicyInterface::ROTATION_90); + processDown(mapper, toRawX(50), toRawY(75)); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); + ASSERT_NEAR(50, args.pointerCoords[0].x, 1); + ASSERT_NEAR(75, args.pointerCoords[0].y, 1); + + processUp(mapper); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled()); +} + +TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareAxes(POSITION); addMapperAndConfigure(mapper); @@ -2752,7 +2769,7 @@ TEST_F(SingleTouchInputMapperTest, Process_Rotation) { } TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID); + SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION | PRESSURE | TOOL); addMapperAndConfigure(mapper); @@ -2884,7 +2901,7 @@ void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); @@ -3135,7 +3152,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION | ID); prepareVirtualKeys(); @@ -3295,7 +3312,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId } TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR); addMapperAndConfigure(mapper); @@ -3340,11 +3357,11 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL | MINOR); - prepareCalibration("touch.touchSize.calibration", "geometric"); - prepareCalibration("touch.toolSize.calibration", "geometric"); + addConfigurationProperty("touch.touchSize.calibration", "geometric"); + addConfigurationProperty("touch.toolSize.calibration", "geometric"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. @@ -3381,17 +3398,17 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) } TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL); - prepareCalibration("touch.touchSize.calibration", "pressure"); - prepareCalibration("touch.toolSize.calibration", "linear"); - prepareCalibration("touch.toolSize.linearScale", "10"); - prepareCalibration("touch.toolSize.linearBias", "160"); - prepareCalibration("touch.toolSize.isSummed", "1"); - prepareCalibration("touch.pressure.calibration", "amplitude"); - prepareCalibration("touch.pressure.source", "touch"); - prepareCalibration("touch.pressure.scale", "0.01"); + addConfigurationProperty("touch.touchSize.calibration", "pressure"); + addConfigurationProperty("touch.toolSize.calibration", "linear"); + addConfigurationProperty("touch.toolSize.linearScale", "10"); + addConfigurationProperty("touch.toolSize.linearBias", "160"); + addConfigurationProperty("touch.toolSize.isSummed", "1"); + addConfigurationProperty("touch.pressure.calibration", "amplitude"); + addConfigurationProperty("touch.pressure.source", "touch"); + addConfigurationProperty("touch.pressure.scale", "0.01"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. @@ -3437,18 +3454,18 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinear } TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) { - MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID); + MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); prepareDisplay(InputReaderPolicyInterface::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL); - prepareCalibration("touch.touchSize.calibration", "pressure"); - prepareCalibration("touch.toolSize.calibration", "area"); - prepareCalibration("touch.toolSize.areaScale", "22"); - prepareCalibration("touch.toolSize.areaBias", "1"); - prepareCalibration("touch.toolSize.linearScale", "9.2"); - prepareCalibration("touch.toolSize.linearBias", "3"); - prepareCalibration("touch.pressure.calibration", "amplitude"); - prepareCalibration("touch.pressure.source", "touch"); - prepareCalibration("touch.pressure.scale", "0.01"); + addConfigurationProperty("touch.touchSize.calibration", "pressure"); + addConfigurationProperty("touch.toolSize.calibration", "area"); + addConfigurationProperty("touch.toolSize.areaScale", "22"); + addConfigurationProperty("touch.toolSize.areaBias", "1"); + addConfigurationProperty("touch.toolSize.linearScale", "9.2"); + addConfigurationProperty("touch.toolSize.linearBias", "3"); + addConfigurationProperty("touch.pressure.calibration", "amplitude"); + addConfigurationProperty("touch.pressure.source", "touch"); + addConfigurationProperty("touch.pressure.scale", "0.01"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 9c01aea..8bd833b 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -28,6 +28,7 @@ commonSources:= \ Flattenable.cpp \ ObbFile.cpp \ Pool.cpp \ + PropertyMap.cpp \ RefBase.cpp \ ResourceTypes.cpp \ SharedBuffer.cpp \ diff --git a/libs/utils/FileMap.cpp b/libs/utils/FileMap.cpp index e1ba9b2..f1f8bda 100644 --- a/libs/utils/FileMap.cpp +++ b/libs/utils/FileMap.cpp @@ -63,16 +63,18 @@ FileMap::~FileMap(void) free(mFileName); } #ifdef HAVE_POSIX_FILEMAP - if (munmap(mBasePtr, mBaseLength) != 0) { + if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { LOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength); } #endif #ifdef HAVE_WIN32_FILEMAP - if ( UnmapViewOfFile(mBasePtr) == 0) { + if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) { LOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr, GetLastError() ); } - CloseHandle(mFileMapping); + if (mFileMapping != INVALID_HANDLE_VALUE) { + CloseHandle(mFileMapping); + } CloseHandle(mFileHandle); #endif } diff --git a/libs/utils/PropertyMap.cpp b/libs/utils/PropertyMap.cpp new file mode 100644 index 0000000..fd7edec --- /dev/null +++ b/libs/utils/PropertyMap.cpp @@ -0,0 +1,212 @@ +/* + * 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 "PropertyMap" + +#include <stdlib.h> +#include <string.h> + +#include <utils/PropertyMap.h> +#include <utils/Log.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_PROPERTY_DELIMITER = " \t\r="; + + +// --- PropertyMap --- + +PropertyMap::PropertyMap() { +} + +PropertyMap::~PropertyMap() { +} + +void PropertyMap::clear() { + mProperties.clear(); +} + +void PropertyMap::addProperty(const String8& key, const String8& value) { + mProperties.add(key, value); +} + +bool PropertyMap::hasProperty(const String8& key) const { + return mProperties.indexOfKey(key) >= 0; +} + +bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { + ssize_t index = mProperties.indexOfKey(key); + if (index < 0) { + return false; + } + + outValue = mProperties.valueAt(index); + return true; +} + +bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { + int32_t intValue; + if (!tryGetProperty(key, intValue)) { + return false; + } + + outValue = intValue; + return true; +} + +bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + int value = strtol(stringValue.string(), & end, 10); + if (*end != '\0') { + LOGW("Property key '%s' has invalid value '%s'. Expected an integer.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + +bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + float value = strtof(stringValue.string(), & end); + if (*end != '\0') { + LOGW("Property key '%s' has invalid value '%s'. Expected a float.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + +status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) { + *outMap = NULL; + + Tokenizer* tokenizer; + status_t status = Tokenizer::open(filename, &tokenizer); + if (status) { + LOGE("Error %d opening property file %s.", status, filename.string()); + } else { + PropertyMap* map = new PropertyMap(); + if (!map) { + LOGE("Error allocating property 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; + LOGD("Parsed property 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; +} + + +// --- PropertyMap::Parser --- + +PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) : + mMap(map), mTokenizer(tokenizer) { +} + +PropertyMap::Parser::~Parser() { +} + +status_t PropertyMap::Parser::parse() { + while (!mTokenizer->isEof()) { +#if DEBUG_PARSER + LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), + mTokenizer->peekRemainderOfLine().string()); +#endif + + mTokenizer->skipDelimiters(WHITESPACE); + + if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { + String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); + if (keyToken.isEmpty()) { + LOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + + if (mTokenizer->nextChar() != '=') { + LOGE("%s: Expected '=' between property key and value.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + + String8 valueToken = mTokenizer->nextToken(WHITESPACE); + if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { + LOGE("%s: Found reserved character '\\' or '\"' in property value.", + mTokenizer->getLocation().string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + if (!mTokenizer->isEol()) { + LOGE("%s: Expected end of line, got '%s'.", + mTokenizer->getLocation().string(), + mTokenizer->peekRemainderOfLine().string()); + return BAD_VALUE; + } + + if (mMap->hasProperty(keyToken)) { + LOGE("%s: Duplicate property value for key '%s'.", + mTokenizer->getLocation().string(), keyToken.string()); + return BAD_VALUE; + } + + mMap->addProperty(keyToken, valueToken); + } + + mTokenizer->nextLine(); + } + return NO_ERROR; +} + +} // namespace android diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp index e531a2a..0bc5aff 100644 --- a/libs/utils/String8.cpp +++ b/libs/utils/String8.cpp @@ -195,6 +195,24 @@ String8::~String8() SharedBuffer::bufferFromData(mString)->release(); } +String8 String8::format(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + + String8 result(formatV(fmt, args)); + + va_end(args); + return result; +} + +String8 String8::formatV(const char* fmt, va_list args) +{ + String8 result; + result.appendFormatV(fmt, args); + return result; +} + void String8::clear() { SharedBuffer::bufferFromData(mString)->release(); mString = getEmptyString(); diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp index 9251973..b3445b7 100644 --- a/libs/utils/Tokenizer.cpp +++ b/libs/utils/Tokenizer.cpp @@ -35,16 +35,16 @@ static inline bool isDelimiter(char ch, const char* delimiters) { return strchr(delimiters, ch) != NULL; } - -Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, - const char* buffer, size_t length) : - mFilename(filename), mFileMap(fileMap), mBuffer(buffer), mLength(length), - mCurrent(buffer), mLineNumber(1) { +Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) : + mFilename(filename), mFileMap(fileMap), + mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) { } Tokenizer::~Tokenizer() { if (mFileMap) { mFileMap->release(); + } else { + delete[] mBuffer; } } @@ -63,22 +63,33 @@ status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { LOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); } else { size_t length = size_t(stat.st_size); + FileMap* fileMap = new FileMap(); - if (!fileMap->create(NULL, fd, 0, length, true)) { - result = NO_MEMORY; - LOGE("Error mapping file '%s', %s.", filename.string(), strerror(errno)); - } else { + char* buffer; + if (fileMap->create(NULL, fd, 0, length, true)) { fileMap->advise(FileMap::SEQUENTIAL); - - *outTokenizer = new Tokenizer(filename, fileMap, - static_cast<const char*>(fileMap->getDataPtr()), length); - if (!*outTokenizer) { - result = NO_MEMORY; - LOGE("Error allocating tokenizer for file=%s.", filename.string()); + buffer = static_cast<char*>(fileMap->getDataPtr()); + } else { + fileMap->release(); + fileMap = NULL; + + // Fall back to reading into a buffer since we can't mmap files in sysfs. + // The length we obtained from stat is wrong too (it will always be 4096) + // so we must trust that read will read the entire file. + buffer = new char[length]; + ssize_t nrd = read(fd, buffer, length); + if (nrd < 0) { + result = -errno; + LOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); + delete[] buffer; + buffer = NULL; + } else { + length = size_t(nrd); } } - if (result) { - fileMap->release(); + + if (!result) { + *outTokenizer = new Tokenizer(filename, fileMap, buffer, length); } } close(fd); |