diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/audioflinger/AudioFlinger.cpp | 102 | ||||
-rw-r--r-- | libs/audioflinger/AudioFlinger.h | 9 | ||||
-rw-r--r-- | libs/binder/IPermissionController.cpp | 8 | ||||
-rw-r--r-- | libs/binder/IServiceManager.cpp | 2 | ||||
-rw-r--r-- | libs/binder/Parcel.cpp | 11 | ||||
-rw-r--r-- | libs/surfaceflinger/TextureManager.cpp | 2 | ||||
-rw-r--r-- | libs/ui/Android.mk | 11 | ||||
-rw-r--r-- | libs/ui/EventHub.cpp | 124 | ||||
-rw-r--r-- | libs/ui/Input.cpp | 80 | ||||
-rw-r--r-- | libs/ui/InputDevice.cpp | 729 | ||||
-rw-r--r-- | libs/ui/InputDispatcher.cpp | 8 | ||||
-rw-r--r-- | libs/ui/InputReader.cpp | 716 | ||||
-rw-r--r-- | libs/ui/InputTransport.cpp | 19 | ||||
-rw-r--r-- | libs/ui/PixelFormat.cpp | 1 | ||||
-rw-r--r-- | libs/ui/tests/InputPublisherAndConsumer_test.cpp | 2 | ||||
-rw-r--r-- | libs/utils/Android.mk | 10 |
16 files changed, 980 insertions, 854 deletions
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index e6f46ce..97eb6c0 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -17,8 +17,7 @@ #define LOG_TAG "AudioFlinger" -// -#define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #include <math.h> #include <signal.h> @@ -5085,15 +5084,53 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle) } } +void AudioFlinger::EffectModule::updateState() { + Mutex::Autolock _l(mLock); + + switch (mState) { + case RESTART: + reset_l(); + // FALL THROUGH + + case STARTING: + // clear auxiliary effect input buffer for next accumulation + if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { + memset(mConfig.inputCfg.buffer.raw, + 0, + mConfig.inputCfg.buffer.frameCount*sizeof(int32_t)); + } + start_l(); + mState = ACTIVE; + break; + case STOPPING: + stop_l(); + mDisableWaitCnt = mMaxDisableWaitCnt; + mState = STOPPED; + break; + case STOPPED: + // mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the + // turn off sequence. + if (--mDisableWaitCnt == 0) { + reset_l(); + mState = IDLE; + } + break; + default: //IDLE , ACTIVE + break; + } +} + void AudioFlinger::EffectModule::process() { Mutex::Autolock _l(mLock); - if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) { + if (mEffectInterface == NULL || + mConfig.inputCfg.buffer.raw == NULL || + mConfig.outputCfg.buffer.raw == NULL) { return; } - if (mState != IDLE) { + if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) { // do 32 bit to 16 bit conversion for auxiliary effect input buffer if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32, @@ -5101,33 +5138,15 @@ void AudioFlinger::EffectModule::process() mConfig.inputCfg.buffer.frameCount); } - // TODO: handle effects with buffer provider - if (mState != ACTIVE) { - switch (mState) { - case RESET: - reset_l(); - mState = STARTING; - // clear auxiliary effect input buffer for next accumulation - if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t)); - } - return; - case STARTING: - start_l(); - mState = ACTIVE; - break; - case STOPPING: - mState = STOPPED; - break; - case STOPPED: - stop_l(); - mState = IDLE; - return; - } - } - // do the actual processing in the effect engine - (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer); + int ret = (*mEffectInterface)->process(mEffectInterface, + &mConfig.inputCfg.buffer, + &mConfig.outputCfg.buffer); + + // force transition to IDLE state when engine is ready + if (mState == STOPPED && ret == -ENODATA) { + mDisableWaitCnt = 1; + } // clear auxiliary effect input buffer for next accumulation if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { @@ -5216,6 +5235,10 @@ status_t AudioFlinger::EffectModule::configure() if (status == 0) { status = cmdStatus; } + + mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) / + (1000 * mConfig.outputCfg.buffer.frameCount); + return status; } @@ -5292,21 +5315,19 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled) switch (mState) { // going from disabled to enabled case IDLE: - mState = RESET; + mState = STARTING; + break; + case STOPPED: + mState = RESTART; break; case STOPPING: mState = ACTIVE; break; - case STOPPED: - mState = STARTING; - break; // going from enabled to disabled - case RESET: - mState = IDLE; - break; + case RESTART: case STARTING: - mState = STOPPED; + mState = IDLE; break; case ACTIVE: mState = STOPPING; @@ -5325,7 +5346,7 @@ status_t AudioFlinger::EffectModule::setEnabled(bool enabled) bool AudioFlinger::EffectModule::isEnabled() { switch (mState) { - case RESET: + case RESTART: case STARTING: case ACTIVE: return true; @@ -5772,6 +5793,9 @@ void AudioFlinger::EffectChain::process_l() for (size_t i = 0; i < size; i++) { mEffects[i]->process(); } + for (size_t i = 0; i < size; i++) { + mEffects[i]->updateState(); + } // if no track is active, input buffer must be cleared here as the mixer process // will not do it if (mSessionId > 0 && activeTracks() == 0) { diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h index ec3d7f1..507c9ac 100644 --- a/libs/audioflinger/AudioFlinger.h +++ b/libs/audioflinger/AudioFlinger.h @@ -905,7 +905,7 @@ private: enum effect_state { IDLE, - RESET, + RESTART, STARTING, ACTIVE, STOPPING, @@ -914,6 +914,7 @@ private: int id() { return mId; } void process(); + void updateState(); status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData); void reset_l(); @@ -948,6 +949,9 @@ private: protected: + // Maximum time allocated to effect engines to complete the turn off sequence + static const uint32_t MAX_DISABLE_TIME_MS = 10000; + EffectModule(const EffectModule&); EffectModule& operator = (const EffectModule&); @@ -973,6 +977,9 @@ private: status_t mStatus; // initialization status uint32_t mState; // current activation state (effect_state) Vector< wp<EffectHandle> > mHandles; // list of client handles + uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after + // sending disable command. + uint32_t mDisableWaitCnt; // current process() calls count during disable period. }; // The EffectHandle class implements the IEffect interface. It provides resources diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index bff4c9b..e13036f 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -36,7 +36,7 @@ public: : BpInterface<IPermissionController>(impl) { } - + virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) { Parcel data, reply; @@ -46,7 +46,7 @@ public: data.writeInt32(uid); remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply); // fail on exception - if (reply.readInt32() != 0) return 0; + if (reply.readExceptionCode() != 0) return 0; return reply.readInt32() != 0; } }; @@ -66,8 +66,7 @@ status_t BnPermissionController::onTransact( int32_t pid = data.readInt32(); int32_t uid = data.readInt32(); bool res = checkPermission(permission, pid, uid); - // write exception - reply->writeInt32(0); + reply->writeNoException(); reply->writeInt32(res ? 1 : 0); return NO_ERROR; } break; @@ -77,4 +76,3 @@ status_t BnPermissionController::onTransact( } }; // namespace android - diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index a3a3f0e..1fa4c35 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -158,7 +158,7 @@ public: data.writeString16(name); data.writeStrongBinder(service); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readInt32() : err; + return err == NO_ERROR ? reply.readExceptionCode() : err; } virtual Vector<String16> listServices() diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index c2574bd..47be1bf 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -754,6 +754,11 @@ restart_write: goto restart_write; } +status_t Parcel::writeNoException() +{ + return writeInt32(0); +} + void Parcel::remove(size_t start, size_t amt) { LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!"); @@ -942,6 +947,12 @@ wp<IBinder> Parcel::readWeakBinder() const return val; } +int32_t Parcel::readExceptionCode() const +{ + int32_t exception_code = readAligned<int32_t>(); + // TODO: skip over the response header here, once that's in. + return exception_code; +} native_handle* Parcel::readNativeHandle() const { diff --git a/libs/surfaceflinger/TextureManager.cpp b/libs/surfaceflinger/TextureManager.cpp index 6526032..3b326df 100644 --- a/libs/surfaceflinger/TextureManager.cpp +++ b/libs/surfaceflinger/TextureManager.cpp @@ -107,7 +107,6 @@ bool TextureManager::isSupportedYuvFormat(int format) { switch (format) { case HAL_PIXEL_FORMAT_YV12: - case HAL_PIXEL_FORMAT_YV16: return true; } return false; @@ -118,7 +117,6 @@ bool TextureManager::isYuvFormat(int format) switch (format) { // supported YUV formats case HAL_PIXEL_FORMAT_YV12: - case HAL_PIXEL_FORMAT_YV16: // Legacy/deprecated YUV formats case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index 24cdc78..4243bbf 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -12,6 +12,7 @@ LOCAL_SRC_FILES:= \ KeyLayoutMap.cpp \ KeyCharacterMap.cpp \ Input.cpp \ + InputDevice.cpp \ InputDispatcher.cpp \ InputManager.cpp \ InputReader.cpp \ @@ -38,3 +39,13 @@ ifeq ($(TARGET_SIMULATOR),true) endif include $(BUILD_SHARED_LIBRARY) + + +# Include subdirectory makefiles +# ============================================================ + +# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework +# team really wants is to build the stuff defined by this makefile. +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 27895f2..768b04e 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -54,6 +54,9 @@ */ #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) +/* 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 @@ -182,7 +185,7 @@ int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t deviceClasses, } int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const { - uint8_t key_bitmask[(KEY_MAX + 7) / 8]; + uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { @@ -218,7 +221,7 @@ int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const Vector<int32_t> scanCodes; device->layoutMap->findScancodes(keyCode, &scanCodes); - uint8_t key_bitmask[(KEY_MAX + 7) / 8]; + uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) { @@ -264,7 +267,7 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_ } int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const { - uint8_t sw_bitmask[(SW_MAX + 7) / 8]; + uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(mFDs[id_to_index(device->id)].fd, EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) { @@ -409,7 +412,7 @@ bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType, LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n", iev.code, *outKeycode, *outFlags, err); if (err != 0) { - *outKeycode = 0; + *outKeycode = AKEYCODE_UNKNOWN; *outFlags = 0; } } else { @@ -509,6 +512,26 @@ bool EventHub::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFla // ---------------------------------------------------------------------------- +static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { + const uint8_t* end = array + endIndex; + array += startIndex; + while (array != end) { + if (*(array++) != 0) { + return true; + } + } + return false; +} + +static const int32_t GAMEPAD_KEYCODES[] = { + AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, + AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, + AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, + AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, + AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, + AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE +}; + int EventHub::open_device(const char *deviceName) { int version; @@ -626,27 +649,27 @@ int EventHub::open_device(const char *deviceName) mFDs[mFDCount].fd = fd; mFDs[mFDCount].events = POLLIN; - // figure out the kinds of events the device reports + // Figure out the kinds of events the device reports. - // See if this is a keyboard, and classify it. Note that we only - // consider up through the function keys; we don't want to include - // ones after that (play cd etc) so we don't mistakenly consider a - // controller to be a keyboard. - uint8_t key_bitmask[(KEY_MAX+7)/8]; + uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)]; memset(key_bitmask, 0, sizeof(key_bitmask)); + LOGV("Getting keys..."); if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) { //LOGI("MAP\n"); - //for (int i=0; i<((KEY_MAX+7)/8); i++) { + //for (int i = 0; i < sizeof(key_bitmask); i++) { // LOGI("%d: 0x%02x\n", i, key_bitmask[i]); //} - for (int i=0; i<((BTN_MISC+7)/8); i++) { - if (key_bitmask[i] != 0) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - break; - } - } - if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) { + + // See if this is a keyboard. Ignore everything in the button range except for + // gamepads which are also considered keyboards. + if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) + || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD), + sizeof_bit_array(BTN_DIGI)) + || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK), + sizeof_bit_array(KEY_MAX + 1))) { + device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; + device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; if (device->keyBitmask != NULL) { memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); @@ -658,39 +681,39 @@ int EventHub::open_device(const char *deviceName) } } - // See if this is a trackball. + // See if this is a trackball (or mouse). if (test_bit(BTN_MOUSE, key_bitmask)) { - uint8_t rel_bitmask[(REL_MAX+7)/8]; + uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)]; memset(rel_bitmask, 0, sizeof(rel_bitmask)); LOGV("Getting relative controllers..."); - if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) - { + if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) { if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) { device->classes |= INPUT_DEVICE_CLASS_TRACKBALL; } } } - - uint8_t abs_bitmask[(ABS_MAX+7)/8]; + + // See if this is a touch pad. + uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)]; memset(abs_bitmask, 0, sizeof(abs_bitmask)); LOGV("Getting absolute controllers..."); - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask); - - // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) - && test_bit(ABS_MT_POSITION_X, abs_bitmask) - && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; - - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, key_bitmask) - && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN; + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { + // Is this a new modern multi-touch driver? + if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) + && test_bit(ABS_MT_POSITION_X, abs_bitmask) + && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { + device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; + + // Is this an old style single-touch driver? + } else if (test_bit(BTN_TOUCH, key_bitmask) + && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { + device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN; + } } #ifdef EV_SW // figure out the switches this device reports - uint8_t sw_bitmask[(SW_MAX+7)/8]; + uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)]; memset(sw_bitmask, 0, sizeof(sw_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) { for (int i=0; i<EV_SW; i++) { @@ -726,7 +749,10 @@ int EventHub::open_device(const char *deviceName) "%s/usr/keylayout/%s", root, "qwerty.kl"); defaultKeymap = true; } - device->layoutMap->load(keylayoutFilename); + status_t status = device->layoutMap->load(keylayoutFilename); + if (status) { + LOGE("Error %d loading key layout.", status); + } // tell the world about the devname (the descriptive name) if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) { @@ -746,19 +772,27 @@ int EventHub::open_device(const char *deviceName) property_set(propName, name); // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (hasKeycode(device, kKeyCodeQ)) { + if (hasKeycode(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } - // See if this has a DPAD. - if (hasKeycode(device, kKeyCodeDpadUp) && - hasKeycode(device, kKeyCodeDpadDown) && - hasKeycode(device, kKeyCodeDpadLeft) && - hasKeycode(device, kKeyCodeDpadRight) && - hasKeycode(device, kKeyCodeDpadCenter)) { + // See if this device has a DPAD. + if (hasKeycode(device, AKEYCODE_DPAD_UP) && + hasKeycode(device, AKEYCODE_DPAD_DOWN) && + hasKeycode(device, AKEYCODE_DPAD_LEFT) && + hasKeycode(device, AKEYCODE_DPAD_RIGHT) && + hasKeycode(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } + // See if this device has a gamepad. + for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) { + if (hasKeycode(device, GAMEPAD_KEYCODES[i])) { + device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; + break; + } + } + LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n", device->id, name, propName, keylayoutFilename); } diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index a64251f..1f19c2c 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -22,26 +22,26 @@ void InputEvent::initialize(int32_t deviceId, int32_t nature) { bool KeyEvent::hasDefaultAction(int32_t keyCode) { switch (keyCode) { - case KEYCODE_HOME: - case KEYCODE_BACK: - case KEYCODE_CALL: - case KEYCODE_ENDCALL: - case KEYCODE_VOLUME_UP: - case KEYCODE_VOLUME_DOWN: - case KEYCODE_POWER: - case KEYCODE_CAMERA: - case KEYCODE_HEADSETHOOK: - case KEYCODE_MENU: - case KEYCODE_NOTIFICATION: - case KEYCODE_FOCUS: - case KEYCODE_SEARCH: - case KEYCODE_MEDIA_PLAY_PAUSE: - case KEYCODE_MEDIA_STOP: - case KEYCODE_MEDIA_NEXT: - case KEYCODE_MEDIA_PREVIOUS: - case KEYCODE_MEDIA_REWIND: - case KEYCODE_MEDIA_FAST_FORWARD: - case KEYCODE_MUTE: + case AKEYCODE_HOME: + case AKEYCODE_BACK: + case AKEYCODE_CALL: + case AKEYCODE_ENDCALL: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_POWER: + case AKEYCODE_CAMERA: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MENU: + case AKEYCODE_NOTIFICATION: + case AKEYCODE_FOCUS: + case AKEYCODE_SEARCH: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_MUTE: return true; } @@ -54,26 +54,26 @@ bool KeyEvent::hasDefaultAction() const { bool KeyEvent::isSystemKey(int32_t keyCode) { switch (keyCode) { - case KEYCODE_MENU: - case KEYCODE_SOFT_RIGHT: - case KEYCODE_HOME: - case KEYCODE_BACK: - case KEYCODE_CALL: - case KEYCODE_ENDCALL: - case KEYCODE_VOLUME_UP: - case KEYCODE_VOLUME_DOWN: - case KEYCODE_MUTE: - case KEYCODE_POWER: - case KEYCODE_HEADSETHOOK: - case KEYCODE_MEDIA_PLAY_PAUSE: - case KEYCODE_MEDIA_STOP: - case KEYCODE_MEDIA_NEXT: - case KEYCODE_MEDIA_PREVIOUS: - case KEYCODE_MEDIA_REWIND: - case KEYCODE_MEDIA_FAST_FORWARD: - case KEYCODE_CAMERA: - case KEYCODE_FOCUS: - case KEYCODE_SEARCH: + case AKEYCODE_MENU: + case AKEYCODE_SOFT_RIGHT: + case AKEYCODE_HOME: + case AKEYCODE_BACK: + case AKEYCODE_CALL: + case AKEYCODE_ENDCALL: + case AKEYCODE_VOLUME_UP: + case AKEYCODE_VOLUME_DOWN: + case AKEYCODE_MUTE: + case AKEYCODE_POWER: + case AKEYCODE_HEADSETHOOK: + case AKEYCODE_MEDIA_PLAY_PAUSE: + case AKEYCODE_MEDIA_STOP: + case AKEYCODE_MEDIA_NEXT: + case AKEYCODE_MEDIA_PREVIOUS: + case AKEYCODE_MEDIA_REWIND: + case AKEYCODE_MEDIA_FAST_FORWARD: + case AKEYCODE_CAMERA: + case AKEYCODE_FOCUS: + case AKEYCODE_SEARCH: return true; } diff --git a/libs/ui/InputDevice.cpp b/libs/ui/InputDevice.cpp new file mode 100644 index 0000000..6014017 --- /dev/null +++ b/libs/ui/InputDevice.cpp @@ -0,0 +1,729 @@ +// +// Copyright 2010 The Android Open Source Project +// +// The input reader. +// +#define LOG_TAG "InputDevice" + +//#define LOG_NDEBUG 0 + +// Log debug messages for each raw event received from the EventHub. +#define DEBUG_RAW_EVENTS 0 + +// Log debug messages about touch screen filtering hacks. +#define DEBUG_HACKS 0 + +// Log debug messages about virtual key processing. +#define DEBUG_VIRTUAL_KEYS 0 + +// Log debug messages about pointers. +#define DEBUG_POINTERS 0 + +// Log debug messages about pointer assignment calculations. +#define DEBUG_POINTER_ASSIGNMENT 0 + +#include <cutils/log.h> +#include <ui/InputDevice.h> + +#include <stddef.h> +#include <unistd.h> +#include <errno.h> +#include <limits.h> + +/* Slop distance for jumpy pointer detection. + * The vertical range of the screen divided by this is our epsilon value. */ +#define JUMPY_EPSILON_DIVISOR 212 + +/* Number of jumpy points to drop for touchscreens that need it. */ +#define JUMPY_TRANSITION_DROPS 3 +#define JUMPY_DROP_LIMIT 3 + +/* Maximum squared distance for averaging. + * If moving farther than this, turn of averaging to avoid lag in response. */ +#define AVERAGING_DISTANCE_LIMIT (75 * 75) + + +namespace android { + +// --- Static Functions --- + +template<typename T> +inline static T abs(const T& value) { + return value < 0 ? - value : value; +} + +template<typename T> +inline static T min(const T& a, const T& b) { + return a < b ? a : b; +} + +template<typename T> +inline static void swap(T& a, T& b) { + T temp = a; + a = b; + b = temp; +} + + +// --- InputDevice --- + +InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) : + id(id), classes(classes), name(name), ignored(false) { +} + +void InputDevice::reset() { + if (isKeyboard()) { + keyboard.reset(); + } + + if (isTrackball()) { + trackball.reset(); + } + + if (isMultiTouchScreen()) { + multiTouchScreen.reset(); + } else if (isSingleTouchScreen()) { + singleTouchScreen.reset(); + } + + if (isTouchScreen()) { + touchScreen.reset(); + } +} + + +// --- InputDevice::TouchData --- + +void InputDevice::TouchData::copyFrom(const TouchData& other) { + pointerCount = other.pointerCount; + idBits = other.idBits; + + for (uint32_t i = 0; i < pointerCount; i++) { + pointers[i] = other.pointers[i]; + idToIndex[i] = other.idToIndex[i]; + } +} + + +// --- InputDevice::KeyboardState --- + +void InputDevice::KeyboardState::reset() { + current.metaState = META_NONE; + current.downTime = 0; +} + + +// --- InputDevice::TrackballState --- + +void InputDevice::TrackballState::reset() { + accumulator.clear(); + current.down = false; + current.downTime = 0; +} + + +// --- InputDevice::TouchScreenState --- + +void InputDevice::TouchScreenState::reset() { + lastTouch.clear(); + downTime = 0; + currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP; + + for (uint32_t i = 0; i < MAX_POINTERS; i++) { + averagingTouchFilter.historyStart[i] = 0; + averagingTouchFilter.historyEnd[i] = 0; + } + + jumpyTouchFilter.jumpyPointsDropped = 0; +} + +struct PointerDistanceHeapElement { + uint32_t currentPointerIndex : 8; + uint32_t lastPointerIndex : 8; + uint64_t distance : 48; // squared distance +}; + +void InputDevice::TouchScreenState::calculatePointerIds() { + uint32_t currentPointerCount = currentTouch.pointerCount; + uint32_t lastPointerCount = lastTouch.pointerCount; + + if (currentPointerCount == 0) { + // No pointers to assign. + currentTouch.idBits.clear(); + } else if (lastPointerCount == 0) { + // All pointers are new. + currentTouch.idBits.clear(); + for (uint32_t i = 0; i < currentPointerCount; i++) { + currentTouch.pointers[i].id = i; + currentTouch.idToIndex[i] = i; + currentTouch.idBits.markBit(i); + } + } else if (currentPointerCount == 1 && lastPointerCount == 1) { + // Only one pointer and no change in count so it must have the same id as before. + uint32_t id = lastTouch.pointers[0].id; + currentTouch.pointers[0].id = id; + currentTouch.idToIndex[id] = 0; + currentTouch.idBits.value = BitSet32::valueForBit(id); + } else { + // General case. + // We build a heap of squared euclidean distances between current and last pointers + // associated with the current and last pointer indices. Then, we find the best + // match (by distance) for each current pointer. + PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; + + uint32_t heapSize = 0; + for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; + currentPointerIndex++) { + for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; + lastPointerIndex++) { + int64_t deltaX = currentTouch.pointers[currentPointerIndex].x + - lastTouch.pointers[lastPointerIndex].x; + int64_t deltaY = currentTouch.pointers[currentPointerIndex].y + - lastTouch.pointers[lastPointerIndex].y; + + uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); + + // Insert new element into the heap (sift up). + heap[heapSize].currentPointerIndex = currentPointerIndex; + heap[heapSize].lastPointerIndex = lastPointerIndex; + heap[heapSize].distance = distance; + heapSize += 1; + } + } + + // Heapify + for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { + startIndex -= 1; + for (uint32_t parentIndex = startIndex; ;) { + uint32_t childIndex = parentIndex * 2 + 1; + if (childIndex >= heapSize) { + break; + } + + if (childIndex + 1 < heapSize + && heap[childIndex + 1].distance < heap[childIndex].distance) { + childIndex += 1; + } + + if (heap[parentIndex].distance <= heap[childIndex].distance) { + break; + } + + swap(heap[parentIndex], heap[childIndex]); + parentIndex = childIndex; + } + } + +#if DEBUG_POINTER_ASSIGNMENT + LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize); + for (size_t i = 0; i < heapSize; i++) { + LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", + i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, + heap[i].distance); + } +#endif + + // Pull matches out by increasing order of distance. + // To avoid reassigning pointers that have already been matched, the loop keeps track + // of which last and current pointers have been matched using the matchedXXXBits variables. + // It also tracks the used pointer id bits. + BitSet32 matchedLastBits(0); + BitSet32 matchedCurrentBits(0); + BitSet32 usedIdBits(0); + bool first = true; + for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) { + for (;;) { + if (first) { + // The first time through the loop, we just consume the root element of + // the heap (the one with smallest distance). + first = false; + } else { + // Previous iterations consumed the root element of the heap. + // Pop root element off of the heap (sift down). + heapSize -= 1; + assert(heapSize > 0); + + // Sift down. + heap[0] = heap[heapSize]; + for (uint32_t parentIndex = 0; ;) { + uint32_t childIndex = parentIndex * 2 + 1; + if (childIndex >= heapSize) { + break; + } + + if (childIndex + 1 < heapSize + && heap[childIndex + 1].distance < heap[childIndex].distance) { + childIndex += 1; + } + + if (heap[parentIndex].distance <= heap[childIndex].distance) { + break; + } + + swap(heap[parentIndex], heap[childIndex]); + parentIndex = childIndex; + } + +#if DEBUG_POINTER_ASSIGNMENT + LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize); + for (size_t i = 0; i < heapSize; i++) { + LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", + i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, + heap[i].distance); + } +#endif + } + + uint32_t currentPointerIndex = heap[0].currentPointerIndex; + if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched + + uint32_t lastPointerIndex = heap[0].lastPointerIndex; + if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched + + matchedCurrentBits.markBit(currentPointerIndex); + matchedLastBits.markBit(lastPointerIndex); + + uint32_t id = lastTouch.pointers[lastPointerIndex].id; + currentTouch.pointers[currentPointerIndex].id = id; + currentTouch.idToIndex[id] = currentPointerIndex; + usedIdBits.markBit(id); + +#if DEBUG_POINTER_ASSIGNMENT + LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", + lastPointerIndex, currentPointerIndex, id, heap[0].distance); +#endif + break; + } + } + + // Assign fresh ids to new pointers. + if (currentPointerCount > lastPointerCount) { + for (uint32_t i = currentPointerCount - lastPointerCount; ;) { + uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit(); + uint32_t id = usedIdBits.firstUnmarkedBit(); + + currentTouch.pointers[currentPointerIndex].id = id; + currentTouch.idToIndex[id] = currentPointerIndex; + usedIdBits.markBit(id); + +#if DEBUG_POINTER_ASSIGNMENT + LOGD("calculatePointerIds - assigned: cur=%d, id=%d", + currentPointerIndex, id); +#endif + + if (--i == 0) break; // done + matchedCurrentBits.markBit(currentPointerIndex); + } + } + + // Fix id bits. + currentTouch.idBits = usedIdBits; + } +} + +/* Special hack for devices that have bad screen data: if one of the + * points has moved more than a screen height from the last position, + * then drop it. */ +bool InputDevice::TouchScreenState::applyBadTouchFilter() { + // This hack requires valid axis parameters. + if (! parameters.yAxis.valid) { + return false; + } + + uint32_t pointerCount = currentTouch.pointerCount; + + // Nothing to do if there are no points. + if (pointerCount == 0) { + return false; + } + + // Don't do anything if a finger is going down or up. We run + // here before assigning pointer IDs, so there isn't a good + // way to do per-finger matching. + if (pointerCount != lastTouch.pointerCount) { + return false; + } + + // We consider a single movement across more than a 7/16 of + // the long size of the screen to be bad. This was a magic value + // determined by looking at the maximum distance it is feasible + // to actually move in one sample. + int32_t maxDeltaY = parameters.yAxis.range * 7 / 16; + + // XXX The original code in InputDevice.java included commented out + // code for testing the X axis. Note that when we drop a point + // we don't actually restore the old X either. Strange. + // The old code also tries to track when bad points were previously + // detected but it turns out that due to the placement of a "break" + // at the end of the loop, we never set mDroppedBadPoint to true + // so it is effectively dead code. + // Need to figure out if the old code is busted or just overcomplicated + // but working as intended. + + // Look through all new points and see if any are farther than + // acceptable from all previous points. + for (uint32_t i = pointerCount; i-- > 0; ) { + int32_t y = currentTouch.pointers[i].y; + int32_t closestY = INT_MAX; + int32_t closestDeltaY = 0; + +#if DEBUG_HACKS + LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y); +#endif + + for (uint32_t j = pointerCount; j-- > 0; ) { + int32_t lastY = lastTouch.pointers[j].y; + int32_t deltaY = abs(y - lastY); + +#if DEBUG_HACKS + LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d", + j, lastY, deltaY); +#endif + + if (deltaY < maxDeltaY) { + goto SkipSufficientlyClosePoint; + } + if (deltaY < closestDeltaY) { + closestDeltaY = deltaY; + closestY = lastY; + } + } + + // Must not have found a close enough match. +#if DEBUG_HACKS + LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d", + i, y, closestY, closestDeltaY, maxDeltaY); +#endif + + currentTouch.pointers[i].y = closestY; + return true; // XXX original code only corrects one point + + SkipSufficientlyClosePoint: ; + } + + // No change. + return false; +} + +/* Special hack for devices that have bad screen data: drop points where + * the coordinate value for one axis has jumped to the other pointer's location. + */ +bool InputDevice::TouchScreenState::applyJumpyTouchFilter() { + // This hack requires valid axis parameters. + if (! parameters.yAxis.valid) { + return false; + } + + uint32_t pointerCount = currentTouch.pointerCount; + if (lastTouch.pointerCount != pointerCount) { +#if DEBUG_HACKS + LOGD("JumpyTouchFilter: Different pointer count %d -> %d", + lastTouch.pointerCount, pointerCount); + for (uint32_t i = 0; i < pointerCount; i++) { + LOGD(" Pointer %d (%d, %d)", i, + currentTouch.pointers[i].x, currentTouch.pointers[i].y); + } +#endif + + if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) { + if (lastTouch.pointerCount == 1 && pointerCount == 2) { + // Just drop the first few events going from 1 to 2 pointers. + // They're bad often enough that they're not worth considering. + currentTouch.pointerCount = 1; + jumpyTouchFilter.jumpyPointsDropped += 1; + +#if DEBUG_HACKS + LOGD("JumpyTouchFilter: Pointer 2 dropped"); +#endif + return true; + } else if (lastTouch.pointerCount == 2 && pointerCount == 1) { + // The event when we go from 2 -> 1 tends to be messed up too + currentTouch.pointerCount = 2; + currentTouch.pointers[0] = lastTouch.pointers[0]; + currentTouch.pointers[1] = lastTouch.pointers[1]; + jumpyTouchFilter.jumpyPointsDropped += 1; + +#if DEBUG_HACKS + for (int32_t i = 0; i < 2; i++) { + LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i, + currentTouch.pointers[i].x, currentTouch.pointers[i].y); + } +#endif + return true; + } + } + // Reset jumpy points dropped on other transitions or if limit exceeded. + jumpyTouchFilter.jumpyPointsDropped = 0; + +#if DEBUG_HACKS + LOGD("JumpyTouchFilter: Transition - drop limit reset"); +#endif + return false; + } + + // We have the same number of pointers as last time. + // A 'jumpy' point is one where the coordinate value for one axis + // has jumped to the other pointer's location. No need to do anything + // else if we only have one pointer. + if (pointerCount < 2) { + return false; + } + + if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) { + int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR; + + // We only replace the single worst jumpy point as characterized by pointer distance + // in a single axis. + int32_t badPointerIndex = -1; + int32_t badPointerReplacementIndex = -1; + int32_t badPointerDistance = INT_MIN; // distance to be corrected + + for (uint32_t i = pointerCount; i-- > 0; ) { + int32_t x = currentTouch.pointers[i].x; + int32_t y = currentTouch.pointers[i].y; + +#if DEBUG_HACKS + LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y); +#endif + + // Check if a touch point is too close to another's coordinates + bool dropX = false, dropY = false; + for (uint32_t j = 0; j < pointerCount; j++) { + if (i == j) { + continue; + } + + if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) { + dropX = true; + break; + } + + if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) { + dropY = true; + break; + } + } + if (! dropX && ! dropY) { + continue; // not jumpy + } + + // Find a replacement candidate by comparing with older points on the + // complementary (non-jumpy) axis. + int32_t distance = INT_MIN; // distance to be corrected + int32_t replacementIndex = -1; + + if (dropX) { + // X looks too close. Find an older replacement point with a close Y. + int32_t smallestDeltaY = INT_MAX; + for (uint32_t j = 0; j < pointerCount; j++) { + int32_t deltaY = abs(y - lastTouch.pointers[j].y); + if (deltaY < smallestDeltaY) { + smallestDeltaY = deltaY; + replacementIndex = j; + } + } + distance = abs(x - lastTouch.pointers[replacementIndex].x); + } else { + // Y looks too close. Find an older replacement point with a close X. + int32_t smallestDeltaX = INT_MAX; + for (uint32_t j = 0; j < pointerCount; j++) { + int32_t deltaX = abs(x - lastTouch.pointers[j].x); + if (deltaX < smallestDeltaX) { + smallestDeltaX = deltaX; + replacementIndex = j; + } + } + distance = abs(y - lastTouch.pointers[replacementIndex].y); + } + + // If replacing this pointer would correct a worse error than the previous ones + // considered, then use this replacement instead. + if (distance > badPointerDistance) { + badPointerIndex = i; + badPointerReplacementIndex = replacementIndex; + badPointerDistance = distance; + } + } + + // Correct the jumpy pointer if one was found. + if (badPointerIndex >= 0) { +#if DEBUG_HACKS + LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)", + badPointerIndex, + lastTouch.pointers[badPointerReplacementIndex].x, + lastTouch.pointers[badPointerReplacementIndex].y); +#endif + + currentTouch.pointers[badPointerIndex].x = + lastTouch.pointers[badPointerReplacementIndex].x; + currentTouch.pointers[badPointerIndex].y = + lastTouch.pointers[badPointerReplacementIndex].y; + jumpyTouchFilter.jumpyPointsDropped += 1; + return true; + } + } + + jumpyTouchFilter.jumpyPointsDropped = 0; + return false; +} + +/* Special hack for devices that have bad screen data: aggregate and + * compute averages of the coordinate data, to reduce the amount of + * jitter seen by applications. */ +void InputDevice::TouchScreenState::applyAveragingTouchFilter() { + for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) { + uint32_t id = currentTouch.pointers[currentIndex].id; + int32_t x = currentTouch.pointers[currentIndex].x; + int32_t y = currentTouch.pointers[currentIndex].y; + int32_t pressure = currentTouch.pointers[currentIndex].pressure; + + if (lastTouch.idBits.hasBit(id)) { + // Pointer was down before and is still down now. + // Compute average over history trace. + uint32_t start = averagingTouchFilter.historyStart[id]; + uint32_t end = averagingTouchFilter.historyEnd[id]; + + int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x; + int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y; + uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); + +#if DEBUG_HACKS + LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld", + id, distance); +#endif + + if (distance < AVERAGING_DISTANCE_LIMIT) { + // Increment end index in preparation for recording new historical data. + end += 1; + if (end > AVERAGING_HISTORY_SIZE) { + end = 0; + } + + // If the end index has looped back to the start index then we have filled + // the historical trace up to the desired size so we drop the historical + // data at the start of the trace. + if (end == start) { + start += 1; + if (start > AVERAGING_HISTORY_SIZE) { + start = 0; + } + } + + // Add the raw data to the historical trace. + averagingTouchFilter.historyStart[id] = start; + averagingTouchFilter.historyEnd[id] = end; + averagingTouchFilter.historyData[end].pointers[id].x = x; + averagingTouchFilter.historyData[end].pointers[id].y = y; + averagingTouchFilter.historyData[end].pointers[id].pressure = pressure; + + // Average over all historical positions in the trace by total pressure. + int32_t averagedX = 0; + int32_t averagedY = 0; + int32_t totalPressure = 0; + for (;;) { + int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x; + int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y; + int32_t historicalPressure = averagingTouchFilter.historyData[start] + .pointers[id].pressure; + + averagedX += historicalX * historicalPressure; + averagedY += historicalY * historicalPressure; + totalPressure += historicalPressure; + + if (start == end) { + break; + } + + start += 1; + if (start > AVERAGING_HISTORY_SIZE) { + start = 0; + } + } + + averagedX /= totalPressure; + averagedY /= totalPressure; + +#if DEBUG_HACKS + LOGD("AveragingTouchFilter: Pointer id %d - " + "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, + averagedX, averagedY); +#endif + + currentTouch.pointers[currentIndex].x = averagedX; + currentTouch.pointers[currentIndex].y = averagedY; + } else { +#if DEBUG_HACKS + LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id); +#endif + } + } else { +#if DEBUG_HACKS + LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id); +#endif + } + + // Reset pointer history. + averagingTouchFilter.historyStart[id] = 0; + averagingTouchFilter.historyEnd[id] = 0; + averagingTouchFilter.historyData[0].pointers[id].x = x; + averagingTouchFilter.historyData[0].pointers[id].y = y; + averagingTouchFilter.historyData[0].pointers[id].pressure = pressure; + } +} + +bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const { + if (! parameters.xAxis.valid || ! parameters.yAxis.valid) { + // Assume all points on a touch screen without valid axis parameters are + // inside the display. + return true; + } + + return x >= parameters.xAxis.minValue + && x <= parameters.xAxis.maxValue + && y >= parameters.yAxis.minValue + && y <= parameters.yAxis.maxValue; +} + +const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const { + int32_t x = currentTouch.pointers[0].x; + int32_t y = currentTouch.pointers[0].y; + for (size_t i = 0; i < virtualKeys.size(); i++) { + const InputDevice::VirtualKey& virtualKey = virtualKeys[i]; + +#if DEBUG_VIRTUAL_KEYS + LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " + "left=%d, top=%d, right=%d, bottom=%d", + x, y, + virtualKey.keyCode, virtualKey.scanCode, + virtualKey.hitLeft, virtualKey.hitTop, + virtualKey.hitRight, virtualKey.hitBottom); +#endif + + if (virtualKey.isHit(x, y)) { + return & virtualKey; + } + } + + return NULL; +} + + +// --- InputDevice::SingleTouchScreenState --- + +void InputDevice::SingleTouchScreenState::reset() { + accumulator.clear(); + current.down = false; + current.x = 0; + current.y = 0; + current.pressure = 0; + current.size = 0; +} + + +// --- InputDevice::MultiTouchScreenState --- + +void InputDevice::MultiTouchScreenState::reset() { + accumulator.clear(); +} + +} // namespace android diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index f809cba..c4ffce1 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -40,10 +40,10 @@ namespace android { // TODO, this needs to be somewhere else, perhaps in the policy static inline bool isMovementKey(int32_t keyCode) { - return keyCode == KEYCODE_DPAD_UP - || keyCode == KEYCODE_DPAD_DOWN - || keyCode == KEYCODE_DPAD_LEFT - || keyCode == KEYCODE_DPAD_RIGHT; + return keyCode == AKEYCODE_DPAD_UP + || keyCode == AKEYCODE_DPAD_DOWN + || keyCode == AKEYCODE_DPAD_LEFT + || keyCode == AKEYCODE_DPAD_RIGHT; } static inline nsecs_t now() { diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index fced15c..0a21db7 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -33,18 +33,6 @@ /** Amount that trackball needs to move in order to generate a key event. */ #define TRACKBALL_MOVEMENT_THRESHOLD 6 -/* Slop distance for jumpy pointer detection. - * The vertical range of the screen divided by this is our epsilon value. */ -#define JUMPY_EPSILON_DIVISOR 212 - -/* Number of jumpy points to drop for touchscreens that need it. */ -#define JUMPY_TRANSITION_DROPS 3 -#define JUMPY_DROP_LIMIT 3 - -/* Maximum squared distance for averaging. - * If moving farther than this, turn of averaging to avoid lag in response. */ -#define AVERAGING_DISTANCE_LIMIT (75 * 75) - namespace android { @@ -71,19 +59,19 @@ inline static void swap(T& a, T& b) { int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; switch (keyCode) { - case KEYCODE_ALT_LEFT: + case AKEYCODE_ALT_LEFT: mask = META_ALT_LEFT_ON; break; - case KEYCODE_ALT_RIGHT: + case AKEYCODE_ALT_RIGHT: mask = META_ALT_RIGHT_ON; break; - case KEYCODE_SHIFT_LEFT: + case AKEYCODE_SHIFT_LEFT: mask = META_SHIFT_LEFT_ON; break; - case KEYCODE_SHIFT_RIGHT: + case AKEYCODE_SHIFT_RIGHT: mask = META_SHIFT_RIGHT_ON; break; - case KEYCODE_SYM: + case AKEYCODE_SYM: mask = META_SYM_ON; break; default: @@ -107,10 +95,10 @@ int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { static const int32_t keyCodeRotationMap[][4] = { // key codes enumerated counter-clockwise with the original (unrotated) key first // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - { KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT }, - { KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN }, - { KEYCODE_DPAD_UP, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT }, - { KEYCODE_DPAD_LEFT, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_UP }, + { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, + { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, + { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, + { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, }; static const int keyCodeRotationMapSize = sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); @@ -127,668 +115,6 @@ int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { } -// --- InputDevice --- - -InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) : - id(id), classes(classes), name(name), ignored(false) { -} - -void InputDevice::reset() { - if (isKeyboard()) { - keyboard.reset(); - } - - if (isTrackball()) { - trackball.reset(); - } - - if (isMultiTouchScreen()) { - multiTouchScreen.reset(); - } else if (isSingleTouchScreen()) { - singleTouchScreen.reset(); - } - - if (isTouchScreen()) { - touchScreen.reset(); - } -} - - -// --- InputDevice::TouchData --- - -void InputDevice::TouchData::copyFrom(const TouchData& other) { - pointerCount = other.pointerCount; - idBits = other.idBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointers[i] = other.pointers[i]; - idToIndex[i] = other.idToIndex[i]; - } -} - - -// --- InputDevice::KeyboardState --- - -void InputDevice::KeyboardState::reset() { - current.metaState = META_NONE; - current.downTime = 0; -} - - -// --- InputDevice::TrackballState --- - -void InputDevice::TrackballState::reset() { - accumulator.clear(); - current.down = false; - current.downTime = 0; -} - - -// --- InputDevice::TouchScreenState --- - -void InputDevice::TouchScreenState::reset() { - lastTouch.clear(); - downTime = 0; - currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP; - - for (uint32_t i = 0; i < MAX_POINTERS; i++) { - averagingTouchFilter.historyStart[i] = 0; - averagingTouchFilter.historyEnd[i] = 0; - } - - jumpyTouchFilter.jumpyPointsDropped = 0; -} - -struct PointerDistanceHeapElement { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance -}; - -void InputDevice::TouchScreenState::calculatePointerIds() { - uint32_t currentPointerCount = currentTouch.pointerCount; - uint32_t lastPointerCount = lastTouch.pointerCount; - - if (currentPointerCount == 0) { - // No pointers to assign. - currentTouch.idBits.clear(); - } else if (lastPointerCount == 0) { - // All pointers are new. - currentTouch.idBits.clear(); - for (uint32_t i = 0; i < currentPointerCount; i++) { - currentTouch.pointers[i].id = i; - currentTouch.idToIndex[i] = i; - currentTouch.idBits.markBit(i); - } - } else if (currentPointerCount == 1 && lastPointerCount == 1) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = lastTouch.pointers[0].id; - currentTouch.pointers[0].id = id; - currentTouch.idToIndex[id] = 0; - currentTouch.idBits.value = BitSet32::valueForBit(id); - } else { - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - int64_t deltaX = currentTouch.pointers[currentPointerIndex].x - - lastTouch.pointers[lastPointerIndex].x; - int64_t deltaY = currentTouch.pointers[currentPointerIndex].y - - lastTouch.pointers[lastPointerIndex].y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) { - for (;;) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heapSize -= 1; - assert(heapSize > 0); - - // Sift down. - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - } - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = lastTouch.pointers[lastPointerIndex].id; - currentTouch.pointers[currentPointerIndex].id = id; - currentTouch.idToIndex[id] = currentPointerIndex; - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to new pointers. - if (currentPointerCount > lastPointerCount) { - for (uint32_t i = currentPointerCount - lastPointerCount; ;) { - uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit(); - uint32_t id = usedIdBits.firstUnmarkedBit(); - - currentTouch.pointers[currentPointerIndex].id = id; - currentTouch.idToIndex[id] = currentPointerIndex; - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - LOGD("calculatePointerIds - assigned: cur=%d, id=%d", - currentPointerIndex, id); -#endif - - if (--i == 0) break; // done - matchedCurrentBits.markBit(currentPointerIndex); - } - } - - // Fix id bits. - currentTouch.idBits = usedIdBits; - } -} - -/* Special hack for devices that have bad screen data: if one of the - * points has moved more than a screen height from the last position, - * then drop it. */ -bool InputDevice::TouchScreenState::applyBadTouchFilter() { - // This hack requires valid axis parameters. - if (! parameters.yAxis.valid) { - return false; - } - - uint32_t pointerCount = currentTouch.pointerCount; - - // Nothing to do if there are no points. - if (pointerCount == 0) { - return false; - } - - // Don't do anything if a finger is going down or up. We run - // here before assigning pointer IDs, so there isn't a good - // way to do per-finger matching. - if (pointerCount != lastTouch.pointerCount) { - return false; - } - - // We consider a single movement across more than a 7/16 of - // the long size of the screen to be bad. This was a magic value - // determined by looking at the maximum distance it is feasible - // to actually move in one sample. - int32_t maxDeltaY = parameters.yAxis.range * 7 / 16; - - // XXX The original code in InputDevice.java included commented out - // code for testing the X axis. Note that when we drop a point - // we don't actually restore the old X either. Strange. - // The old code also tries to track when bad points were previously - // detected but it turns out that due to the placement of a "break" - // at the end of the loop, we never set mDroppedBadPoint to true - // so it is effectively dead code. - // Need to figure out if the old code is busted or just overcomplicated - // but working as intended. - - // Look through all new points and see if any are farther than - // acceptable from all previous points. - for (uint32_t i = pointerCount; i-- > 0; ) { - int32_t y = currentTouch.pointers[i].y; - int32_t closestY = INT_MAX; - int32_t closestDeltaY = 0; - -#if DEBUG_HACKS - LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y); -#endif - - for (uint32_t j = pointerCount; j-- > 0; ) { - int32_t lastY = lastTouch.pointers[j].y; - int32_t deltaY = abs(y - lastY); - -#if DEBUG_HACKS - LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d", - j, lastY, deltaY); -#endif - - if (deltaY < maxDeltaY) { - goto SkipSufficientlyClosePoint; - } - if (deltaY < closestDeltaY) { - closestDeltaY = deltaY; - closestY = lastY; - } - } - - // Must not have found a close enough match. -#if DEBUG_HACKS - LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d", - i, y, closestY, closestDeltaY, maxDeltaY); -#endif - - currentTouch.pointers[i].y = closestY; - return true; // XXX original code only corrects one point - - SkipSufficientlyClosePoint: ; - } - - // No change. - return false; -} - -/* Special hack for devices that have bad screen data: drop points where - * the coordinate value for one axis has jumped to the other pointer's location. - */ -bool InputDevice::TouchScreenState::applyJumpyTouchFilter() { - // This hack requires valid axis parameters. - if (! parameters.yAxis.valid) { - return false; - } - - uint32_t pointerCount = currentTouch.pointerCount; - if (lastTouch.pointerCount != pointerCount) { -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Different pointer count %d -> %d", - lastTouch.pointerCount, pointerCount); - for (uint32_t i = 0; i < pointerCount; i++) { - LOGD(" Pointer %d (%d, %d)", i, - currentTouch.pointers[i].x, currentTouch.pointers[i].y); - } -#endif - - if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) { - if (lastTouch.pointerCount == 1 && pointerCount == 2) { - // Just drop the first few events going from 1 to 2 pointers. - // They're bad often enough that they're not worth considering. - currentTouch.pointerCount = 1; - jumpyTouchFilter.jumpyPointsDropped += 1; - -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Pointer 2 dropped"); -#endif - return true; - } else if (lastTouch.pointerCount == 2 && pointerCount == 1) { - // The event when we go from 2 -> 1 tends to be messed up too - currentTouch.pointerCount = 2; - currentTouch.pointers[0] = lastTouch.pointers[0]; - currentTouch.pointers[1] = lastTouch.pointers[1]; - jumpyTouchFilter.jumpyPointsDropped += 1; - -#if DEBUG_HACKS - for (int32_t i = 0; i < 2; i++) { - LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i, - currentTouch.pointers[i].x, currentTouch.pointers[i].y); - } -#endif - return true; - } - } - // Reset jumpy points dropped on other transitions or if limit exceeded. - jumpyTouchFilter.jumpyPointsDropped = 0; - -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Transition - drop limit reset"); -#endif - return false; - } - - // We have the same number of pointers as last time. - // A 'jumpy' point is one where the coordinate value for one axis - // has jumped to the other pointer's location. No need to do anything - // else if we only have one pointer. - if (pointerCount < 2) { - return false; - } - - if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) { - int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR; - - // We only replace the single worst jumpy point as characterized by pointer distance - // in a single axis. - int32_t badPointerIndex = -1; - int32_t badPointerReplacementIndex = -1; - int32_t badPointerDistance = INT_MIN; // distance to be corrected - - for (uint32_t i = pointerCount; i-- > 0; ) { - int32_t x = currentTouch.pointers[i].x; - int32_t y = currentTouch.pointers[i].y; - -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y); -#endif - - // Check if a touch point is too close to another's coordinates - bool dropX = false, dropY = false; - for (uint32_t j = 0; j < pointerCount; j++) { - if (i == j) { - continue; - } - - if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) { - dropX = true; - break; - } - - if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) { - dropY = true; - break; - } - } - if (! dropX && ! dropY) { - continue; // not jumpy - } - - // Find a replacement candidate by comparing with older points on the - // complementary (non-jumpy) axis. - int32_t distance = INT_MIN; // distance to be corrected - int32_t replacementIndex = -1; - - if (dropX) { - // X looks too close. Find an older replacement point with a close Y. - int32_t smallestDeltaY = INT_MAX; - for (uint32_t j = 0; j < pointerCount; j++) { - int32_t deltaY = abs(y - lastTouch.pointers[j].y); - if (deltaY < smallestDeltaY) { - smallestDeltaY = deltaY; - replacementIndex = j; - } - } - distance = abs(x - lastTouch.pointers[replacementIndex].x); - } else { - // Y looks too close. Find an older replacement point with a close X. - int32_t smallestDeltaX = INT_MAX; - for (uint32_t j = 0; j < pointerCount; j++) { - int32_t deltaX = abs(x - lastTouch.pointers[j].x); - if (deltaX < smallestDeltaX) { - smallestDeltaX = deltaX; - replacementIndex = j; - } - } - distance = abs(y - lastTouch.pointers[replacementIndex].y); - } - - // If replacing this pointer would correct a worse error than the previous ones - // considered, then use this replacement instead. - if (distance > badPointerDistance) { - badPointerIndex = i; - badPointerReplacementIndex = replacementIndex; - badPointerDistance = distance; - } - } - - // Correct the jumpy pointer if one was found. - if (badPointerIndex >= 0) { -#if DEBUG_HACKS - LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)", - badPointerIndex, - lastTouch.pointers[badPointerReplacementIndex].x, - lastTouch.pointers[badPointerReplacementIndex].y); -#endif - - currentTouch.pointers[badPointerIndex].x = - lastTouch.pointers[badPointerReplacementIndex].x; - currentTouch.pointers[badPointerIndex].y = - lastTouch.pointers[badPointerReplacementIndex].y; - jumpyTouchFilter.jumpyPointsDropped += 1; - return true; - } - } - - jumpyTouchFilter.jumpyPointsDropped = 0; - return false; -} - -/* Special hack for devices that have bad screen data: aggregate and - * compute averages of the coordinate data, to reduce the amount of - * jitter seen by applications. */ -void InputDevice::TouchScreenState::applyAveragingTouchFilter() { - for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) { - uint32_t id = currentTouch.pointers[currentIndex].id; - int32_t x = currentTouch.pointers[currentIndex].x; - int32_t y = currentTouch.pointers[currentIndex].y; - int32_t pressure = currentTouch.pointers[currentIndex].pressure; - - if (lastTouch.idBits.hasBit(id)) { - // Pointer was down before and is still down now. - // Compute average over history trace. - uint32_t start = averagingTouchFilter.historyStart[id]; - uint32_t end = averagingTouchFilter.historyEnd[id]; - - int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x; - int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y; - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld", - id, distance); -#endif - - if (distance < AVERAGING_DISTANCE_LIMIT) { - // Increment end index in preparation for recording new historical data. - end += 1; - if (end > AVERAGING_HISTORY_SIZE) { - end = 0; - } - - // If the end index has looped back to the start index then we have filled - // the historical trace up to the desired size so we drop the historical - // data at the start of the trace. - if (end == start) { - start += 1; - if (start > AVERAGING_HISTORY_SIZE) { - start = 0; - } - } - - // Add the raw data to the historical trace. - averagingTouchFilter.historyStart[id] = start; - averagingTouchFilter.historyEnd[id] = end; - averagingTouchFilter.historyData[end].pointers[id].x = x; - averagingTouchFilter.historyData[end].pointers[id].y = y; - averagingTouchFilter.historyData[end].pointers[id].pressure = pressure; - - // Average over all historical positions in the trace by total pressure. - int32_t averagedX = 0; - int32_t averagedY = 0; - int32_t totalPressure = 0; - for (;;) { - int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x; - int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y; - int32_t historicalPressure = averagingTouchFilter.historyData[start] - .pointers[id].pressure; - - averagedX += historicalX * historicalPressure; - averagedY += historicalY * historicalPressure; - totalPressure += historicalPressure; - - if (start == end) { - break; - } - - start += 1; - if (start > AVERAGING_HISTORY_SIZE) { - start = 0; - } - } - - averagedX /= totalPressure; - averagedY /= totalPressure; - -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - " - "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, - averagedX, averagedY); -#endif - - currentTouch.pointers[currentIndex].x = averagedX; - currentTouch.pointers[currentIndex].y = averagedY; - } else { -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id); -#endif - } - } else { -#if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id); -#endif - } - - // Reset pointer history. - averagingTouchFilter.historyStart[id] = 0; - averagingTouchFilter.historyEnd[id] = 0; - averagingTouchFilter.historyData[0].pointers[id].x = x; - averagingTouchFilter.historyData[0].pointers[id].y = y; - averagingTouchFilter.historyData[0].pointers[id].pressure = pressure; - } -} - -bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const { - if (! parameters.xAxis.valid || ! parameters.yAxis.valid) { - // Assume all points on a touch screen without valid axis parameters are - // inside the display. - return true; - } - - return x >= parameters.xAxis.minValue - && x <= parameters.xAxis.maxValue - && y >= parameters.yAxis.minValue - && y <= parameters.yAxis.maxValue; -} - -const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const { - int32_t x = currentTouch.pointers[0].x; - int32_t y = currentTouch.pointers[0].y; - for (size_t i = 0; i < virtualKeys.size(); i++) { - const InputDevice::VirtualKey& virtualKey = virtualKeys[i]; - -#if DEBUG_VIRTUAL_KEYS - LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, - virtualKey.keyCode, virtualKey.scanCode, - virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return & virtualKey; - } - } - - return NULL; -} - - -// --- InputDevice::SingleTouchScreenState --- - -void InputDevice::SingleTouchScreenState::reset() { - accumulator.clear(); - current.down = false; - current.x = 0; - current.y = 0; - current.pressure = 0; - current.size = 0; -} - - -// --- InputDevice::MultiTouchScreenState --- - -void InputDevice::MultiTouchScreenState::reset() { - accumulator.clear(); -} - - // --- InputReader --- InputReader::InputReader(const sp<EventHubInterface>& eventHub, @@ -927,32 +253,30 @@ void InputReader::handleKey(const RawEvent* rawEvent) { bool down = rawEvent->value != 0; int32_t scanCode = rawEvent->scanCode; - if (device->isKeyboard() && (scanCode < BTN_FIRST || scanCode > BTN_LAST)) { - int32_t keyCode = rawEvent->keyCode; - onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags); - } else if (device->isSingleTouchScreen()) { + if (device->isSingleTouchScreen()) { switch (rawEvent->scanCode) { case BTN_TOUCH: device->singleTouchScreen.accumulator.fields |= InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH; device->singleTouchScreen.accumulator.btnTouch = down; - break; + return; } - } else if (device->isTrackball()) { + } + + if (device->isTrackball()) { switch (rawEvent->scanCode) { case BTN_MOUSE: device->trackball.accumulator.fields |= InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE; device->trackball.accumulator.btnMouse = down; - - // send the down immediately - // XXX this emulates the old behavior of KeyInputQueue, unclear whether it is - // necessary or if we can wait until the next sync - onTrackballStateChanged(rawEvent->when, device); - device->trackball.accumulator.clear(); - break; + return; } } + + if (device->isKeyboard()) { + int32_t keyCode = rawEvent->keyCode; + onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags); + } } void InputReader::handleRelativeMotion(const RawEvent* rawEvent) { diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 25def3c..fc83e31 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -690,22 +690,3 @@ void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const { } } // namespace android - -// --- AInputQueue --- - -using android::InputEvent; -using android::InputChannel; -using android::InputConsumer; -using android::sp; -using android::status_t; - -AInputQueue::AInputQueue(const sp<InputChannel>& channel) : - mConsumer(channel) { -} - -AInputQueue::~AInputQueue() { -} - -status_t AInputQueue::consume(InputEvent** event) { - return mConsumer.consume(&mInputEventFactory, event); -} diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index b205418..edf1aed 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -60,7 +60,6 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info) switch (format) { case HAL_PIXEL_FORMAT_YCbCr_422_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: - case HAL_PIXEL_FORMAT_YV16: info->bitsPerPixel = 16; goto done; case HAL_PIXEL_FORMAT_YCrCb_420_SP: diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp index 2d6b531..55504f2 100644 --- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -76,7 +76,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { const int32_t nature = INPUT_EVENT_NATURE_KEY; const int32_t action = KEY_EVENT_ACTION_DOWN; const int32_t flags = KEY_EVENT_FLAG_FROM_SYSTEM; - const int32_t keyCode = KEYCODE_ENTER; + const int32_t keyCode = AKEYCODE_ENTER; const int32_t scanCode = 13; const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON; const int32_t repeatCount = 1; diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index 2bb42ab..8bd5823 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -122,3 +122,13 @@ LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp include $(BUILD_STATIC_LIBRARY) endif endif + + +# Include subdirectory makefiles +# ============================================================ + +# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework +# team really wants is to build the stuff defined by this makefile. +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif
\ No newline at end of file |