diff options
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 28 | ||||
-rw-r--r-- | core/java/com/android/internal/widget/PointerLocationView.java | 91 | ||||
-rwxr-xr-x | include/ui/KeycodeLabels.h | 2 | ||||
-rw-r--r-- | native/include/android/input.h | 1 | ||||
-rw-r--r-- | services/input/InputDispatcher.cpp | 59 | ||||
-rw-r--r-- | services/input/InputDispatcher.h | 18 | ||||
-rw-r--r-- | services/input/InputListener.cpp | 19 | ||||
-rw-r--r-- | services/input/InputListener.h | 20 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 1536 | ||||
-rw-r--r-- | services/input/InputReader.h | 309 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 509 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 68 |
13 files changed, 1747 insertions, 914 deletions
diff --git a/api/current.txt b/api/current.txt index 4332833..eb58ae4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22315,6 +22315,7 @@ package android.view { field public static final int AXIS_RZ = 14; // 0xe field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 + field public static final int AXIS_TILT = 25; // 0x19 field public static final int AXIS_TOOL_MAJOR = 6; // 0x6 field public static final int AXIS_TOOL_MINOR = 7; // 0x7 field public static final int AXIS_TOUCH_MAJOR = 4; // 0x4 diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index da5c7b2..8e0ab1a 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -619,6 +619,11 @@ public final class MotionEvent extends InputEvent implements Parcelable { * indicates that the major axis of contact is oriented to the left. * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians * (finger pointing fully right). + * <li>For a stylus, the orientation indicates the direction in which the stylus + * is pointing in relation to the vertical axis of the current orientation of the screen. + * The range is from -PI radians to PI radians, where 0 is pointing up, + * -PI/2 radians is pointing left, -PI or PI radians is pointing down, and PI/2 radians + * is pointing right. See also {@link #AXIS_TILT}. * </ul> * </p> * @@ -883,8 +888,8 @@ public final class MotionEvent extends InputEvent implements Parcelable { * <p> * <ul> * <li>For a stylus, reports the distance of the stylus from the screen. - * The value is nominally measured in millimeters where 0.0 indicates direct contact - * and larger values indicate increasing distance from the surface. + * A value of 0.0 indicates direct contact and larger values indicate increasing + * distance from the surface. * </ul> * </p> * @@ -896,6 +901,24 @@ public final class MotionEvent extends InputEvent implements Parcelable { public static final int AXIS_DISTANCE = 24; /** + * Axis constant: Tilt axis of a motion event. + * <p> + * <ul> + * <li>For a stylus, reports the tilt angle of the stylus in radians where + * 0 radians indicates that the stylus is being held perpendicular to the + * surface, and PI/2 radians indicates that the stylus is being held flat + * against the surface. + * </ul> + * </p> + * + * @see #getAxisValue(int, int) + * @see #getHistoricalAxisValue(int, int, int) + * @see MotionEvent.PointerCoords#getAxisValue(int, int) + * @see InputDevice#getMotionRange + */ + public static final int AXIS_TILT = 25; + + /** * Axis constant: Generic 1 axis of a motion event. * The interpretation of a generic axis is device-specific. * @@ -1104,6 +1127,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { names.append(AXIS_GAS, "AXIS_GAS"); names.append(AXIS_BRAKE, "AXIS_BRAKE"); names.append(AXIS_DISTANCE, "AXIS_DISTANCE"); + names.append(AXIS_TILT, "AXIS_TILT"); names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1"); names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2"); names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3"); diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java index bf1c637..158291b 100644 --- a/core/java/com/android/internal/widget/PointerLocationView.java +++ b/core/java/com/android/internal/widget/PointerLocationView.java @@ -46,6 +46,7 @@ public class PointerLocationView extends View { // Most recent coordinates. private PointerCoords mCoords = new PointerCoords(); + private int mToolType; // Most recent velocity. private float mXVelocity; @@ -88,7 +89,7 @@ public class PointerLocationView extends View { private int mMaxNumPointers; private int mActivePointerId; private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>(); - private final PointerCoords mHoverCoords = new PointerCoords(); + private final PointerCoords mTempCoords = new PointerCoords(); private final VelocityTracker mVelocity; @@ -306,22 +307,66 @@ public class PointerLocationView extends View { ps.mCoords.toolMinor, ps.mCoords.orientation, mPaint); // Draw the orientation arrow. + float arrowSize = ps.mCoords.toolMajor * 0.7f; + if (arrowSize < 20) { + arrowSize = 20; + } mPaint.setARGB(255, pressureLevel, 255, 0); - float orientationVectorX = (float) (Math.sin(-ps.mCoords.orientation) - * ps.mCoords.toolMajor * 0.7); - float orientationVectorY = (float) (Math.cos(-ps.mCoords.orientation) - * ps.mCoords.toolMajor * 0.7); - canvas.drawLine( - ps.mCoords.x - orientationVectorX, ps.mCoords.y - orientationVectorY, - ps.mCoords.x + orientationVectorX, ps.mCoords.y + orientationVectorY, - mPaint); + float orientationVectorX = (float) (Math.sin(ps.mCoords.orientation) + * arrowSize); + float orientationVectorY = (float) (-Math.cos(ps.mCoords.orientation) + * arrowSize); + if (ps.mToolType == MotionEvent.TOOL_TYPE_STYLUS + || ps.mToolType == MotionEvent.TOOL_TYPE_ERASER) { + // Show full circle orientation. + canvas.drawLine(ps.mCoords.x, ps.mCoords.y, + ps.mCoords.x + orientationVectorX, + ps.mCoords.y + orientationVectorY, + mPaint); + } else { + // Show half circle orientation. + canvas.drawLine( + ps.mCoords.x - orientationVectorX, + ps.mCoords.y - orientationVectorY, + ps.mCoords.x + orientationVectorX, + ps.mCoords.y + orientationVectorY, + mPaint); + } + + // Draw the tilt point along the orientation arrow. + float tiltScale = (float) Math.sin( + ps.mCoords.getAxisValue(MotionEvent.AXIS_TILT)); + canvas.drawCircle( + ps.mCoords.x + orientationVectorX * tiltScale, + ps.mCoords.y + orientationVectorY * tiltScale, + 3.0f, mPaint); } } } } - - private void logPointerCoords(int action, int index, MotionEvent.PointerCoords coords, int id, - int toolType, int buttonState) { + + private void logMotionEvent(String type, MotionEvent event) { + final int action = event.getAction(); + final int N = event.getHistorySize(); + final int NI = event.getPointerCount(); + for (int historyPos = 0; historyPos < N; historyPos++) { + for (int i = 0; i < NI; i++) { + final int id = event.getPointerId(i); + event.getHistoricalPointerCoords(i, historyPos, mTempCoords); + logCoords(type, action, i, mTempCoords, id, + event.getToolType(i), event.getButtonState()); + } + } + for (int i = 0; i < NI; i++) { + final int id = event.getPointerId(i); + event.getPointerCoords(i, mTempCoords); + logCoords(type, action, i, mTempCoords, id, + event.getToolType(i), event.getButtonState()); + } + } + + private void logCoords(String type, int action, int index, + MotionEvent.PointerCoords coords, int id, int toolType, int buttonState) { final String prefix; switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: @@ -373,7 +418,7 @@ public class PointerLocationView extends View { } Log.i(TAG, mText.clear() - .append("Pointer ").append(id + 1) + .append(type).append(" id ").append(id + 1) .append(": ") .append(prefix) .append(" (").append(coords.x, 3).append(", ").append(coords.y, 3) @@ -385,6 +430,9 @@ public class PointerLocationView extends View { .append(" ToolMinor=").append(coords.toolMinor, 3) .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1) .append("deg") + .append(" Tilt=").append((float)( + coords.getAxisValue(MotionEvent.AXIS_TILT) * 180 / Math.PI), 1) + .append("deg") .append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1) .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1) .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1) @@ -445,10 +493,10 @@ public class PointerLocationView extends View { for (int i = 0; i < NI; i++) { final int id = event.getPointerId(i); final PointerState ps = mCurDown ? mPointers.get(id) : null; - final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; + final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords; event.getHistoricalPointerCoords(i, historyPos, coords); if (mPrintCoords) { - logPointerCoords(action, i, coords, id, + logCoords("Pointer", action, i, coords, id, event.getToolType(i), event.getButtonState()); } if (ps != null) { @@ -459,16 +507,17 @@ public class PointerLocationView extends View { for (int i = 0; i < NI; i++) { final int id = event.getPointerId(i); final PointerState ps = mCurDown ? mPointers.get(id) : null; - final PointerCoords coords = ps != null ? ps.mCoords : mHoverCoords; + final PointerCoords coords = ps != null ? ps.mCoords : mTempCoords; event.getPointerCoords(i, coords); if (mPrintCoords) { - logPointerCoords(action, i, coords, id, + logCoords("Pointer", action, i, coords, id, event.getToolType(i), event.getButtonState()); } if (ps != null) { ps.addTrace(coords.x, coords.y); ps.mXVelocity = mVelocity.getXVelocity(id); ps.mYVelocity = mVelocity.getYVelocity(id); + ps.mToolType = event.getToolType(i); } } @@ -515,11 +564,11 @@ public class PointerLocationView extends View { if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { addPointerEvent(event); } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { - Log.i(TAG, "Joystick: " + event); + logMotionEvent("Joystick", event); } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) { - Log.i(TAG, "Position: " + event); + logMotionEvent("Position", event); } else { - Log.i(TAG, "Generic: " + event); + logMotionEvent("Generic", event); } return true; } @@ -563,7 +612,7 @@ public class PointerLocationView extends View { @Override public boolean onTrackballEvent(MotionEvent event) { - Log.i(TAG, "Trackball: " + event); + logMotionEvent("Trackball", event); return true; } diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index 8383957..2efe8ca 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -278,6 +278,8 @@ static const KeycodeLabel AXES[] = { { "WHEEL", 21 }, { "GAS", 22 }, { "BRAKE", 23 }, + { "DISTANCE", 24 }, + { "TILT", 25 }, { "GENERIC_1", 32 }, { "GENERIC_2", 33 }, { "GENERIC_3", 34 }, diff --git a/native/include/android/input.h b/native/include/android/input.h index 7a0dcd3..f2befa9 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -373,6 +373,7 @@ enum { AMOTION_EVENT_AXIS_GAS = 22, AMOTION_EVENT_AXIS_BRAKE = 23, AMOTION_EVENT_AXIS_DISTANCE = 24, + AMOTION_EVENT_AXIS_TILT = 25, AMOTION_EVENT_AXIS_GENERIC_1 = 32, AMOTION_EVENT_AXIS_GENERIC_2 = 33, AMOTION_EVENT_AXIS_GENERIC_3 = 34, diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 3cd3ac3..f6ce44c 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -401,6 +401,14 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { break; } + case EventEntry::TYPE_DEVICE_RESET: { + DeviceResetEntry* typedEntry = + static_cast<DeviceResetEntry*>(mPendingEvent); + done = dispatchDeviceResetLocked(currentTime, typedEntry); + dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped + break; + } + case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); if (isAppSwitchDue) { @@ -727,6 +735,19 @@ bool InputDispatcher::dispatchConfigurationChangedLocked( return true; } +bool InputDispatcher::dispatchDeviceResetLocked( + nsecs_t currentTime, DeviceResetEntry* entry) { +#if DEBUG_OUTBOUND_EVENT_DETAILS + LOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); +#endif + + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, + "device was reset"); + options.deviceId = entry->deviceId; + synthesizeCancelationEventsForAllConnectionsLocked(options); + return true; +} + bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. @@ -2921,6 +2942,25 @@ void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { args->switchCode, args->switchValue, policyFlags); } +void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { +#if DEBUG_INBOUND_EVENT_DETAILS + LOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", + args->eventTime, args->deviceId); +#endif + + bool needWake; + { // acquire lock + AutoMutex _l(mLock); + + DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId); + needWake = enqueueInboundEventLocked(newEntry); + } // release lock + + if (needWake) { + mLooper->wake(); + } +} + int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) { @@ -4016,6 +4056,17 @@ InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { } +// --- InputDispatcher::DeviceResetEntry --- + +InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) : + EventEntry(TYPE_DEVICE_RESET, eventTime, 0), + deviceId(deviceId) { +} + +InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { +} + + // --- InputDispatcher::KeyEntry --- InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, @@ -4407,6 +4458,10 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, return false; } + if (options.deviceId != -1 && memento.deviceId != options.deviceId) { + return false; + } + switch (options.mode) { case CancelationOptions::CANCEL_ALL_EVENTS: case CancelationOptions::CANCEL_NON_POINTER_EVENTS: @@ -4420,6 +4475,10 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options) { + if (options.deviceId != -1 && memento.deviceId != options.deviceId) { + return false; + } + switch (options.mode) { case CancelationOptions::CANCEL_ALL_EVENTS: return true; diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index cae1610..3c83691 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -381,6 +381,7 @@ public: virtual void notifyKey(const NotifyKeyArgs* args); virtual void notifyMotion(const NotifyMotionArgs* args); virtual void notifySwitch(const NotifySwitchArgs* args); + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, @@ -424,6 +425,7 @@ private: struct EventEntry : Link<EventEntry> { enum { TYPE_CONFIGURATION_CHANGED, + TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION }; @@ -453,6 +455,15 @@ private: virtual ~ConfigurationChangedEntry(); }; + struct DeviceResetEntry : EventEntry { + int32_t deviceId; + + DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); + + protected: + virtual ~DeviceResetEntry(); + }; + struct KeyEntry : EventEntry { int32_t deviceId; uint32_t source; @@ -688,8 +699,11 @@ private: // The specific keycode of the key event to cancel, or -1 to cancel any key event. int32_t keyCode; + // The specific device id of events to cancel, or -1 to cancel events from any device. + int32_t deviceId; + CancelationOptions(Mode mode, const char* reason) : - mode(mode), reason(reason), keyCode(-1) { } + mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } }; /* Tracks dispatched key and motion event state so that cancelation events can be @@ -982,6 +996,8 @@ private: // Dispatch inbound events. bool dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry); + bool dispatchDeviceResetLocked( + nsecs_t currentTime, DeviceResetEntry* entry); bool dispatchKeyLocked( nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); diff --git a/services/input/InputListener.cpp b/services/input/InputListener.cpp index 4f9fe90..657a6b9 100644 --- a/services/input/InputListener.cpp +++ b/services/input/InputListener.cpp @@ -118,6 +118,21 @@ void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const } +// --- NotifyDeviceResetArgs --- + +NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) : + eventTime(eventTime), deviceId(deviceId) { +} + +NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : + eventTime(other.eventTime), deviceId(other.deviceId) { +} + +void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const { + listener->notifyDeviceReset(this); +} + + // --- QueuedInputListener --- QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : @@ -148,6 +163,10 @@ void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { mArgsQueue.push(new NotifySwitchArgs(*args)); } +void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { + mArgsQueue.push(new NotifyDeviceResetArgs(*args)); +} + void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { diff --git a/services/input/InputListener.h b/services/input/InputListener.h index 3fef132..f920cd1 100644 --- a/services/input/InputListener.h +++ b/services/input/InputListener.h @@ -131,6 +131,24 @@ struct NotifySwitchArgs : public NotifyArgs { }; +/* Describes a device reset event, such as when a device is added, + * reconfigured, or removed. */ +struct NotifyDeviceResetArgs : public NotifyArgs { + nsecs_t eventTime; + int32_t deviceId; + + inline NotifyDeviceResetArgs() { } + + NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId); + + NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); + + virtual ~NotifyDeviceResetArgs() { } + + virtual void notify(const sp<InputListenerInterface>& listener) const; +}; + + /* * The interface used by the InputReader to notify the InputListener about input events. */ @@ -144,6 +162,7 @@ public: virtual void notifyKey(const NotifyKeyArgs* args) = 0; virtual void notifyMotion(const NotifyMotionArgs* args) = 0; virtual void notifySwitch(const NotifySwitchArgs* args) = 0; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; }; @@ -162,6 +181,7 @@ public: virtual void notifyKey(const NotifyKeyArgs* args); virtual void notifyMotion(const NotifyMotionArgs* args); virtual void notifySwitch(const NotifySwitchArgs* args); + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); void flush(); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 2035a4b..88378ef 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -198,6 +198,39 @@ static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, } +// --- InputReaderConfiguration --- + +bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external, + int32_t* width, int32_t* height, int32_t* orientation) const { + if (displayId == 0) { + const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay; + if (info.width > 0 && info.height > 0) { + if (width) { + *width = info.width; + } + if (height) { + *height = info.height; + } + if (orientation) { + *orientation = info.orientation; + } + return true; + } + } + return false; +} + +void InputReaderConfiguration::setDisplayInfo(int32_t displayId, bool external, + int32_t width, int32_t height, int32_t orientation) { + if (displayId == 0) { + DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay; + info.width = width; + info.height = height; + info.orientation = orientation; + } +} + + // --- InputReader --- InputReader::InputReader(const sp<EventHubInterface>& eventHub, @@ -289,10 +322,10 @@ void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: - addDeviceLocked(rawEvent->deviceId); + addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: - removeDeviceLocked(rawEvent->deviceId); + removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); @@ -307,12 +340,13 @@ void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { } } -void InputReader::addDeviceLocked(int32_t deviceId) { +void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { String8 name = mEventHub->getDeviceName(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); InputDevice* device = createDeviceLocked(deviceId, name, classes); - device->configure(&mConfig, 0); + device->configure(when, &mConfig, 0); + device->reset(when); if (device->isIgnored()) { LOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, name.string()); @@ -331,7 +365,7 @@ void InputReader::addDeviceLocked(int32_t deviceId) { } } -void InputReader::removeDeviceLocked(int32_t deviceId) { +void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { InputDevice* device = NULL; ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { @@ -350,8 +384,7 @@ void InputReader::removeDeviceLocked(int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } - device->reset(); - + device->reset(when); delete device; } @@ -453,13 +486,14 @@ void InputReader::refreshConfigurationLocked(uint32_t changes) { if (changes) { LOGI("Reconfiguring input devices. changes=0x%08x", changes); + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { mEventHub->requestReopenDevices(); } else { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); - device->configure(&mConfig, changes); + device->configure(now, &mConfig, changes); } } } @@ -861,7 +895,7 @@ void InputDevice::addMapper(InputMapper* mapper) { mMappers.add(mapper); } -void InputDevice::configure(const InputReaderConfiguration* config, uint32_t changes) { +void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; if (!isIgnored()) { @@ -872,18 +906,22 @@ void InputDevice::configure(const InputReaderConfiguration* config, uint32_t cha size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; - mapper->configure(config, changes); + mapper->configure(when, config, changes); mSources |= mapper->getSources(); } } } -void InputDevice::reset() { +void InputDevice::reset(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; - mapper->reset(); + mapper->reset(when); } + + mContext->updateGlobalMetaState(); + + notifyReset(when); } void InputDevice::process(const RawEvent* rawEvents, size_t count) { @@ -915,7 +953,7 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) { } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) { LOGI("Detected input event buffer overrun for device %s.", mName.string()); mDropUntilNextSync = true; - reset(); + reset(rawEvent->when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; @@ -1001,6 +1039,11 @@ void InputDevice::fadePointer() { } } +void InputDevice::notifyReset(nsecs_t when) { + NotifyDeviceResetArgs args(when, mId); + mContext->getListener()->notifyDeviceReset(&args); +} + // --- CursorButtonAccumulator --- @@ -1008,6 +1051,17 @@ CursorButtonAccumulator::CursorButtonAccumulator() { clearButtons(); } +void CursorButtonAccumulator::reset(InputDevice* device) { + mBtnLeft = device->isKeyPressed(BTN_LEFT); + mBtnRight = device->isKeyPressed(BTN_RIGHT); + mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); + mBtnBack = device->isKeyPressed(BTN_BACK); + mBtnSide = device->isKeyPressed(BTN_SIDE); + mBtnForward = device->isKeyPressed(BTN_FORWARD); + mBtnExtra = device->isKeyPressed(BTN_EXTRA); + mBtnTask = device->isKeyPressed(BTN_TASK); +} + void CursorButtonAccumulator::clearButtons() { mBtnLeft = 0; mBtnRight = 0; @@ -1073,21 +1127,17 @@ uint32_t CursorButtonAccumulator::getButtonState() const { // --- CursorMotionAccumulator --- -CursorMotionAccumulator::CursorMotionAccumulator() : - mHaveRelWheel(false), mHaveRelHWheel(false) { +CursorMotionAccumulator::CursorMotionAccumulator() { clearRelativeAxes(); } -void CursorMotionAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); +void CursorMotionAccumulator::reset(InputDevice* device) { + clearRelativeAxes(); } void CursorMotionAccumulator::clearRelativeAxes() { mRelX = 0; mRelY = 0; - mRelWheel = 0; - mRelHWheel = 0; } void CursorMotionAccumulator::process(const RawEvent* rawEvent) { @@ -1099,6 +1149,39 @@ void CursorMotionAccumulator::process(const RawEvent* rawEvent) { case REL_Y: mRelY = rawEvent->value; break; + } + } +} + +void CursorMotionAccumulator::finishSync() { + clearRelativeAxes(); +} + + +// --- CursorScrollAccumulator --- + +CursorScrollAccumulator::CursorScrollAccumulator() : + mHaveRelWheel(false), mHaveRelHWheel(false) { + clearRelativeAxes(); +} + +void CursorScrollAccumulator::configure(InputDevice* device) { + mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); + mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); +} + +void CursorScrollAccumulator::reset(InputDevice* device) { + clearRelativeAxes(); +} + +void CursorScrollAccumulator::clearRelativeAxes() { + mRelWheel = 0; + mRelHWheel = 0; +} + +void CursorScrollAccumulator::process(const RawEvent* rawEvent) { + if (rawEvent->type == EV_REL) { + switch (rawEvent->scanCode) { case REL_WHEEL: mRelWheel = rawEvent->value; break; @@ -1109,6 +1192,10 @@ void CursorMotionAccumulator::process(const RawEvent* rawEvent) { } } +void CursorScrollAccumulator::finishSync() { + clearRelativeAxes(); +} + // --- TouchButtonAccumulator --- @@ -1118,7 +1205,21 @@ TouchButtonAccumulator::TouchButtonAccumulator() : } void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->getEventHub()->hasScanCode(device->getId(), BTN_TOUCH); + mHaveBtnTouch = device->hasKey(BTN_TOUCH); +} + +void TouchButtonAccumulator::reset(InputDevice* device) { + mBtnTouch = device->isKeyPressed(BTN_TOUCH); + mBtnStylus = device->isKeyPressed(BTN_STYLUS); + mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); + mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); + mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); + mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); + mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); + mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); + mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); + mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); + mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); } void TouchButtonAccumulator::clearButtons() { @@ -1128,6 +1229,11 @@ void TouchButtonAccumulator::clearButtons() { mBtnToolFinger = 0; mBtnToolPen = 0; mBtnToolRubber = 0; + mBtnToolBrush = 0; + mBtnToolPencil = 0; + mBtnToolAirbrush = 0; + mBtnToolMouse = 0; + mBtnToolLens = 0; } void TouchButtonAccumulator::process(const RawEvent* rawEvent) { @@ -1151,6 +1257,21 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { case BTN_TOOL_RUBBER: mBtnToolRubber = rawEvent->value; break; + case BTN_TOOL_BRUSH: + mBtnToolBrush = rawEvent->value; + break; + case BTN_TOOL_PENCIL: + mBtnToolPencil = rawEvent->value; + break; + case BTN_TOOL_AIRBRUSH: + mBtnToolAirbrush = rawEvent->value; + break; + case BTN_TOOL_MOUSE: + mBtnToolMouse = rawEvent->value; + break; + case BTN_TOOL_LENS: + mBtnToolLens = rawEvent->value; + break; } } } @@ -1167,10 +1288,13 @@ uint32_t TouchButtonAccumulator::getButtonState() const { } int32_t TouchButtonAccumulator::getToolType() const { + if (mBtnToolMouse || mBtnToolLens) { + return AMOTION_EVENT_TOOL_TYPE_MOUSE; + } if (mBtnToolRubber) { return AMOTION_EVENT_TOOL_TYPE_ERASER; } - if (mBtnToolPen) { + if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { return AMOTION_EVENT_TOOL_TYPE_STYLUS; } if (mBtnToolFinger) { @@ -1180,7 +1304,9 @@ int32_t TouchButtonAccumulator::getToolType() const { } bool TouchButtonAccumulator::isToolActive() const { - return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber; + return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber + || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush + || mBtnToolMouse || mBtnToolLens; } bool TouchButtonAccumulator::isHovering() const { @@ -1204,6 +1330,8 @@ void RawPointerAxes::clear() { toolMinor.clear(); orientation.clear(); distance.clear(); + tiltX.clear(); + tiltY.clear(); trackingId.clear(); slot.clear(); } @@ -1284,12 +1412,24 @@ SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { clearAbsoluteAxes(); } +void SingleTouchMotionAccumulator::reset(InputDevice* device) { + mAbsX = device->getAbsoluteAxisValue(ABS_X); + mAbsY = device->getAbsoluteAxisValue(ABS_Y); + mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); + mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); + mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); + mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); + mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); +} + void SingleTouchMotionAccumulator::clearAbsoluteAxes() { mAbsX = 0; mAbsY = 0; mAbsPressure = 0; mAbsToolWidth = 0; mAbsDistance = 0; + mAbsTiltX = 0; + mAbsTiltY = 0; } void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { @@ -1310,6 +1450,12 @@ void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { case ABS_DISTANCE: mAbsDistance = rawEvent->value; break; + case ABS_TILT_X: + mAbsTiltX = rawEvent->value; + break; + case ABS_TILT_Y: + mAbsTiltY = rawEvent->value; + break; } } } @@ -1333,9 +1479,37 @@ void MultiTouchMotionAccumulator::configure(size_t slotCount, bool usingSlotsPro mSlots = new Slot[slotCount]; } +void MultiTouchMotionAccumulator::reset(InputDevice* device) { + // Unfortunately there is no way to read the initial contents of the slots. + // So when we reset the accumulator, we must assume they are all zeroes. + if (mUsingSlotsProtocol) { + // Query the driver for the current slot index and use it as the initial slot + // before we start reading events from the device. It is possible that the + // current slot index will not be the same as it was when the first event was + // written into the evdev buffer, which means the input mapper could start + // out of sync with the initial state of the events in the evdev buffer. + // In the extremely unlikely case that this happens, the data from + // two slots will be confused until the next ABS_MT_SLOT event is received. + // This can cause the touch point to "jump", but at least there will be + // no stuck touches. + int32_t initialSlot; + status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), + ABS_MT_SLOT, &initialSlot); + if (status) { + LOGD("Could not retrieve current multitouch slot index. status=%d", status); + initialSlot = -1; + } + clearSlots(initialSlot); + } else { + clearSlots(-1); + } +} + void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); + if (mSlots) { + for (size_t i = 0; i < mSlotCount; i++) { + mSlots[i].clear(); + } } mCurrentSlot = initialSlot; } @@ -1425,6 +1599,12 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { } } +void MultiTouchMotionAccumulator::finishSync() { + if (!mUsingSlotsProtocol) { + clearSlots(-1); + } +} + // --- MultiTouchMotionAccumulator::Slot --- @@ -1479,10 +1659,11 @@ void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { void InputMapper::dump(String8& dump) { } -void InputMapper::configure(const InputReaderConfiguration* config, uint32_t changes) { +void InputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { } -void InputMapper::reset() { +void InputMapper::reset(nsecs_t when) { } void InputMapper::timeoutExpired(nsecs_t when) { @@ -1564,17 +1745,11 @@ KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType) : InputMapper(device), mSource(source), mKeyboardType(keyboardType) { - initialize(); } KeyboardInputMapper::~KeyboardInputMapper() { } -void KeyboardInputMapper::initialize() { - mMetaState = AMETA_NONE; - mDownTime = 0; -} - uint32_t KeyboardInputMapper::getSources() { return mSource; } @@ -1589,21 +1764,31 @@ void KeyboardInputMapper::dump(String8& dump) { dump.append(INDENT2 "Keyboard Input Mapper:\n"); dumpParameters(dump); dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); + dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size()); dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); } -void KeyboardInputMapper::configure(const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(config, changes); +void KeyboardInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); if (!changes) { // first time only // Configure basic parameters. configureParameters(); + } - // Reset LEDs. - resetLedState(); + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { + if (!config->getDisplayInfo(mParameters.associatedDisplayId, + false /*external*/, NULL, NULL, &mOrientation)) { + mOrientation = DISPLAY_ORIENTATION_0; + } + } else { + mOrientation = DISPLAY_ORIENTATION_0; + } } } @@ -1626,19 +1811,14 @@ void KeyboardInputMapper::dumpParameters(String8& dump) { toString(mParameters.orientationAware)); } -void KeyboardInputMapper::reset() { - // Synthesize key up event on reset if keys are currently down. - while (!mKeyDowns.isEmpty()) { - const KeyDown& keyDown = mKeyDowns.top(); - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - processKey(when, false, keyDown.keyCode, keyDown.scanCode, 0); - } +void KeyboardInputMapper::reset(nsecs_t when) { + mMetaState = AMETA_NONE; + mDownTime = 0; + mKeyDowns.clear(); - initialize(); resetLedState(); - InputMapper::reset(); - getContext()->updateGlobalMetaState(); + InputMapper::reset(when); } void KeyboardInputMapper::process(const RawEvent* rawEvent) { @@ -1666,15 +1846,8 @@ 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 (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { - int32_t orientation; - if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, - false /*external*/, NULL, NULL, & orientation)) { - orientation = DISPLAY_ORIENTATION_0; - } - - keyCode = rotateKeyCode(keyCode, orientation); + keyCode = rotateKeyCode(keyCode, mOrientation); } // Add key down. @@ -1813,7 +1986,6 @@ void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) { - initialize(); } CursorInputMapper::~CursorInputMapper() { @@ -1838,10 +2010,10 @@ void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { } info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f); - if (mCursorMotionAccumulator.haveRelativeVWheel()) { + if (mCursorScrollAccumulator.haveRelativeVWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } - if (mCursorMotionAccumulator.haveRelativeHWheel()) { + if (mCursorScrollAccumulator.haveRelativeHWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } } @@ -1854,21 +2026,23 @@ void CursorInputMapper::dump(String8& dump) { dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); dump.appendFormat(INDENT3 "HaveVWheel: %s\n", - toString(mCursorMotionAccumulator.haveRelativeVWheel())); + toString(mCursorScrollAccumulator.haveRelativeVWheel())); dump.appendFormat(INDENT3 "HaveHWheel: %s\n", - toString(mCursorMotionAccumulator.haveRelativeHWheel())); + toString(mCursorScrollAccumulator.haveRelativeHWheel())); dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); + dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState); dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); } -void CursorInputMapper::configure(const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(config, changes); +void CursorInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); if (!changes) { // first time only - mCursorMotionAccumulator.configure(getDevice()); + mCursorScrollAccumulator.configure(getDevice()); // Configure basic parameters. configureParameters(); @@ -1901,6 +2075,17 @@ void CursorInputMapper::configure(const InputReaderConfiguration* config, uint32 mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); } + + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { + if (!config->getDisplayInfo(mParameters.associatedDisplayId, + false /*external*/, NULL, NULL, &mOrientation)) { + mOrientation = DISPLAY_ORIENTATION_0; + } + } else { + mOrientation = DISPLAY_ORIENTATION_0; + } + } } void CursorInputMapper::configureParameters() { @@ -1944,34 +2129,25 @@ void CursorInputMapper::dumpParameters(String8& dump) { toString(mParameters.orientationAware)); } -void CursorInputMapper::initialize() { - mCursorButtonAccumulator.clearButtons(); - mCursorMotionAccumulator.clearRelativeAxes(); - +void CursorInputMapper::reset(nsecs_t when) { mButtonState = 0; mDownTime = 0; -} -void CursorInputMapper::reset() { - // Reset velocity. mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); - // Synthesize button up event on reset. - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - mCursorButtonAccumulator.clearButtons(); - mCursorMotionAccumulator.clearRelativeAxes(); - sync(when); - - initialize(); + mCursorButtonAccumulator.reset(getDevice()); + mCursorMotionAccumulator.reset(getDevice()); + mCursorScrollAccumulator.reset(getDevice()); - InputMapper::reset(); + InputMapper::reset(when); } void CursorInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorMotionAccumulator.process(rawEvent); + mCursorScrollAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { sync(rawEvent->when); @@ -2001,19 +2177,13 @@ void CursorInputMapper::sync(nsecs_t when) { float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; bool moved = deltaX != 0 || deltaY != 0; + // Rotate delta according to orientation if needed. if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0 && (deltaX != 0.0f || deltaY != 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(mParameters.associatedDisplayId, - false /*external*/, NULL, NULL, & orientation)) { - orientation = DISPLAY_ORIENTATION_0; - } - - rotateDelta(orientation, &deltaX, &deltaY); + rotateDelta(mOrientation, &deltaX, &deltaY); } + // Move the pointer. PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; @@ -2022,8 +2192,8 @@ void CursorInputMapper::sync(nsecs_t when) { PointerCoords pointerCoords; pointerCoords.clear(); - float vscroll = mCursorMotionAccumulator.getRelativeVWheel(); - float hscroll = mCursorMotionAccumulator.getRelativeHWheel(); + float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); + float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); bool scrolled = vscroll != 0 || hscroll != 0; mWheelYVelocityControl.move(when, NULL, &vscroll); @@ -2115,7 +2285,8 @@ void CursorInputMapper::sync(nsecs_t when) { synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); - mCursorMotionAccumulator.clearRelativeAxes(); + mCursorMotionAccumulator.finishSync(); + mCursorScrollAccumulator.finishSync(); } int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { @@ -2137,65 +2308,57 @@ void CursorInputMapper::fadePointer() { TouchInputMapper::TouchInputMapper(InputDevice* device) : InputMapper(device), + mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) { - initialize(); } TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { - return mTouchSource | mPointerSource; + return mSource; } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); - // Ensure surface information is up to date so that orientation changes are - // noticed immediately. - if (!configureSurface()) { - return; - } - - info->addMotionRange(mOrientedRanges.x); - info->addMotionRange(mOrientedRanges.y); - - if (mOrientedRanges.havePressure) { + if (mDeviceMode != DEVICE_MODE_DISABLED) { + info->addMotionRange(mOrientedRanges.x); + info->addMotionRange(mOrientedRanges.y); info->addMotionRange(mOrientedRanges.pressure); - } - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); - } + if (mOrientedRanges.haveSize) { + info->addMotionRange(mOrientedRanges.size); + } - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); - } + if (mOrientedRanges.haveTouchSize) { + info->addMotionRange(mOrientedRanges.touchMajor); + info->addMotionRange(mOrientedRanges.touchMinor); + } - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); - } + if (mOrientedRanges.haveToolSize) { + info->addMotionRange(mOrientedRanges.toolMajor); + info->addMotionRange(mOrientedRanges.toolMinor); + } - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); - } + if (mOrientedRanges.haveOrientation) { + info->addMotionRange(mOrientedRanges.orientation); + } - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); - } + if (mOrientedRanges.haveDistance) { + info->addMotionRange(mOrientedRanges.distance); + } - if (mPointerController != NULL) { - float minX, minY, maxX, maxY; - if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mPointerSource, - minX, maxX, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mPointerSource, - minY, maxY, 0.0f, 0.0f); + if (mOrientedRanges.haveTilt) { + info->addMotionRange(mOrientedRanges.tilt); + } + + if (mCursorScrollAccumulator.haveRelativeVWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); + } + if (mCursorScrollAccumulator.haveRelativeHWheel()) { + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mPointerSource, - 0.0f, 1.0f, 0.0f, 0.0f); } } @@ -2215,8 +2378,14 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale); dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale); + dump.appendFormat(INDENT4 "OrientationCenter: %0.3f\n", mOrientationCenter); dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); + dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); + dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); + dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); + dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); + dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); @@ -2226,11 +2395,12 @@ void TouchInputMapper::dump(String8& dump) { const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " - "orientation=%d, distance=%d, toolType=%d, isHovering=%s\n", i, + "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " + "toolType=%d, isHovering=%s\n", i, pointer.id, pointer.x, pointer.y, pointer.pressure, pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, pointer.toolMinor, - pointer.orientation, pointer.distance, + pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, pointer.toolType, toString(pointer.isHovering)); } @@ -2241,7 +2411,8 @@ void TouchInputMapper::dump(String8& dump) { const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " - "orientation=%0.3f, distance=%0.3f, toolType=%d, isHovering=%s\n", i, + "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " + "toolType=%d, isHovering=%s\n", i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(), @@ -2251,50 +2422,30 @@ void TouchInputMapper::dump(String8& dump) { pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), + pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, toString(mLastCookedPointerData.isHovering(i))); } - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + if (mDeviceMode == DEVICE_MODE_POINTER) { dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", - mPointerGestureXMovementScale); + mPointerXMovementScale); dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", - mPointerGestureYMovementScale); + mPointerYMovementScale); dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", - mPointerGestureXZoomScale); + mPointerXZoomScale); dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", - mPointerGestureYZoomScale); + mPointerYZoomScale); dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); } } -void TouchInputMapper::initialize() { - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mSentHoverEnter = false; - mDownTime = 0; - - mCurrentVirtualKey.down = false; - - mOrientedRanges.havePressure = false; - mOrientedRanges.haveSize = false; - mOrientedRanges.haveTouchSize = false; - mOrientedRanges.haveToolSize = false; - mOrientedRanges.haveOrientation = false; - mOrientedRanges.haveDistance = false; - - mPointerGesture.reset(); -} - -void TouchInputMapper::configure(const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(config, changes); +void TouchInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); mConfig = *config; @@ -2302,23 +2453,9 @@ void TouchInputMapper::configure(const InputReaderConfiguration* config, uint32_ // Configure basic parameters. configureParameters(); - // Configure sources. - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - mTouchSource = AINPUT_SOURCE_TOUCHSCREEN; - mPointerSource = 0; - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - mTouchSource = AINPUT_SOURCE_TOUCHPAD; - mPointerSource = 0; - break; - case Parameters::DEVICE_TYPE_POINTER: - mTouchSource = AINPUT_SOURCE_TOUCHPAD; - mPointerSource = AINPUT_SOURCE_MOUSE; - break; - default: - LOG_ASSERT(false); - } + // Configure common accumulators. + mCursorScrollAccumulator.configure(getDevice()); + mTouchButtonAccumulator.configure(getDevice()); // Configure absolute axis information. configureRawPointerAxes(); @@ -2326,19 +2463,27 @@ void TouchInputMapper::configure(const InputReaderConfiguration* config, uint32_ // Prepare input device calibration. parseCalibration(); resolveCalibration(); - - // Configure surface dimensions and orientation. - configureSurface(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - mPointerGesture.pointerVelocityControl.setParameters( - mConfig.pointerVelocityControlParameters); + // Update pointer speed. + mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); + mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); + mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); } - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT)) { - // Reset the touch screen when pointer gesture enablement changes. - reset(); + bool resetNeeded = false; + if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO + | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT))) { + // Configure device sources, surface dimensions, orientation and + // scaling factors. + configureSurface(when, &resetNeeded); + } + + if (changes && resetNeeded) { + // Send reset, unless this is the first time the device has been configured, + // in which case the reader will call reset itself after all mappers are ready. + getDevice()->notifyReset(when); } } @@ -2435,8 +2580,8 @@ void TouchInputMapper::dumpParameters(String8& dump) { LOG_ASSERT(false); } - dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n", - mParameters.associatedDisplayId); + dump.appendFormat(INDENT4 "AssociatedDisplay: id=%d, isExternal=%s\n", + mParameters.associatedDisplayId, toString(mParameters.associatedDisplayIsExternal)); dump.appendFormat(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } @@ -2456,47 +2601,79 @@ void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); + dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } -bool TouchInputMapper::configureSurface() { +void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { + int32_t oldDeviceMode = mDeviceMode; + + // Determine device mode. + if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER + && mConfig.pointerGesturesEnabled) { + mSource = AINPUT_SOURCE_MOUSE; + mDeviceMode = DEVICE_MODE_POINTER; + } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN + && mParameters.associatedDisplayId >= 0) { + mSource = AINPUT_SOURCE_TOUCHSCREEN; + mDeviceMode = DEVICE_MODE_DIRECT; + } else { + mSource = AINPUT_SOURCE_TOUCHPAD; + mDeviceMode = DEVICE_MODE_UNSCALED; + } + // Ensure we have valid X and Y axes. if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { LOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " "The device will be inoperable.", getDeviceName().string()); - return false; + mDeviceMode = DEVICE_MODE_DISABLED; + return; } - // Update orientation and dimensions if needed. - int32_t orientation = DISPLAY_ORIENTATION_0; - int32_t width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - + // Get associated display dimensions. if (mParameters.associatedDisplayId >= 0) { - // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. - if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, + if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId, mParameters.associatedDisplayIsExternal, &mAssociatedDisplayWidth, &mAssociatedDisplayHeight, &mAssociatedDisplayOrientation)) { - return false; + LOGI(INDENT "Touch device '%s' could not query the properties of its associated " + "display %d. The device will be inoperable until the display size " + "becomes available.", + getDeviceName().string(), mParameters.associatedDisplayId); + mDeviceMode = DEVICE_MODE_DISABLED; + return; } + } - // A touch screen inherits the dimensions of the display. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { - width = mAssociatedDisplayWidth; - height = mAssociatedDisplayHeight; - } + // Configure dimensions. + int32_t width, height, orientation; + if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { + width = mAssociatedDisplayWidth; + height = mAssociatedDisplayHeight; + orientation = mParameters.orientationAware ? + mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0; + } else { + width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; + height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; + orientation = DISPLAY_ORIENTATION_0; + } + + // If moving between pointer modes, need to reset some state. + bool deviceModeChanged; + if (mDeviceMode != oldDeviceMode) { + deviceModeChanged = true; - // The device inherits the orientation of the display if it is orientation aware. - if (mParameters.orientationAware) { - orientation = mAssociatedDisplayOrientation; + if (mDeviceMode == DEVICE_MODE_POINTER) { + if (mPointerController == NULL) { + mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + } + } else { + mPointerController.clear(); } - } - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER - && mPointerController == NULL) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); + mOrientedRanges.clear(); } bool orientationChanged = mSurfaceOrientation != orientation; @@ -2505,9 +2682,9 @@ bool TouchInputMapper::configureSurface() { } bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height; - if (sizeChanged) { - LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d", - getDeviceId(), getDeviceName().string(), width, height); + if (sizeChanged || deviceModeChanged) { + LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d, mode is %d", + getDeviceId(), getDeviceName().string(), width, height, mDeviceMode); mSurfaceWidth = width; mSurfaceHeight = height; @@ -2519,9 +2696,9 @@ bool TouchInputMapper::configureSurface() { mYPrecision = 1.0f / mYScale; mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mTouchSource; + mOrientedRanges.x.source = mSource; mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mTouchSource; + mOrientedRanges.y.source = mSource; configureVirtualKeys(); @@ -2550,7 +2727,7 @@ bool TouchInputMapper::configureSurface() { mOrientedRanges.haveSize = true; mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mTouchSource; + mOrientedRanges.touchMajor.source = mSource; mOrientedRanges.touchMajor.min = 0; mOrientedRanges.touchMajor.max = diagonalSize; mOrientedRanges.touchMajor.flat = 0; @@ -2560,7 +2737,7 @@ bool TouchInputMapper::configureSurface() { mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mTouchSource; + mOrientedRanges.toolMajor.source = mSource; mOrientedRanges.toolMajor.min = 0; mOrientedRanges.toolMajor.max = diagonalSize; mOrientedRanges.toolMajor.flat = 0; @@ -2570,7 +2747,7 @@ bool TouchInputMapper::configureSurface() { mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mTouchSource; + mOrientedRanges.size.source = mSource; mOrientedRanges.size.min = 0; mOrientedRanges.size.max = 1.0; mOrientedRanges.size.flat = 0; @@ -2581,44 +2758,77 @@ bool TouchInputMapper::configureSurface() { // Pressure factors. mPressureScale = 0; - if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE) { - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL - || mCalibration.pressureCalibration - == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - } else if (mRawPointerAxes.pressure.valid - && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL + || mCalibration.pressureCalibration + == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { + if (mCalibration.havePressureScale) { + mPressureScale = mCalibration.pressureScale; + } else if (mRawPointerAxes.pressure.valid + && mRawPointerAxes.pressure.maxValue != 0) { + mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; } + } - mOrientedRanges.havePressure = true; - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mTouchSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = 1.0; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; + mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; + mOrientedRanges.pressure.source = mSource; + mOrientedRanges.pressure.min = 0; + mOrientedRanges.pressure.max = 1.0; + mOrientedRanges.pressure.flat = 0; + mOrientedRanges.pressure.fuzz = 0; + + // Tilt + mTiltXCenter = 0; + mTiltXScale = 0; + mTiltYCenter = 0; + mTiltYScale = 0; + mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; + if (mHaveTilt) { + mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, + mRawPointerAxes.tiltX.maxValue); + mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, + mRawPointerAxes.tiltY.maxValue); + mTiltXScale = M_PI / 180; + mTiltYScale = M_PI / 180; + + mOrientedRanges.haveTilt = true; + + mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; + mOrientedRanges.tilt.source = mSource; + mOrientedRanges.tilt.min = 0; + mOrientedRanges.tilt.max = M_PI_2; + mOrientedRanges.tilt.flat = 0; + mOrientedRanges.tilt.fuzz = 0; } // Orientation + mOrientationCenter = 0; mOrientationScale = 0; - if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) { + if (mHaveTilt) { + mOrientedRanges.haveOrientation = true; + + mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI; + mOrientedRanges.orientation.max = M_PI; + mOrientedRanges.orientation.flat = 0; + mOrientedRanges.orientation.fuzz = 0; + } else if (mCalibration.orientationCalibration != + Calibration::ORIENTATION_CALIBRATION_NONE) { if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawPointerAxes.orientation.valid - && mRawPointerAxes.orientation.maxValue != 0) { - mOrientationScale = float(M_PI_2) / mRawPointerAxes.orientation.maxValue; + if (mRawPointerAxes.orientation.valid) { + mOrientationCenter = avg(mRawPointerAxes.orientation.minValue, + mRawPointerAxes.orientation.maxValue); + mOrientationScale = M_PI / (mRawPointerAxes.orientation.maxValue - + mRawPointerAxes.orientation.minValue); } } mOrientedRanges.haveOrientation = true; mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mTouchSource; - mOrientedRanges.orientation.min = - M_PI_2; + mOrientedRanges.orientation.source = mSource; + mOrientedRanges.orientation.min = -M_PI_2; mOrientedRanges.orientation.max = M_PI_2; mOrientedRanges.orientation.flat = 0; mOrientedRanges.orientation.fuzz = 0; @@ -2639,7 +2849,7 @@ bool TouchInputMapper::configureSurface() { mOrientedRanges.haveDistance = true; mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mTouchSource; + mOrientedRanges.distance.source = mSource; mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; mOrientedRanges.distance.max = @@ -2650,7 +2860,7 @@ bool TouchInputMapper::configureSurface() { } } - if (orientationChanged || sizeChanged) { + if (orientationChanged || sizeChanged || deviceModeChanged) { // Compute oriented surface dimensions, precision, scales and ranges. // Note that the maximum value reported is an inclusive maximum value so it is one // unit less than the total width or height of surface. @@ -2698,7 +2908,7 @@ bool TouchInputMapper::configureSurface() { } // Compute pointer gesture detection parameters. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { + if (mDeviceMode == DEVICE_MODE_POINTER) { int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; float rawDiagonal = hypotf(rawWidth, rawHeight); @@ -2710,34 +2920,30 @@ bool TouchInputMapper::configureSurface() { // is applied. // Assume that the touch pad has a square aspect ratio such that movements in // X and Y of the same number of raw units cover the same physical distance. - mPointerGestureXMovementScale = mConfig.pointerGestureMovementSpeedRatio + mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; - mPointerGestureYMovementScale = mPointerGestureXMovementScale; + mPointerYMovementScale = mPointerXMovementScale; // Scale zooms to cover a smaller range of the display than movements do. // This value determines the area around the pointer that is affected by freeform // pointer gestures. - mPointerGestureXZoomScale = mConfig.pointerGestureZoomSpeedRatio + mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; - mPointerGestureYZoomScale = mPointerGestureXZoomScale; + mPointerYZoomScale = mPointerXZoomScale; // Max width between pointers to detect a swipe gesture is more than some fraction // of the diagonal axis of the touch pad. Touches that are wider than this are // translated into freeform gestures. mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; + } - // Reset the current pointer gesture. - mPointerGesture.reset(); + // Abort current pointer usages because the state has changed. + abortPointerUsage(when, 0 /*policyFlags*/); - // Remove any current spots. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->clearSpots(); - } - } + // Inform the dispatcher about the changes. + *outResetNeeded = true; } - - return true; } void TouchInputMapper::dumpSurface(String8& dump) { @@ -3023,26 +3229,71 @@ void TouchInputMapper::dumpCalibration(String8& dump) { } } -void TouchInputMapper::reset() { - // Synthesize touch up event. - // This will also take care of finishing virtual key processing if needed. - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); +void TouchInputMapper::reset(nsecs_t when) { + mCursorButtonAccumulator.reset(getDevice()); + mCursorScrollAccumulator.reset(getDevice()); + mTouchButtonAccumulator.reset(getDevice()); + + mPointerVelocityControl.reset(); + mWheelXVelocityControl.reset(); + mWheelYVelocityControl.reset(); + mCurrentRawPointerData.clear(); + mLastRawPointerData.clear(); + mCurrentCookedPointerData.clear(); + mLastCookedPointerData.clear(); mCurrentButtonState = 0; - syncTouch(when, true); + mLastButtonState = 0; + mCurrentRawVScroll = 0; + mCurrentRawHScroll = 0; + mCurrentFingerIdBits.clear(); + mLastFingerIdBits.clear(); + mCurrentStylusIdBits.clear(); + mLastStylusIdBits.clear(); + mCurrentMouseIdBits.clear(); + mLastMouseIdBits.clear(); + mPointerUsage = POINTER_USAGE_NONE; + mSentHoverEnter = false; + mDownTime = 0; - initialize(); + mCurrentVirtualKey.down = false; + + mPointerGesture.reset(); + mPointerSimple.reset(); - if (mPointerController != NULL - && mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { + if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->clearSpots(); } - InputMapper::reset(); + InputMapper::reset(when); } -void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { +void TouchInputMapper::process(const RawEvent* rawEvent) { + mCursorButtonAccumulator.process(rawEvent); + mCursorScrollAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void TouchInputMapper::sync(nsecs_t when) { + // Sync button state. + mCurrentButtonState = mTouchButtonAccumulator.getButtonState() + | mCursorButtonAccumulator.getButtonState(); + + // Sync scroll state. + mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + mCursorScrollAccumulator.finishSync(); + + // Sync touch state. + bool havePointerIds = true; + mCurrentRawPointerData.clear(); + syncTouch(when, &havePointerIds); + #if DEBUG_RAW_EVENTS if (!havePointerIds) { LOGD("syncTouch: pointerCount %d -> %d, no pointer ids", @@ -3060,66 +3311,123 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { } #endif - // Configure the surface now, if possible. - if (!configureSurface()) { - mLastRawPointerData.clear(); - mLastCookedPointerData.clear(); - mLastButtonState = 0; - return; - } + // Reset state that we will compute below. + mCurrentFingerIdBits.clear(); + mCurrentStylusIdBits.clear(); + mCurrentMouseIdBits.clear(); + mCurrentCookedPointerData.clear(); - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } + if (mDeviceMode == DEVICE_MODE_DISABLED) { + // Drop all input if the device is disabled. + mCurrentRawPointerData.clear(); + mCurrentButtonState = 0; + } else { + // Preprocess pointer data. + if (!havePointerIds) { + assignPointerIds(); + } - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - if (mLastRawPointerData.pointerCount == 0 && mCurrentRawPointerData.pointerCount != 0) { - if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { - // If this is a touch screen, hide the pointer on an initial down. - getContext()->fadePointer(); + // Handle policy on initial down or hover events. + uint32_t policyFlags = 0; + if (mLastRawPointerData.pointerCount == 0 && mCurrentRawPointerData.pointerCount != 0) { + if (mDeviceMode == DEVICE_MODE_DIRECT) { + // If this is a touch screen, hide the pointer on an initial down. + getContext()->fadePointer(); + } + + // Initial downs on external touch devices should wake the device. + // We don't do this for internal touch screens to prevent them from waking + // up in your pocket. + // TODO: Use the input device configuration to control this behavior more finely. + if (getDevice()->isExternal()) { + policyFlags |= POLICY_FLAG_WAKE_DROPPED; + } } - // Initial downs on external touch devices should wake the device. - // We don't do this for internal touch screens to prevent them from waking - // up in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - if (getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + policyFlags, mLastButtonState, mCurrentButtonState); + + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawPointerData.clear(); } - } - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mTouchSource, - policyFlags, mLastButtonState, mCurrentButtonState); + // Cook pointer data. This call populates the mCurrentCookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); - } + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mPointerController != NULL) { + for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentStylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentFingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentMouseIdBits.markBit(id); + } + } + for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentStylusIdBits.markBit(id); + } + } - if (mPointerController != NULL && mConfig.pointerGesturesEnabled) { - dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); - } + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentStylusIdBits.isEmpty()) { + mCurrentMouseIdBits.clear(); + mCurrentFingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentMouseIdBits.isEmpty()) { + mCurrentFingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } else { + pointerUsage = POINTER_USAGE_NONE; + } - cookPointerData(); - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + dispatchHoverExit(when, policyFlags); + dispatchTouches(when, policyFlags); + dispatchHoverEnterAndMove(when, policyFlags); + } - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mTouchSource, - policyFlags, mLastButtonState, mCurrentButtonState); + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + policyFlags, mLastButtonState, mCurrentButtonState); + } // Copy current touch to last touch in preparation for the next cycle. mLastRawPointerData.copyFrom(mCurrentRawPointerData); mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); mLastButtonState = mCurrentButtonState; + mLastFingerIdBits = mCurrentFingerIdBits; + mLastStylusIdBits = mCurrentStylusIdBits; + mLastMouseIdBits = mCurrentMouseIdBits; + + // Clear some transient state. + mCurrentRawVScroll = 0; + mCurrentRawHScroll = 0; } void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mPointerController != NULL) { - dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); + if (mPointerUsage == POINTER_USAGE_GESTURES) { + dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); + } } } @@ -3245,7 +3553,7 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { if (!currentIdBits.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedPointerData.pointerProperties, @@ -3280,7 +3588,7 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.clearFirstMarkedBit(); - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, @@ -3295,7 +3603,7 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { LOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, @@ -3314,7 +3622,7 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { mDownTime = when; } - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, @@ -3330,7 +3638,7 @@ void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { (mCurrentCookedPointerData.hoveringIdBits.isEmpty() || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, @@ -3346,7 +3654,7 @@ void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFl && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, @@ -3356,7 +3664,7 @@ void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFl mSentHoverEnter = true; } - dispatchMotion(when, policyFlags, mTouchSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, @@ -3467,30 +3775,40 @@ void TouchInputMapper::cookPointerData() { break; } - // Orientation + // Tilt and Orientation + float tilt; float orientation; - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mOrientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float confidence = hypotf(c1, c2); - float scale = 1.0f + confidence / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; - } else { + if (mHaveTilt) { + float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; + float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; + orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); + tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); + } else { + tilt = 0; + + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + orientation = (in.orientation - mOrientationCenter) * mOrientationScale; + break; + case Calibration::ORIENTATION_CALIBRATION_VECTOR: { + int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); + int32_t c2 = signExtendNybble(in.orientation & 0x0f); + if (c1 != 0 || c2 != 0) { + orientation = atan2f(c1, c2) * 0.5f; + float confidence = hypotf(c1, c2); + float scale = 1.0f + confidence / 16.0f; + touchMajor *= scale; + touchMinor /= scale; + toolMajor *= scale; + toolMinor /= scale; + } else { + orientation = 0; + } + break; + } + default: orientation = 0; } - break; - } - default: - orientation = 0; } // Distance @@ -3545,6 +3863,7 @@ void TouchInputMapper::cookPointerData() { out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); + out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); // Write output properties. @@ -3559,6 +3878,46 @@ void TouchInputMapper::cookPointerData() { } } +void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, + PointerUsage pointerUsage) { + if (pointerUsage != mPointerUsage) { + abortPointerUsage(when, policyFlags); + mPointerUsage = pointerUsage; + } + + switch (mPointerUsage) { + case POINTER_USAGE_GESTURES: + dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); + break; + case POINTER_USAGE_STYLUS: + dispatchPointerStylus(when, policyFlags); + break; + case POINTER_USAGE_MOUSE: + dispatchPointerMouse(when, policyFlags); + break; + default: + break; + } +} + +void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { + switch (mPointerUsage) { + case POINTER_USAGE_GESTURES: + abortPointerGestures(when, policyFlags); + break; + case POINTER_USAGE_STYLUS: + abortPointerStylus(when, policyFlags); + break; + case POINTER_USAGE_MOUSE: + abortPointerMouse(when, policyFlags); + break; + default: + break; + } + + mPointerUsage = POINTER_USAGE_NONE; +} + void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { // Update current gesture coordinates. @@ -3649,7 +4008,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); if (!dispatchedGestureIdBits.isEmpty()) { if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mPointerSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, @@ -3669,7 +4028,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag while (!upGestureIdBits.isEmpty()) { uint32_t id = upGestureIdBits.clearFirstMarkedBit(); - dispatchMotion(when, policyFlags, mPointerSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, @@ -3684,7 +4043,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for all pointers that moved. if (moveNeeded) { - dispatchMotion(when, policyFlags, mPointerSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, @@ -3704,7 +4063,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag mPointerGesture.downTime = when; } - dispatchMotion(when, policyFlags, mPointerSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, @@ -3715,7 +4074,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mPointerSource, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, @@ -3741,7 +4100,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - NotifyMotionArgs args(when, getDeviceId(), mPointerSource, policyFlags, + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime); @@ -3766,6 +4125,31 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag } } +void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { + // Cancel previously dispatches pointers. + if (!mPointerGesture.lastGestureIdBits.isEmpty()) { + int32_t metaState = getContext()->getGlobalMetaState(); + int32_t buttonState = mCurrentButtonState; + dispatchMotion(when, policyFlags, mSource, + AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, + AMOTION_EVENT_EDGE_FLAG_NONE, + mPointerGesture.lastGestureProperties, + mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, + mPointerGesture.lastGestureIdBits, -1, + 0, 0, mPointerGesture.downTime); + } + + // Reset the current pointer gesture. + mPointerGesture.reset(); + mPointerVelocityControl.reset(); + + // Remove any current spots. + if (mPointerController != NULL) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + mPointerController->clearSpots(); + } +} + bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { *outCancelPreviousGesture = false; @@ -3793,7 +4177,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.pointerVelocityControl.reset(); + mPointerVelocityControl.reset(); return true; } } @@ -3802,18 +4186,21 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return false; } + const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); + const uint32_t lastFingerCount = mLastFingerIdBits.count(); + // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); count++) { + for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { uint32_t id = idBits.clearFirstMarkedBit(); const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - positions[count].x = pointer.x * mPointerGestureXMovementScale; - positions[count].y = pointer.y * mPointerGestureYMovementScale; + positions[count].x = pointer.x * mPointerXMovementScale; + positions[count].y = pointer.y * mPointerYMovementScale; } mPointerGesture.velocityTracker.addMovement(when, - mCurrentRawPointerData.touchingIdBits, positions); + mCurrentFingerIdBits, positions); } // Pick a new active touch id if needed. @@ -3825,25 +4212,22 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { - if (!mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (!mCurrentFingerIdBits.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = - mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); + mCurrentFingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } - } else if (!mCurrentRawPointerData.touchingIdBits.hasBit(activeTouchId)) { + } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { activeTouchChanged = true; - if (!mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (!mCurrentFingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = - mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); + mCurrentFingerIdBits.firstMarkedBit(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } } - uint32_t currentTouchingPointerCount = mCurrentRawPointerData.touchingIdBits.count(); - uint32_t lastTouchingPointerCount = mLastRawPointerData.touchingIdBits.count(); - // Determine whether we are in quiet time. bool isQuietTime = false; if (activeTouchId < 0) { @@ -3854,13 +4238,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || mPointerGesture.lastGestureMode == PointerGesture::SWIPE || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) - && currentTouchingPointerCount < 2) { + && currentFingerCount < 2) { // Enter quiet time when exiting swipe or freeform state. // This is to prevent accidentally entering the hover state and flinging the // pointer when finishing a swipe and there is still one pointer left onscreen. isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - && currentTouchingPointerCount >= 2 + && currentFingerCount >= 2 && !isPointerDown(mCurrentButtonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button @@ -3888,7 +4272,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.pointerVelocityControl.reset(); + mPointerVelocityControl.reset(); } else if (isPointerDown(mCurrentButtonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. @@ -3905,7 +4289,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // being dragged. #if DEBUG_GESTURES LOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentTouchingPointerCount=%d", activeTouchId, currentTouchingPointerCount); + "currentFingerCount=%d", activeTouchId, currentFingerCount); #endif // Reset state when just starting. if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { @@ -3915,10 +4299,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Switch pointers if needed. // Find the fastest pointer and follow it. - if (activeTouchId >= 0 && currentTouchingPointerCount > 1) { + if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { + for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { @@ -3939,23 +4323,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - if (activeTouchId >= 0 && mLastRawPointerData.touchingIdBits.hasBit(activeTouchId)) { + if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = mCurrentRawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) * mPointerGestureXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) * mPointerGestureYMovementScale; + float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; + float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. mPointerController->move(deltaX, deltaY); } else { - mPointerGesture.pointerVelocityControl.reset(); + mPointerVelocityControl.reset(); } float x, y; @@ -3972,7 +4356,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (currentTouchingPointerCount == 0) { + } else if (currentFingerCount == 0) { // Case 3. No fingers down and button is not pressed. (NEUTRAL) if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { *outFinishPreviousGesture = true; @@ -3983,7 +4367,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool tapped = false; if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) - && lastTouchingPointerCount == 1) { + && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { float x, y; mPointerController->getPosition(&x, &y); @@ -4033,7 +4417,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - mPointerGesture.pointerVelocityControl.reset(); + mPointerVelocityControl.reset(); if (!tapped) { #if DEBUG_GESTURES @@ -4043,7 +4427,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIdBits.clear(); } - } else if (currentTouchingPointerCount == 1) { + } else if (currentFingerCount == 1) { // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) // The pointer follows the active touch point. // When in HOVER, emit HOVER_MOVE events at the pointer location. @@ -4075,24 +4459,24 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } - if (mLastRawPointerData.touchingIdBits.hasBit(activeTouchId)) { + if (mLastFingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = mCurrentRawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = mLastRawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) - * mPointerGestureXMovementScale; + * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) - * mPointerGestureYMovementScale; + * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. mPointerController->move(deltaX, deltaY); } else { - mPointerGesture.pointerVelocityControl.reset(); + mPointerVelocityControl.reset(); } bool down; @@ -4128,7 +4512,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - if (lastTouchingPointerCount == 0 && currentTouchingPointerCount != 0) { + if (lastFingerCount == 0 && currentFingerCount != 0) { mPointerGesture.resetTap(); mPointerGesture.tapDownTime = when; mPointerGesture.tapX = x; @@ -4156,7 +4540,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { *outFinishPreviousGesture = true; - } else if (!settled && currentTouchingPointerCount > lastTouchingPointerCount) { + } else if (!settled && currentFingerCount > lastFingerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES @@ -4175,7 +4559,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; mPointerGesture.referenceIdBits.clear(); - mPointerGesture.pointerVelocityControl.reset(); + mPointerVelocityControl.reset(); // Use the centroid and pointer location as the reference points for the gesture. #if DEBUG_GESTURES @@ -4192,18 +4576,18 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits.value + for (BitSet32 idBits(mCurrentFingerIdBits.value & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; } - mPointerGesture.referenceIdBits = mCurrentRawPointerData.touchingIdBits; + mPointerGesture.referenceIdBits = mCurrentFingerIdBits; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastRawPointerData.touchingIdBits.value - & mCurrentRawPointerData.touchingIdBits.value); + BitSet32 commonIdBits(mLastFingerIdBits.value + & mCurrentFingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { bool first = (idBits == commonIdBits); uint32_t id = idBits.clearFirstMarkedBit(); @@ -4229,8 +4613,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - dist[id] = hypotf(delta.dx * mPointerGestureXZoomScale, - delta.dy * mPointerGestureYZoomScale); + dist[id] = hypotf(delta.dx * mPointerXZoomScale, + delta.dy * mPointerYZoomScale); if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { distOverThreshold += 1; } @@ -4239,17 +4623,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Only transition when at least two pointers have moved further than // the minimum distance threshold. if (distOverThreshold >= 2) { - if (currentTouchingPointerCount > 2) { + if (currentFingerCount > 2) { // There are more than two pointers, switch to FREEFORM. #if DEBUG_GESTURES LOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentTouchingPointerCount); + currentFingerCount); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. - BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); + BitSet32 idBits(mCurrentFingerIdBits); uint32_t id1 = idBits.clearFirstMarkedBit(); uint32_t id2 = idBits.firstMarkedBit(); const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); @@ -4277,10 +4661,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dx1 = delta1.dx * mPointerGestureXZoomScale; - float dy1 = delta1.dy * mPointerGestureYZoomScale; - float dx2 = delta2.dx * mPointerGestureXZoomScale; - float dy2 = delta2.dy * mPointerGestureYZoomScale; + float dx1 = delta1.dx * mPointerXZoomScale; + float dy1 = delta1.dy * mPointerYZoomScale; + float dx2 = delta2.dx * mPointerXZoomScale; + float dy2 = delta2.dy * mPointerYZoomScale; float dot = dx1 * dx2 + dy1 * dy2; float cosine = dot / (dist1 * dist2); // denominator always > 0 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { @@ -4314,10 +4698,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { // Switch from SWIPE to FREEFORM if additional pointers go down. // Cancel previous gesture. - if (currentTouchingPointerCount > 2) { + if (currentFingerCount > 2) { #if DEBUG_GESTURES LOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentTouchingPointerCount); + currentFingerCount); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; @@ -4338,11 +4722,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.referenceTouchX += commonDeltaX; mPointerGesture.referenceTouchY += commonDeltaY; - commonDeltaX *= mPointerGestureXMovementScale; - commonDeltaY *= mPointerGestureYMovementScale; + commonDeltaX *= mPointerXMovementScale; + commonDeltaY *= mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); - mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); + mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); mPointerGesture.referenceGestureX += commonDeltaX; mPointerGesture.referenceGestureY += commonDeltaY; @@ -4355,7 +4739,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, #if DEBUG_GESTURES LOGD("Gestures: PRESS or SWIPE activeTouchId=%d," "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentTouchingPointerCount); + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); #endif LOG_ASSERT(mPointerGesture.activeGestureId >= 0); @@ -4377,7 +4761,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, #if DEBUG_GESTURES LOGD("Gestures: FREEFORM activeTouchId=%d," "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentTouchingPointerCount); + activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); #endif LOG_ASSERT(mPointerGesture.activeGestureId >= 0); @@ -4399,14 +4783,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastRawPointerData.touchingIdBits.value - & mCurrentRawPointerData.touchingIdBits.value; + mappedTouchIdBits.value = mLastFingerIdBits.value + & mCurrentFingerIdBits.value; usedGestureIdBits = mPointerGesture.lastGestureIdBits; // Check whether we need to choose a new active gesture id because the // current went went up. - for (BitSet32 upTouchIdBits(mLastRawPointerData.touchingIdBits.value - & ~mCurrentRawPointerData.touchingIdBits.value); + for (BitSet32 upTouchIdBits(mLastFingerIdBits.value + & ~mCurrentFingerIdBits.value); !upTouchIdBits.isEmpty(); ) { uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; @@ -4425,8 +4809,8 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId); #endif - BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); - for (uint32_t i = 0; i < currentTouchingPointerCount; i++) { + BitSet32 idBits(mCurrentFingerIdBits); + for (uint32_t i = 0; i < currentFingerCount; i++) { uint32_t touchId = idBits.clearFirstMarkedBit(); uint32_t gestureId; if (!mappedTouchIdBits.hasBit(touchId)) { @@ -4451,9 +4835,9 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) - * mPointerGestureXZoomScale; + * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) - * mPointerGestureYZoomScale; + * mPointerYZoomScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerGesture.currentGestureProperties[i].clear(); @@ -4517,6 +4901,215 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return true; } +void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + bool down, hovering; + if (!mCurrentStylusIdBits.isEmpty()) { + uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedPointerData.idToIndex[id]; + float x = mCurrentCookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedPointerData.pointerCoords[index].getY(); + mPointerController->setPosition(x, y); + + hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); + down = !hovering; + + mPointerController->getPosition(&x, &y); + mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerSimple.currentProperties.id = 0; + mPointerSimple.currentProperties.toolType = + mCurrentCookedPointerData.pointerProperties[index].toolType; + } else { + down = false; + hovering = false; + } + + dispatchPointerSimple(when, policyFlags, down, hovering); +} + +void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { + abortPointerSimple(when, policyFlags); +} + +void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + bool down, hovering; + if (!mCurrentMouseIdBits.isEmpty()) { + uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; + if (mLastMouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; + float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x + - mLastRawPointerData.pointers[lastIndex].x) + * mPointerXMovementScale; + float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y + - mLastRawPointerData.pointers[lastIndex].y) + * mPointerYMovementScale; + + rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); + mPointerVelocityControl.move(when, &deltaX, &deltaY); + + mPointerController->move(deltaX, deltaY); + } else { + mPointerVelocityControl.reset(); + } + + down = isPointerDown(mCurrentButtonState); + hovering = !down; + + float x, y; + mPointerController->getPosition(&x, &y); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedPointerData.pointerCoords[currentIndex]); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, + hovering ? 0.0f : 1.0f); + mPointerSimple.currentProperties.id = 0; + mPointerSimple.currentProperties.toolType = + mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; + } else { + mPointerVelocityControl.reset(); + + down = false; + hovering = false; + } + + dispatchPointerSimple(when, policyFlags, down, hovering); +} + +void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { + abortPointerSimple(when, policyFlags); + + mPointerVelocityControl.reset(); +} + +void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, + bool down, bool hovering) { + int32_t metaState = getContext()->getGlobalMetaState(); + + if (mPointerController != NULL) { + if (down || hovering) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + mPointerController->clearSpots(); + mPointerController->setButtonState(mCurrentButtonState); + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); + } + } + + if (mPointerSimple.down && !down) { + mPointerSimple.down = false; + + // Send up. + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, + 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + if (mPointerSimple.hovering && !hovering) { + mPointerSimple.hovering = false; + + // Send hover exit. + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, + 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + if (down) { + if (!mPointerSimple.down) { + mPointerSimple.down = true; + mPointerSimple.downTime = when; + + // Send down. + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + // Send move. + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + if (hovering) { + if (!mPointerSimple.hovering) { + mPointerSimple.hovering = true; + + // Send hover enter. + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + // Send hover move. + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, + 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + if (mCurrentRawVScroll || mCurrentRawHScroll) { + float vscroll = mCurrentRawVScroll; + float hscroll = mCurrentRawHScroll; + mWheelYVelocityControl.move(when, NULL, &vscroll); + mWheelXVelocityControl.move(when, &hscroll, NULL); + + // Send scroll. + PointerCoords pointerCoords; + pointerCoords.copyFrom(mPointerSimple.currentCoords); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); + + NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, + 1, &mPointerSimple.currentProperties, &pointerCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.downTime); + getListener()->notifyMotion(&args); + } + + // Save state. + if (down || hovering) { + mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); + mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); + } else { + mPointerSimple.reset(); + } +} + +void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { + mPointerSimple.currentCoords.clear(); + mPointerSimple.currentProperties.clear(); + + dispatchPointerSimple(when, policyFlags, false, false); +} + void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, @@ -4862,44 +5455,32 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) { - clearState(); } SingleTouchInputMapper::~SingleTouchInputMapper() { } -void SingleTouchInputMapper::clearState() { - mCursorButtonAccumulator.clearButtons(); - mTouchButtonAccumulator.clearButtons(); - mSingleTouchMotionAccumulator.clearAbsoluteAxes(); -} +void SingleTouchInputMapper::reset(nsecs_t when) { + mSingleTouchMotionAccumulator.reset(getDevice()); -void SingleTouchInputMapper::reset() { - TouchInputMapper::reset(); - - clearState(); - } + TouchInputMapper::reset(when); +} void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - mSingleTouchMotionAccumulator.process(rawEvent); + TouchInputMapper::process(rawEvent); - if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { - sync(rawEvent->when); - } + mSingleTouchMotionAccumulator.process(rawEvent); } -void SingleTouchInputMapper::sync(nsecs_t when) { - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - +void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { if (mTouchButtonAccumulator.isToolActive()) { mCurrentRawPointerData.pointerCount = 1; mCurrentRawPointerData.idToIndex[0] = 0; - bool isHovering = mTouchButtonAccumulator.isHovering() - || mSingleTouchMotionAccumulator.getAbsoluteDistance() > 0; + bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE + && (mTouchButtonAccumulator.isHovering() + || (mRawPointerAxes.pressure.valid + && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); mCurrentRawPointerData.markIdBit(0, isHovering); RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; @@ -4913,29 +5494,26 @@ void SingleTouchInputMapper::sync(nsecs_t when) { outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); outPointer.orientation = 0; outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); + outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); + outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } outPointer.isHovering = isHovering; } - - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() - | mCursorButtonAccumulator.getButtonState(); - - syncTouch(when, true); } void SingleTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); - mTouchButtonAccumulator.configure(getDevice()); - getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); + getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); + getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); } @@ -4948,58 +5526,25 @@ MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : MultiTouchInputMapper::~MultiTouchInputMapper() { } -void MultiTouchInputMapper::clearState() { - mCursorButtonAccumulator.clearButtons(); - mTouchButtonAccumulator.clearButtons(); - mPointerIdBits.clear(); +void MultiTouchInputMapper::reset(nsecs_t when) { + mMultiTouchMotionAccumulator.reset(getDevice()); - if (mMultiTouchMotionAccumulator.isUsingSlotsProtocol()) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - status_t status = getEventHub()->getAbsoluteAxisValue(getDeviceId(), ABS_MT_SLOT, - &initialSlot); - if (status) { - LOGW("Could not retrieve current multitouch slot index. status=%d", status); - initialSlot = -1; - } - mMultiTouchMotionAccumulator.clearSlots(initialSlot); - } else { - mMultiTouchMotionAccumulator.clearSlots(-1); - } -} - -void MultiTouchInputMapper::reset() { - TouchInputMapper::reset(); + mPointerIdBits.clear(); - clearState(); + TouchInputMapper::reset(when); } void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - mMultiTouchMotionAccumulator.process(rawEvent); + TouchInputMapper::process(rawEvent); - if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { - sync(rawEvent->when); - } + mMultiTouchMotionAccumulator.process(rawEvent); } -void MultiTouchInputMapper::sync(nsecs_t when) { +void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; - bool havePointerIds = true; BitSet32 newPointerIdBits; - mCurrentRawPointerData.clear(); - for (size_t inIndex = 0; inIndex < inCount; inIndex++) { const MultiTouchMotionAccumulator::Slot* inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); @@ -5026,6 +5571,8 @@ void MultiTouchInputMapper::sync(nsecs_t when) { outPointer.toolMinor = inSlot->getToolMinor(); outPointer.orientation = inSlot->getOrientation(); outPointer.distance = inSlot->getDistance(); + outPointer.tiltX = 0; + outPointer.tiltY = 0; outPointer.toolType = inSlot->getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { @@ -5035,12 +5582,13 @@ void MultiTouchInputMapper::sync(nsecs_t when) { } } - bool isHovering = mTouchButtonAccumulator.isHovering() - || inSlot->getDistance() > 0; + bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE + && (mTouchButtonAccumulator.isHovering() + || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. - if (havePointerIds) { + if (*outHavePointerIds) { int32_t trackingId = inSlot->getTrackingId(); int32_t id = -1; if (trackingId >= 0) { @@ -5057,7 +5605,7 @@ void MultiTouchInputMapper::sync(nsecs_t when) { } } if (id < 0) { - havePointerIds = false; + *outHavePointerIds = false; mCurrentRawPointerData.clearIdBits(); newPointerIdBits.clear(); } else { @@ -5072,23 +5620,14 @@ void MultiTouchInputMapper::sync(nsecs_t when) { } mCurrentRawPointerData.pointerCount = outCount; - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() - | mCursorButtonAccumulator.getButtonState(); - mPointerIdBits = newPointerIdBits; - syncTouch(when, havePointerIds); - - if (!mMultiTouchMotionAccumulator.isUsingSlotsProtocol()) { - mMultiTouchMotionAccumulator.clearSlots(-1); - } + mMultiTouchMotionAccumulator.finishSync(); } void MultiTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); - mTouchButtonAccumulator.configure(getDevice()); - getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); @@ -5115,8 +5654,6 @@ void MultiTouchInputMapper::configureRawPointerAxes() { } else { mMultiTouchMotionAccumulator.configure(MAX_POINTERS, false /*usingSlotsProtocol*/); } - - clearState(); } @@ -5184,8 +5721,9 @@ void JoystickInputMapper::dump(String8& dump) { } } -void JoystickInputMapper::configure(const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(config, changes); +void JoystickInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + InputMapper::configure(when, config, changes); if (!changes) { // first time only // Collect all axes. @@ -5314,19 +5852,15 @@ bool JoystickInputMapper::isCenteredAxis(int32_t axis) { } } -void JoystickInputMapper::reset() { +void JoystickInputMapper::reset(nsecs_t when) { // Recenter all axes. - nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); axis.resetValue(); } - sync(when, true /*force*/); - - InputMapper::reset(); + InputMapper::reset(when); } void JoystickInputMapper::process(const RawEvent* rawEvent) { diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 72802fc..76d77f1 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -53,6 +53,9 @@ struct InputReaderConfiguration { // The pointer gesture control changed. CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1, + // The display size or orientation changed. + CHANGE_DISPLAY_INFO = 1 << 2, + // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, }; @@ -153,6 +156,26 @@ struct InputReaderConfiguration { pointerGestureSwipeMaxWidthRatio(0.25f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f) { } + + bool getDisplayInfo(int32_t displayId, bool external, + int32_t* width, int32_t* height, int32_t* orientation) const; + + void setDisplayInfo(int32_t displayId, bool external, + int32_t width, int32_t height, int32_t orientation); + +private: + struct DisplayInfo { + int32_t width; + int32_t height; + int32_t orientation; + + DisplayInfo() : + width(-1), height(-1), orientation(DISPLAY_ORIENTATION_0) { + } + }; + + DisplayInfo mInternalDisplay; + DisplayInfo mExternalDisplay; }; @@ -174,22 +197,6 @@ protected: virtual ~InputReaderPolicyInterface() { } public: - /* Display orientations. */ - enum { - ROTATION_0 = 0, - ROTATION_90 = 1, - ROTATION_180 = 2, - ROTATION_270 = 3 - }; - - /* Gets information about the display with the specified id. - * If external is true, returns the size of the external mirrored - * counterpart of the specified display. - * Returns true if the display info is available, false otherwise. - */ - virtual bool getDisplayInfo(int32_t displayId, bool external, - int32_t* width, int32_t* height, int32_t* orientation) = 0; - /* Gets the input reader configuration. */ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; @@ -364,8 +371,8 @@ private: // low-level input event decoding and device management void processEventsLocked(const RawEvent* rawEvents, size_t count); - void addDeviceLocked(int32_t deviceId); - void removeDeviceLocked(int32_t deviceId); + void addDeviceLocked(nsecs_t when, int32_t deviceId); + void removeDeviceLocked(nsecs_t when, int32_t deviceId); void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); void timeoutExpiredLocked(nsecs_t when); @@ -431,8 +438,8 @@ public: void dump(String8& dump); void addMapper(InputMapper* mapper); - void configure(const InputReaderConfiguration* config, uint32_t changes); - void reset(); + void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); @@ -447,9 +454,25 @@ public: void fadePointer(); + void notifyReset(nsecs_t when); + inline const PropertyMap& getConfiguration() { return mConfiguration; } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } + bool hasKey(int32_t code) { + return getEventHub()->hasScanCode(mId, code); + } + + bool isKeyPressed(int32_t code) { + return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; + } + + int32_t getAbsoluteAxisValue(int32_t code) { + int32_t value; + getEventHub()->getAbsoluteAxisValue(mId, code, &value); + return value; + } + private: InputReaderContext* mContext; int32_t mId; @@ -472,8 +495,8 @@ private: class CursorButtonAccumulator { public: CursorButtonAccumulator(); + void reset(InputDevice* device); - void clearButtons(); void process(const RawEvent* rawEvent); uint32_t getButtonState() const; @@ -487,6 +510,8 @@ private: bool mBtnForward; bool mBtnExtra; bool mBtnTask; + + void clearButtons(); }; @@ -495,10 +520,32 @@ private: class CursorMotionAccumulator { public: CursorMotionAccumulator(); - void configure(InputDevice* device); + void reset(InputDevice* device); + + void process(const RawEvent* rawEvent); + void finishSync(); + + inline int32_t getRelativeX() const { return mRelX; } + inline int32_t getRelativeY() const { return mRelY; } + +private: + int32_t mRelX; + int32_t mRelY; void clearRelativeAxes(); +}; + + +/* Keeps track of cursor scrolling motions. */ + +class CursorScrollAccumulator { +public: + CursorScrollAccumulator(); + void configure(InputDevice* device); + void reset(InputDevice* device); + void process(const RawEvent* rawEvent); + void finishSync(); inline bool haveRelativeVWheel() const { return mHaveRelWheel; } inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } @@ -516,6 +563,8 @@ private: int32_t mRelY; int32_t mRelWheel; int32_t mRelHWheel; + + void clearRelativeAxes(); }; @@ -524,8 +573,8 @@ class TouchButtonAccumulator { public: TouchButtonAccumulator(); void configure(InputDevice* device); + void reset(InputDevice* device); - void clearButtons(); void process(const RawEvent* rawEvent); uint32_t getButtonState() const; @@ -542,6 +591,13 @@ private: bool mBtnToolFinger; bool mBtnToolPen; bool mBtnToolRubber; + bool mBtnToolBrush; + bool mBtnToolPencil; + bool mBtnToolAirbrush; + bool mBtnToolMouse; + bool mBtnToolLens; + + void clearButtons(); }; @@ -556,6 +612,8 @@ struct RawPointerAxes { RawAbsoluteAxisInfo toolMinor; RawAbsoluteAxisInfo orientation; RawAbsoluteAxisInfo distance; + RawAbsoluteAxisInfo tiltX; + RawAbsoluteAxisInfo tiltY; RawAbsoluteAxisInfo trackingId; RawAbsoluteAxisInfo slot; @@ -577,6 +635,8 @@ struct RawPointerData { int32_t toolMinor; int32_t orientation; int32_t distance; + int32_t tiltX; + int32_t tiltY; int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant bool isHovering; }; @@ -637,14 +697,16 @@ class SingleTouchMotionAccumulator { public: SingleTouchMotionAccumulator(); - void clearAbsoluteAxes(); void process(const RawEvent* rawEvent); + void reset(InputDevice* device); inline int32_t getAbsoluteX() const { return mAbsX; } inline int32_t getAbsoluteY() const { return mAbsY; } inline int32_t getAbsolutePressure() const { return mAbsPressure; } inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } inline int32_t getAbsoluteDistance() const { return mAbsDistance; } + inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } + inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } private: int32_t mAbsX; @@ -652,6 +714,10 @@ private: int32_t mAbsPressure; int32_t mAbsToolWidth; int32_t mAbsDistance; + int32_t mAbsTiltX; + int32_t mAbsTiltY; + + void clearAbsoluteAxes(); }; @@ -703,11 +769,10 @@ public: ~MultiTouchMotionAccumulator(); void configure(size_t slotCount, bool usingSlotsProtocol); + void reset(InputDevice* device); void process(const RawEvent* rawEvent); + void finishSync(); - void clearSlots(int32_t initialSlot); - - inline bool isUsingSlotsProtocol() const { return mUsingSlotsProtocol; } inline size_t getSlotCount() const { return mSlotCount; } inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } @@ -716,12 +781,22 @@ private: Slot* mSlots; size_t mSlotCount; bool mUsingSlotsProtocol; + + void clearSlots(int32_t initialSlot); }; /* An input mapper transforms raw input events into cooked event data. * A single input device can have multiple associated input mappers in order to interpret * different classes of events. + * + * InputMapper lifecycle: + * - create + * - configure with 0 changes + * - reset + * - process, process, process (may occasionally reconfigure with non-zero changes or reset) + * - reset + * - destroy */ class InputMapper { public: @@ -739,8 +814,8 @@ public: virtual uint32_t getSources() = 0; virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); - virtual void configure(const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent) = 0; virtual void timeoutExpired(nsecs_t when); @@ -788,8 +863,8 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); - virtual void configure(const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); @@ -800,8 +875,6 @@ public: virtual int32_t getMetaState(); private: - Mutex mLock; - struct KeyDown { int32_t keyCode; int32_t scanCode; @@ -810,6 +883,8 @@ private: uint32_t mSource; int32_t mKeyboardType; + int32_t mOrientation; // orientation for dpad keys + Vector<KeyDown> mKeyDowns; // keys that are down int32_t mMetaState; nsecs_t mDownTime; // time of most recent key down @@ -828,8 +903,6 @@ private: bool orientationAware; } mParameters; - void initialize(); - void configureParameters(); void dumpParameters(String8& dump); @@ -856,8 +929,8 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); - virtual void configure(const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); @@ -882,6 +955,7 @@ private: CursorButtonAccumulator mCursorButtonAccumulator; CursorMotionAccumulator mCursorMotionAccumulator; + CursorScrollAccumulator mCursorScrollAccumulator; int32_t mSource; float mXScale; @@ -898,13 +972,13 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + int32_t mOrientation; + sp<PointerControllerInterface> mPointerController; int32_t mButtonState; nsecs_t mDownTime; - void initialize(); - void configureParameters(); void dumpParameters(String8& dump); @@ -920,8 +994,9 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); - virtual void configure(const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); @@ -932,6 +1007,10 @@ public: virtual void timeoutExpired(nsecs_t when); protected: + CursorButtonAccumulator mCursorButtonAccumulator; + CursorScrollAccumulator mCursorScrollAccumulator; + TouchButtonAccumulator mTouchButtonAccumulator; + struct VirtualKey { int32_t keyCode; int32_t scanCode; @@ -948,9 +1027,16 @@ protected: } }; - // Input sources supported by the device. - uint32_t mTouchSource; // sources when reporting touch data - uint32_t mPointerSource; // sources when reporting pointer gestures + // Input sources and device mode. + uint32_t mSource; + + enum DeviceMode { + DEVICE_MODE_DISABLED, // input is disabled + DEVICE_MODE_DIRECT, // direct mapping (touchscreen) + DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) + DEVICE_MODE_POINTER, // pointer mapping (pointer) + }; + DeviceMode mDeviceMode; // The reader's configuration. InputReaderConfiguration mConfig; @@ -1053,6 +1139,18 @@ protected: int32_t mCurrentButtonState; int32_t mLastButtonState; + // Scroll state. + int32_t mCurrentRawVScroll; + int32_t mCurrentRawHScroll; + + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 mCurrentFingerIdBits; // finger or unknown + BitSet32 mLastFingerIdBits; + BitSet32 mCurrentStylusIdBits; // stylus or eraser + BitSet32 mLastStylusIdBits; + BitSet32 mCurrentMouseIdBits; // mouse or lens + BitSet32 mLastMouseIdBits; + // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; @@ -1068,7 +1166,7 @@ protected: virtual void dumpParameters(String8& dump); virtual void configureRawPointerAxes(); virtual void dumpRawPointerAxes(String8& dump); - virtual bool configureSurface(); + virtual void configureSurface(nsecs_t when, bool* outResetNeeded); virtual void dumpSurface(String8& dump); virtual void configureVirtualKeys(); virtual void dumpVirtualKeys(String8& dump); @@ -1076,7 +1174,7 @@ protected: virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); - void syncTouch(nsecs_t when, bool havePointerIds); + virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; private: // The surface orientation and width and height set by configureSurface(). @@ -1102,16 +1200,21 @@ private: float mSizeScale; + float mOrientationCenter; float mOrientationScale; float mDistanceScale; + bool mHaveTilt; + float mTiltXCenter; + float mTiltXScale; + float mTiltYCenter; + float mTiltYScale; + // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; InputDeviceInfo::MotionRange y; - - bool havePressure; InputDeviceInfo::MotionRange pressure; bool haveSize; @@ -1130,6 +1233,22 @@ private: bool haveDistance; InputDeviceInfo::MotionRange distance; + + bool haveTilt; + InputDeviceInfo::MotionRange tilt; + + OrientedRanges() { + clear(); + } + + void clear() { + haveSize = false; + haveTouchSize = false; + haveToolSize = false; + haveOrientation = false; + haveDistance = false; + haveTilt = false; + } } mOrientedRanges; // Oriented dimensions and precision. @@ -1146,13 +1265,13 @@ private: int32_t scanCode; } mCurrentVirtualKey; - // Scale factor for gesture based pointer movements. - float mPointerGestureXMovementScale; - float mPointerGestureYMovementScale; + // Scale factor for gesture or mouse based pointer movements. + float mPointerXMovementScale; + float mPointerYMovementScale; // Scale factor for gesture based zooming and other freeform motions. - float mPointerGestureXZoomScale; - float mPointerGestureYZoomScale; + float mPointerXZoomScale; + float mPointerYZoomScale; // The maximum swipe width. float mPointerGestureMaxSwipeWidth; @@ -1163,6 +1282,14 @@ private: uint64_t distance : 48; // squared distance }; + enum PointerUsage { + POINTER_USAGE_NONE, + POINTER_USAGE_GESTURES, + POINTER_USAGE_STYLUS, + POINTER_USAGE_MOUSE, + }; + PointerUsage mPointerUsage; + struct PointerGesture { enum Mode { // No fingers, button is not pressed. @@ -1273,9 +1400,6 @@ private: // A velocity tracker for determining whether to switch active pointers during drags. VelocityTracker velocityTracker; - // Velocity control for pointer movements. - VelocityControl pointerVelocityControl; - void reset() { firstTouchTime = LLONG_MIN; activeTouchId = -1; @@ -1288,7 +1412,6 @@ private: velocityTracker.clear(); resetTap(); resetQuietTime(); - pointerVelocityControl.reset(); } void resetTap() { @@ -1301,7 +1424,38 @@ private: } } mPointerGesture; - void initialize(); + struct PointerSimple { + PointerCoords currentCoords; + PointerProperties currentProperties; + PointerCoords lastCoords; + PointerProperties lastProperties; + + // True if the pointer is down. + bool down; + + // True if the pointer is hovering. + bool hovering; + + // Time the pointer last went down. + nsecs_t downTime; + + void reset() { + currentCoords.clear(); + currentProperties.clear(); + lastCoords.clear(); + lastProperties.clear(); + down = false; + hovering = false; + downTime = 0; + } + } mPointerSimple; + + // The pointer and scroll velocity controls. + VelocityControl mPointerVelocityControl; + VelocityControl mWheelXVelocityControl; + VelocityControl mWheelYVelocityControl; + + void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, @@ -1312,9 +1466,24 @@ private: void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); void cookPointerData(); + void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); + void abortPointerUsage(nsecs_t when, uint32_t policyFlags); + void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); + void abortPointerGestures(nsecs_t when, uint32_t policyFlags); bool preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout); + bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, + bool isTimeout); + + void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); + void abortPointerStylus(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); + void abortPointerMouse(nsecs_t when, uint32_t policyFlags); + + void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, + bool down, bool hovering); + void abortPointerSimple(nsecs_t when, uint32_t policyFlags); // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the @@ -1346,20 +1515,15 @@ public: SingleTouchInputMapper(InputDevice* device); virtual ~SingleTouchInputMapper(); - virtual void reset(); + virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); protected: + virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); virtual void configureRawPointerAxes(); private: - CursorButtonAccumulator mCursorButtonAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; - - void clearState(); - - void sync(nsecs_t when); }; @@ -1368,24 +1532,19 @@ public: MultiTouchInputMapper(InputDevice* device); virtual ~MultiTouchInputMapper(); - virtual void reset(); + virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); protected: + virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); virtual void configureRawPointerAxes(); private: - CursorButtonAccumulator mCursorButtonAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; // Specifies the pointer id bits that are in use, and their associated tracking id. BitSet32 mPointerIdBits; int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; - - void clearState(); - - void sync(nsecs_t when); }; @@ -1397,8 +1556,8 @@ public: virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); - virtual void configure(const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); private: diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index ebf66aa..4796958 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -125,13 +125,6 @@ private: // --- FakeInputReaderPolicy --- class FakeInputReaderPolicy : public InputReaderPolicyInterface { - struct DisplayInfo { - int32_t width; - int32_t height; - int32_t orientation; - }; - - KeyedVector<int32_t, DisplayInfo> mDisplayInfos; InputReaderConfiguration mConfig; KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers; @@ -142,18 +135,10 @@ public: FakeInputReaderPolicy() { } - void removeDisplayInfo(int32_t displayId) { - mDisplayInfos.removeItem(displayId); - } - void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { - removeDisplayInfo(displayId); - - DisplayInfo info; - info.width = width; - info.height = height; - info.orientation = orientation; - mDisplayInfos.add(displayId, info); + // Set the size of both the internal and external display at the same time. + mConfig.setDisplayInfo(displayId, false /*external*/, width, height, orientation); + mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation); } virtual nsecs_t getVirtualKeyQuietTime() { @@ -168,26 +153,11 @@ public: mPointerControllers.add(deviceId, controller); } -private: - virtual bool getDisplayInfo(int32_t displayId, bool external /*currently ignored*/, - int32_t* width, int32_t* height, int32_t* orientation) { - ssize_t index = mDisplayInfos.indexOfKey(displayId); - if (index >= 0) { - const DisplayInfo& info = mDisplayInfos.valueAt(index); - if (width) { - *width = info.width; - } - if (height) { - *height = info.height; - } - if (orientation) { - *orientation = info.orientation; - } - return true; - } - return false; + const InputReaderConfiguration* getReaderConfiguration() const { + return &mConfig; } +private: virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } @@ -203,6 +173,7 @@ private: class FakeInputListener : public InputListenerInterface { private: List<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgsQueue; + List<NotifyDeviceResetArgs> mNotifyDeviceResetArgsQueue; List<NotifyKeyArgs> mNotifyKeyArgsQueue; List<NotifyMotionArgs> mNotifyMotionArgsQueue; List<NotifySwitchArgs> mNotifySwitchArgsQueue; @@ -224,6 +195,16 @@ public: mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin()); } + void assertNotifyDeviceResetWasCalled( + NotifyDeviceResetArgs* outEventArgs = NULL) { + ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty()) + << "Expected notifyDeviceReset() to have been called."; + if (outEventArgs) { + *outEventArgs = *mNotifyDeviceResetArgsQueue.begin(); + } + mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin()); + } + void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called."; @@ -266,6 +247,10 @@ private: mNotifyConfigurationChangedArgsQueue.push_back(*args); } + virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) { + mNotifyDeviceResetArgsQueue.push_back(*args); + } + virtual void notifyKey(const NotifyKeyArgs* args) { mNotifyKeyArgsQueue.push_back(*args); } @@ -792,11 +777,12 @@ private: } } - virtual void configure(const InputReaderConfiguration* config, uint32_t changes) { + virtual void configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { mConfigureWasCalled = true; } - virtual void reset() { + virtual void reset(nsecs_t when) { mResetWasCalled = true; } @@ -913,6 +899,7 @@ protected: void addDevice(int32_t deviceId, const String8& name, uint32_t classes, const PropertyMap* configuration) { mFakeEventHub->addDevice(deviceId, name, classes); + if (configuration) { mFakeEventHub->addConfigurationMap(deviceId, configuration); } @@ -1263,7 +1250,15 @@ TEST_F(InputDeviceTest, ImmutableProperties) { TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { // Configuration. InputReaderConfiguration config; - mDevice->configure(&config, 0); + mDevice->configure(ARBITRARY_TIME, &config, 0); + + // Reset. + mDevice->reset(ARBITRARY_TIME); + + NotifyDeviceResetArgs resetArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); // Metadata. ASSERT_TRUE(mDevice->isIgnored()); @@ -1292,9 +1287,6 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { << "Ignored device should never mark any key codes."; ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; - - // Reset. - mDevice->reset(); } TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { @@ -1318,7 +1310,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe mDevice->addMapper(mapper2); InputReaderConfiguration config; - mDevice->configure(&config, 0); + mDevice->configure(ARBITRARY_TIME, &config, 0); String8 propertyValue; ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) @@ -1328,6 +1320,16 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); + // Reset + mDevice->reset(ARBITRARY_TIME); + ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); + ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); + + NotifyDeviceResetArgs resetArgs; + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); + ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); + ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); + // Metadata. ASSERT_FALSE(mDevice->isIgnored()); ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources()); @@ -1379,12 +1381,6 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); - - // Reset. - mDevice->reset(); - - ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); - ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); } @@ -1424,10 +1420,16 @@ protected: } void addMapperAndConfigure(InputMapper* mapper) { - InputReaderConfiguration config; - mDevice->addMapper(mapper); - mDevice->configure(&config, 0); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); + mDevice->reset(ARBITRARY_TIME); + } + + void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, + int32_t orientation) { + mFakePolicy->setDisplayInfo(displayId, width, height, orientation); + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DISPLAY_INFO); } static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type, @@ -1593,71 +1595,6 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { ASSERT_EQ(ARBITRARY_TIME, args.downTime); } -TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Key down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_HOME, AKEYCODE_HOME, 1, POLICY_FLAG_WAKE); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Key up. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_HOME, AKEYCODE_HOME, 0, POLICY_FLAG_WAKE); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Reset. Since no keys still down, should not synthesize any key ups. - mapper->reset(); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); -} - -TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) { - KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, - AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); - addMapperAndConfigure(mapper); - - // Metakey down. - process(mapper, ARBITRARY_TIME, DEVICE_ID, - EV_KEY, KEY_LEFTSHIFT, AKEYCODE_SHIFT_LEFT, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Key down. - process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, - EV_KEY, KEY_A, AKEYCODE_A, 1, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Reset. Since two keys are still down, should synthesize two key ups in reverse order. - mapper->reset(); - - NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_A, args.keyCode); - ASSERT_EQ(KEY_A, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME + 1, args.downTime); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEYCODE_SHIFT_LEFT, args.keyCode); - ASSERT_EQ(KEY_LEFTSHIFT, args.scanCode); - ASSERT_EQ(AMETA_NONE, args.metaState); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); - ASSERT_EQ(uint32_t(0), args.policyFlags); - ASSERT_EQ(ARBITRARY_TIME + 1, args.downTime); - - // And that's it. - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); -} - TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); @@ -1703,7 +1640,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateD AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -1722,7 +1659,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { addConfigurationProperty("keyboard.orientationAware", "1"); addMapperAndConfigure(mapper); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -1734,7 +1671,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT)); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -1746,7 +1683,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN)); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -1758,7 +1695,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT)); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, @@ -1774,7 +1711,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { // in the key up as we did in the key down. NotifyKeyArgs args; - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 1, 0); @@ -1783,7 +1720,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { ASSERT_EQ(KEY_UP, args.scanCode); ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, AKEYCODE_DPAD_UP, 0, 0); @@ -2149,58 +2086,12 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } -TEST_F(CursorInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Button press. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - - // Button release. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 0, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - - // Reset. Should not synthesize button up since button is not pressed. - mapper->reset(); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - -TEST_F(CursorInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) { - CursorInputMapper* mapper = new CursorInputMapper(mDevice); - addConfigurationProperty("cursor.mode", "navigation"); - addMapperAndConfigure(mapper); - - NotifyMotionArgs args; - - // Button press. - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0, 1, 0); - process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0, 0, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - - // Reset. Should synthesize button up. - mapper->reset(); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); -} - TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); @@ -2219,7 +2110,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) addConfigurationProperty("cursor.orientationAware", "1"); addMapperAndConfigure(mapper); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); @@ -2230,7 +2121,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); @@ -2241,7 +2132,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); @@ -2252,7 +2143,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); - mFakePolicy->setDisplayInfo(DISPLAY_ID, + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); @@ -2480,6 +2371,8 @@ protected: static const int32_t RAW_ORIENTATION_MAX; static const int32_t RAW_DISTANCE_MIN; static const int32_t RAW_DISTANCE_MAX; + static const int32_t RAW_TILT_MIN; + static const int32_t RAW_TILT_MAX; static const int32_t RAW_ID_MIN; static const int32_t RAW_ID_MAX; static const int32_t RAW_SLOT_MIN; @@ -2500,8 +2393,9 @@ protected: MINOR = 1 << 5, ID = 1 << 6, DISTANCE = 1 << 7, - SLOT = 1 << 8, - TOOL_TYPE = 1 << 9, + TILT = 1 << 8, + SLOT = 1 << 9, + TOOL_TYPE = 1 << 10, }; void prepareDisplay(int32_t orientation); @@ -2526,6 +2420,8 @@ const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0; const int32_t TouchInputMapperTest::RAW_DISTANCE_MAX = 7; +const int32_t TouchInputMapperTest::RAW_TILT_MIN = 0; +const int32_t TouchInputMapperTest::RAW_TILT_MAX = 150; const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; const int32_t TouchInputMapperTest::RAW_SLOT_MIN = 0; @@ -2543,7 +2439,7 @@ const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { }; void TouchInputMapperTest::prepareDisplay(int32_t orientation) { - mFakePolicy->setDisplayInfo(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); } void TouchInputMapperTest::prepareVirtualKeys() { @@ -2583,6 +2479,7 @@ protected: void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); void processDistance(SingleTouchInputMapper* mapper, int32_t distance); + void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY); void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value); void processSync(SingleTouchInputMapper* mapper); }; @@ -2610,6 +2507,12 @@ void SingleTouchInputMapperTest::prepareAxes(int axes) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE, RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); } + if (axes & TILT) { + mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X, + RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); + mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y, + RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); + } } void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { @@ -2642,6 +2545,12 @@ void SingleTouchInputMapperTest::processDistance( process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_DISTANCE, 0, distance, 0); } +void SingleTouchInputMapperTest::processTilt( + SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) { + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_X, 0, tiltX, 0); + process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_Y, 0, tiltY, 0); +} + void SingleTouchInputMapperTest::processKey( SingleTouchInputMapper* mapper, int32_t code, int32_t value) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, 0, value, 0); @@ -2658,7 +2567,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNot prepareAxes(POSITION); addMapperAndConfigure(mapper); - ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); + ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { @@ -2766,71 +2675,6 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { ASSERT_FALSE(flags[1]); } -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); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Reset. Since key is down, synthesize key up. - mapper->reset(); - - NotifyKeyArgs args; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); - //ASSERT_EQ(ARBITRARY_TIME, args.eventTime); - ASSERT_EQ(DEVICE_ID, args.deviceId); - ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); - ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); - ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); - ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); - ASSERT_EQ(AKEYCODE_HOME, args.keyCode); - ASSERT_EQ(KEY_HOME, args.scanCode); - ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); - ASSERT_EQ(ARBITRARY_TIME, args.downTime); -} - -TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) { - SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); - addConfigurationProperty("touch.deviceType", "touchScreen"); - prepareDisplay(DISPLAY_ORIENTATION_0); - prepareButtons(); - prepareAxes(POSITION); - prepareVirtualKeys(); - addMapperAndConfigure(mapper); - - // Press virtual key. - int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); - int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); - processDown(mapper, x, y); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Release virtual key. - processUp(mapper); - processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); - - // Reset. Since no key is down, nothing happens. - mapper->reset(); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); -} - TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); @@ -3260,7 +3104,7 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); - prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE); + prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. @@ -3268,7 +3112,9 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { int32_t rawY = 200; int32_t rawPressure = 10; int32_t rawToolMajor = 12; - int32_t rawDistance = 0; + int32_t rawDistance = 2; + int32_t rawTiltX = 30; + int32_t rawTiltY = 110; float x = toDisplayX(rawX); float y = toDisplayY(rawY); @@ -3277,16 +3123,25 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { float tool = float(rawToolMajor) * GEOMETRIC_SCALE; float distance = float(rawDistance); + float tiltCenter = (RAW_TILT_MAX + RAW_TILT_MIN) * 0.5f; + float tiltScale = M_PI / 180; + float tiltXAngle = (rawTiltX - tiltCenter) * tiltScale; + float tiltYAngle = (rawTiltY - tiltCenter) * tiltScale; + float orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); + float tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); + processDown(mapper, rawX, rawY); processPressure(mapper, rawPressure); processToolMajor(mapper, rawToolMajor); processDistance(mapper, rawDistance); + processTilt(mapper, rawTiltX, rawTiltY); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - x, y, pressure, size, tool, tool, tool, tool, 0, distance)); + x, y, pressure, size, tool, tool, tool, tool, orientation, distance)); + ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT)); } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { @@ -3482,8 +3337,48 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - // finger + // brush processKey(mapper, BTN_TOOL_PEN, 0); + processKey(mapper, BTN_TOOL_BRUSH, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + + // pencil + processKey(mapper, BTN_TOOL_BRUSH, 0); + processKey(mapper, BTN_TOOL_PENCIL, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + + // airbrush + processKey(mapper, BTN_TOOL_PENCIL, 0); + processKey(mapper, BTN_TOOL_AIRBRUSH, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + + // mouse + processKey(mapper, BTN_TOOL_AIRBRUSH, 0); + processKey(mapper, BTN_TOOL_MOUSE, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + + // lens + processKey(mapper, BTN_TOOL_MOUSE, 0); + processKey(mapper, BTN_TOOL_LENS, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + + // finger + processKey(mapper, BTN_TOOL_LENS, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -3504,7 +3399,15 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); + // mouse trumps eraser + processKey(mapper, BTN_TOOL_MOUSE, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + // back to default tool type + processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_FINGER, 0); @@ -3587,29 +3490,29 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueI toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } -TEST_F(SingleTouchInputMapperTest, Process_WhenAbsDistanceIsPresent_HoversIfItsValueIsGreaterThanZero) { +TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); - prepareAxes(POSITION | DISTANCE); + prepareAxes(POSITION | PRESSURE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; - // initially hovering because distance is 1, pressure defaults to 0 + // initially hovering because pressure is 0 processDown(mapper, 100, 200); - processDistance(mapper, 1); + processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processMove(mapper, 150, 250); @@ -3617,23 +3520,23 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenAbsDistanceIsPresent_HoversIfItsV ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - // down when distance goes to 0, pressure defaults to 1 - processDistance(mapper, 0); + // down when pressure is non-zero + processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - // up when distance goes to 1, hover restored - processDistance(mapper, 1); + // up when pressure becomes 0, hover restored + processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); @@ -3643,12 +3546,12 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenAbsDistanceIsPresent_HoversIfItsV ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processUp(mapper); @@ -3656,7 +3559,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenAbsDistanceIsPresent_HoversIfItsV ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } @@ -4823,8 +4726,48 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); - // finger + // brush processKey(mapper, BTN_TOOL_PEN, 0); + processKey(mapper, BTN_TOOL_BRUSH, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + + // pencil + processKey(mapper, BTN_TOOL_BRUSH, 0); + processKey(mapper, BTN_TOOL_PENCIL, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + + // airbrush + processKey(mapper, BTN_TOOL_PENCIL, 0); + processKey(mapper, BTN_TOOL_AIRBRUSH, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + + // mouse + processKey(mapper, BTN_TOOL_AIRBRUSH, 0); + processKey(mapper, BTN_TOOL_MOUSE, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + + // lens + processKey(mapper, BTN_TOOL_MOUSE, 0); + processKey(mapper, BTN_TOOL_LENS, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + + // finger + processKey(mapper, BTN_TOOL_LENS, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -4845,6 +4788,13 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); + // mouse trumps eraser + processKey(mapper, BTN_TOOL_MOUSE, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + // MT tool type trumps BTN tool types: MT_TOOL_FINGER processToolType(mapper, MT_TOOL_FINGER); // this is the first time we send MT_TOOL_TYPE processSync(mapper); @@ -4861,6 +4811,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { // back to default tool type processToolType(mapper, -1); // use a deliberately undefined tool type, for testing + processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_FINGER, 0); @@ -4942,29 +4893,29 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIs toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } -TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTDistanceIsPresent_HoversIfItsValueIsGreaterThanZero) { +TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); - prepareAxes(POSITION | ID | SLOT | DISTANCE); + prepareAxes(POSITION | ID | SLOT | PRESSURE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; - // initially hovering because distance is 1, pressure defaults to 0 + // initially hovering because pressure is 0 processId(mapper, 1); processPosition(mapper, 100, 200); - processDistance(mapper, 1); + processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processPosition(mapper, 150, 250); @@ -4972,23 +4923,23 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTDistanceIsPresent_HoversIfIts ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); - // down when distance goes to 0, pressure defaults to 1 - processDistance(mapper, 0); + // down when pressure becomes non-zero + processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); - // up when distance goes to 1, hover restored - processDistance(mapper, 1); + // up when pressure becomes 0, hover restored + processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); @@ -4998,12 +4949,12 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTDistanceIsPresent_HoversIfIts ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processId(mapper, -1); @@ -5011,7 +4962,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTDistanceIsPresent_HoversIfIts ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], - toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 1)); + toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 7c84e43..f2a0a71 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -182,8 +182,6 @@ public: /* --- InputReaderPolicyInterface implementation --- */ - virtual bool getDisplayInfo(int32_t displayId, bool external, - int32_t* width, int32_t* height, int32_t* orientation); virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId); @@ -273,7 +271,7 @@ NativeInputManager::NativeInputManager(jobject contextObj, mLocked.displayHeight = -1; mLocked.displayExternalWidth = -1; mLocked.displayExternalHeight = -1; - mLocked.displayOrientation = ROTATION_0; + mLocked.displayOrientation = DISPLAY_ORIENTATION_0; mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE; mLocked.pointerSpeed = 0; @@ -311,31 +309,42 @@ bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const c void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height, int32_t externalWidth, int32_t externalHeight) { + bool changed = false; if (displayId == 0) { - { // acquire lock - AutoMutex _l(mLock); + AutoMutex _l(mLock); - if (mLocked.displayWidth != width || mLocked.displayHeight != height) { - mLocked.displayWidth = width; - mLocked.displayHeight = height; + if (mLocked.displayWidth != width || mLocked.displayHeight != height) { + changed = true; + mLocked.displayWidth = width; + mLocked.displayHeight = height; - sp<PointerController> controller = mLocked.pointerController.promote(); - if (controller != NULL) { - controller->setDisplaySize(width, height); - } + sp<PointerController> controller = mLocked.pointerController.promote(); + if (controller != NULL) { + controller->setDisplaySize(width, height); } + } + if (mLocked.displayExternalWidth != externalWidth + || mLocked.displayExternalHeight != externalHeight) { + changed = true; mLocked.displayExternalWidth = externalWidth; mLocked.displayExternalHeight = externalHeight; - } // release lock + } + } + + if (changed) { + mInputManager->getReader()->requestRefreshConfiguration( + InputReaderConfiguration::CHANGE_DISPLAY_INFO); } } void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation) { + bool changed = false; if (displayId == 0) { AutoMutex _l(mLock); if (mLocked.displayOrientation != orientation) { + changed = true; mLocked.displayOrientation = orientation; sp<PointerController> controller = mLocked.pointerController.promote(); @@ -344,6 +353,11 @@ void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orient } } } + + if (changed) { + mInputManager->getReader()->requestRefreshConfiguration( + InputReaderConfiguration::CHANGE_DISPLAY_INFO); + } } status_t NativeInputManager::registerInputChannel(JNIEnv* env, @@ -358,28 +372,6 @@ status_t NativeInputManager::unregisterInputChannel(JNIEnv* env, return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel); } -bool NativeInputManager::getDisplayInfo(int32_t displayId, bool external, - int32_t* width, int32_t* height, int32_t* orientation) { - bool result = false; - if (displayId == 0) { - AutoMutex _l(mLock); - - if (mLocked.displayWidth > 0 && mLocked.displayHeight > 0) { - if (width) { - *width = external ? mLocked.displayExternalWidth : mLocked.displayWidth; - } - if (height) { - *height = external ? mLocked.displayExternalHeight : mLocked.displayHeight; - } - if (orientation) { - *orientation = mLocked.displayOrientation; - } - result = true; - } - } - return result; -} - void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) { JNIEnv* env = jniEnv(); @@ -438,6 +430,12 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed * POINTER_SPEED_EXPONENT); outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled; + + outConfig->setDisplayInfo(0, false /*external*/, + mLocked.displayWidth, mLocked.displayHeight, mLocked.displayOrientation); + outConfig->setDisplayInfo(0, true /*external*/, + mLocked.displayExternalWidth, mLocked.displayExternalHeight, + mLocked.displayOrientation); } // release lock } |