blob: 160f9eb906b61dfb9a5edff95a0f5c102f31f0c8 [file] [log] [blame]
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Michael Wright227c5542020-07-02 18:30:52 +010017// clang-format off
Prabir Pradhan9244aea2020-02-05 20:31:40 -080018#include "../Macros.h"
Michael Wright227c5542020-07-02 18:30:52 +010019// clang-format on
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070020
21#include "TouchInputMapper.h"
22
Dominik Laskowski75788452021-02-09 18:51:25 -080023#include <ftl/enum.h>
Prabir Pradhan8d9ba912022-11-11 22:26:33 +000024#include <input/PrintTools.h>
Dominik Laskowski75788452021-02-09 18:51:25 -080025
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070026#include "CursorButtonAccumulator.h"
27#include "CursorScrollAccumulator.h"
28#include "TouchButtonAccumulator.h"
29#include "TouchCursorInputMapperCommon.h"
Michael Wrighta9cf4192022-12-01 23:46:39 +000030#include "ui/Rotation.h"
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070031
32namespace android {
33
34// --- Constants ---
35
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070036// Artificial latency on synthetic events created from stylus data without corresponding touch
37// data.
38static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
39
HQ Liue6983c72022-04-19 22:14:56 +000040// Minimum width between two pointers to determine a gesture as freeform gesture in mm
41static const float MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER = 30;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070042// --- Static Definitions ---
43
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +000044static const DisplayViewport kUninitializedViewport;
45
Prabir Pradhan7ddbc952022-11-09 22:03:40 +000046static std::string toString(const Rect& rect) {
47 return base::StringPrintf("Rect{%d, %d, %d, %d}", rect.left, rect.top, rect.right, rect.bottom);
48}
49
50static std::string toString(const ui::Size& size) {
51 return base::StringPrintf("%dx%d", size.width, size.height);
52}
53
54static bool isPointInRect(const Rect& rect, int32_t x, int32_t y) {
55 // Consider all four sides as "inclusive".
56 return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
57}
58
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070059template <typename T>
60inline static void swap(T& a, T& b) {
61 T temp = a;
62 a = b;
63 b = temp;
64}
65
66static float calculateCommonVector(float a, float b) {
67 if (a > 0 && b > 0) {
68 return a < b ? a : b;
69 } else if (a < 0 && b < 0) {
70 return a > b ? a : b;
71 } else {
72 return 0;
73 }
74}
75
76inline static float distance(float x1, float y1, float x2, float y2) {
77 return hypotf(x1 - x2, y1 - y2);
78}
79
80inline static int32_t signExtendNybble(int32_t value) {
81 return value >= 8 ? value - 16 : value;
82}
83
Prabir Pradhan2d613f42022-11-10 20:22:06 +000084static std::tuple<ui::Size /*displayBounds*/, Rect /*physicalFrame*/> getNaturalDisplayInfo(
Michael Wrighta9cf4192022-12-01 23:46:39 +000085 const DisplayViewport& viewport, ui::Rotation naturalOrientation) {
Prabir Pradhan2d613f42022-11-10 20:22:06 +000086 ui::Size rotatedDisplaySize{viewport.deviceWidth, viewport.deviceHeight};
Michael Wrighta9cf4192022-12-01 23:46:39 +000087 if (naturalOrientation == ui::ROTATION_90 || naturalOrientation == ui::ROTATION_270) {
Prabir Pradhan2d613f42022-11-10 20:22:06 +000088 std::swap(rotatedDisplaySize.width, rotatedDisplaySize.height);
89 }
90
Michael Wrighta9cf4192022-12-01 23:46:39 +000091 ui::Transform rotate(ui::Transform::toRotationFlags(naturalOrientation),
92 rotatedDisplaySize.width, rotatedDisplaySize.height);
Prabir Pradhan2d613f42022-11-10 20:22:06 +000093
94 Rect physicalFrame{viewport.physicalLeft, viewport.physicalTop, viewport.physicalRight,
95 viewport.physicalBottom};
96 physicalFrame = rotate.transform(physicalFrame);
97
98 LOG_ALWAYS_FATAL_IF(!physicalFrame.isValid());
99 if (physicalFrame.isEmpty()) {
100 ALOGE("Viewport is not set properly: %s", viewport.toString().c_str());
101 physicalFrame.right =
102 physicalFrame.left + (physicalFrame.width() == 0 ? 1 : physicalFrame.width());
103 physicalFrame.bottom =
104 physicalFrame.top + (physicalFrame.height() == 0 ? 1 : physicalFrame.height());
105 }
106 return {rotatedDisplaySize, physicalFrame};
107}
108
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700109// --- RawPointerData ---
110
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700111void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const {
112 float x = 0, y = 0;
113 uint32_t count = touchingIdBits.count();
114 if (count) {
115 for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty();) {
116 uint32_t id = idBits.clearFirstMarkedBit();
117 const Pointer& pointer = pointerForId(id);
118 x += pointer.x;
119 y += pointer.y;
120 }
121 x /= count;
122 y /= count;
123 }
124 *outX = x;
125 *outY = y;
126}
127
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700128// --- TouchInputMapper ---
129
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800130TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext)
131 : InputMapper(deviceContext),
Prabir Pradhan4f05b5f2022-10-11 21:24:07 +0000132 mTouchButtonAccumulator(deviceContext),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700133 mSource(0),
Michael Wright227c5542020-07-02 18:30:52 +0100134 mDeviceMode(DeviceMode::DISABLED),
Michael Wrighta9cf4192022-12-01 23:46:39 +0000135 mInputDeviceOrientation(ui::ROTATION_0) {}
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700136
137TouchInputMapper::~TouchInputMapper() {}
138
Philip Junker4af3b3d2021-12-14 10:36:55 +0100139uint32_t TouchInputMapper::getSources() const {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700140 return mSource;
141}
142
143void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
144 InputMapper::populateDeviceInfo(info);
145
Prabir Pradhanedb0ba72022-10-04 15:44:11 +0000146 if (mDeviceMode == DeviceMode::DISABLED) {
147 return;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700148 }
Prabir Pradhanedb0ba72022-10-04 15:44:11 +0000149
150 info->addMotionRange(mOrientedRanges.x);
151 info->addMotionRange(mOrientedRanges.y);
152 info->addMotionRange(mOrientedRanges.pressure);
153
154 if (mDeviceMode == DeviceMode::UNSCALED && mSource == AINPUT_SOURCE_TOUCHPAD) {
155 // Populate RELATIVE_X and RELATIVE_Y motion ranges for touchpad capture mode.
156 //
157 // RELATIVE_X and RELATIVE_Y motion ranges should be the largest possible relative
158 // motion, i.e. the hardware dimensions, as the finger could move completely across the
159 // touchpad in one sample cycle.
160 const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
161 const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
162 info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -x.max, x.max, x.flat, x.fuzz,
163 x.resolution);
164 info->addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -y.max, y.max, y.flat, y.fuzz,
165 y.resolution);
166 }
167
168 if (mOrientedRanges.size) {
169 info->addMotionRange(*mOrientedRanges.size);
170 }
171
172 if (mOrientedRanges.touchMajor) {
173 info->addMotionRange(*mOrientedRanges.touchMajor);
174 info->addMotionRange(*mOrientedRanges.touchMinor);
175 }
176
177 if (mOrientedRanges.toolMajor) {
178 info->addMotionRange(*mOrientedRanges.toolMajor);
179 info->addMotionRange(*mOrientedRanges.toolMinor);
180 }
181
182 if (mOrientedRanges.orientation) {
183 info->addMotionRange(*mOrientedRanges.orientation);
184 }
185
186 if (mOrientedRanges.distance) {
187 info->addMotionRange(*mOrientedRanges.distance);
188 }
189
190 if (mOrientedRanges.tilt) {
191 info->addMotionRange(*mOrientedRanges.tilt);
192 }
193
194 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
195 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
196 }
197 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
198 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
199 }
200 if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
201 const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
202 const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
203 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, x.fuzz,
204 x.resolution);
205 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, y.fuzz,
206 y.resolution);
207 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, x.fuzz,
208 x.resolution);
209 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, y.fuzz,
210 y.resolution);
211 }
212 info->setButtonUnderPad(mParameters.hasButtonUnderPad);
Prabir Pradhan167c2702022-09-14 00:37:24 +0000213 info->setSupportsUsi(mParameters.supportsUsi);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700214}
215
216void TouchInputMapper::dump(std::string& dump) {
Chris Yea03dd232020-09-08 19:21:09 -0700217 dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n",
Dominik Laskowski75788452021-02-09 18:51:25 -0800218 ftl::enum_string(mDeviceMode).c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700219 dumpParameters(dump);
220 dumpVirtualKeys(dump);
221 dumpRawPointerAxes(dump);
222 dumpCalibration(dump);
223 dumpAffineTransformation(dump);
Prabir Pradhan1728b212021-10-19 16:00:03 -0700224 dumpDisplay(dump);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700225
226 dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700227 dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
228 dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
229 dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
230 dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
231 dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
232 dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
233 dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
234 dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
235 dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
236 dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
237 dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
238 dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
239 dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
240 dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
241
242 dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
243 dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n",
244 mLastRawState.rawPointerData.pointerCount);
245 for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
246 const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
247 dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
248 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
249 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
250 "toolType=%d, isHovering=%s\n",
251 i, pointer.id, pointer.x, pointer.y, pointer.pressure,
252 pointer.touchMajor, pointer.touchMinor, pointer.toolMajor,
253 pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY,
254 pointer.distance, pointer.toolType, toString(pointer.isHovering));
255 }
256
257 dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n",
258 mLastCookedState.buttonState);
259 dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
260 mLastCookedState.cookedPointerData.pointerCount);
261 for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
262 const PointerProperties& pointerProperties =
263 mLastCookedState.cookedPointerData.pointerProperties[i];
264 const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
Nathaniel R. Lewisadb58ea2019-08-21 04:46:29 +0000265 dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, dx=%0.3f, dy=%0.3f, "
266 "pressure=%0.3f, touchMajor=%0.3f, touchMinor=%0.3f, "
267 "toolMajor=%0.3f, toolMinor=%0.3f, "
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700268 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
269 "toolType=%d, isHovering=%s\n",
270 i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(),
Nathaniel R. Lewisadb58ea2019-08-21 04:46:29 +0000271 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
272 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700273 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
274 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
275 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
276 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
277 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
278 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
279 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
280 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
281 pointerProperties.toolType,
282 toString(mLastCookedState.cookedPointerData.isHovering(i)));
283 }
284
285 dump += INDENT3 "Stylus Fusion:\n";
286 dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n",
287 toString(mExternalStylusConnected));
Prabir Pradhan8d9ba912022-11-11 22:26:33 +0000288 dump += StringPrintf(INDENT4 "Fused External Stylus Pointer ID: %s\n",
289 toString(mFusedStylusPointerId).c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700290 dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
291 mExternalStylusFusionTimeout);
Prabir Pradhan124ea442022-10-28 20:27:44 +0000292 dump += StringPrintf(INDENT4 " External Stylus Buttons Applied: 0x%08x",
293 mExternalStylusButtonsApplied);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700294 dump += INDENT3 "External Stylus State:\n";
295 dumpStylusState(dump, mExternalStylusState);
296
Michael Wright227c5542020-07-02 18:30:52 +0100297 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700298 dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n");
299 dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale);
300 dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale);
301 dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale);
302 dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale);
303 dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth);
304 }
305}
306
Siarhei Vishniakou2935db72022-09-22 13:35:22 -0700307std::list<NotifyArgs> TouchInputMapper::configure(nsecs_t when,
308 const InputReaderConfiguration* config,
309 uint32_t changes) {
310 std::list<NotifyArgs> out = InputMapper::configure(when, config, changes);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700311
312 mConfig = *config;
313
314 if (!changes) { // first time only
315 // Configure basic parameters.
316 configureParameters();
317
318 // Configure common accumulators.
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800319 mCursorScrollAccumulator.configure(getDeviceContext());
Prabir Pradhan4f05b5f2022-10-11 21:24:07 +0000320 mTouchButtonAccumulator.configure();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700321
322 // Configure absolute axis information.
323 configureRawPointerAxes();
324
325 // Prepare input device calibration.
326 parseCalibration();
327 resolveCalibration();
328 }
329
330 if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
331 // Update location calibration to reflect current settings
332 updateAffineTransformation();
333 }
334
335 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
336 // Update pointer speed.
337 mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
338 mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
339 mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
340 }
341
342 bool resetNeeded = false;
343 if (!changes ||
344 (changes &
345 (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
Nathaniel R. Lewisd5665332018-02-22 13:31:42 -0800346 InputReaderConfiguration::CHANGE_POINTER_CAPTURE |
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700347 InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
348 InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
349 InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
Prabir Pradhan1728b212021-10-19 16:00:03 -0700350 // Configure device sources, display dimensions, orientation and
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700351 // scaling factors.
Prabir Pradhan1728b212021-10-19 16:00:03 -0700352 configureInputDevice(when, &resetNeeded);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700353 }
354
355 if (changes && resetNeeded) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -0700356 out += reset(when);
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +0000357
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700358 // Send reset, unless this is the first time the device has been configured,
359 // in which case the reader will call reset itself after all mappers are ready.
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +0000360 out.emplace_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700361 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -0700362 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700363}
364
365void TouchInputMapper::resolveExternalStylusPresence() {
366 std::vector<InputDeviceInfo> devices;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800367 getContext()->getExternalStylusDevices(devices);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700368 mExternalStylusConnected = !devices.empty();
369
370 if (!mExternalStylusConnected) {
371 resetExternalStylus();
372 }
373}
374
375void TouchInputMapper::configureParameters() {
376 // Use the pointer presentation mode for devices that do not support distinct
377 // multitouch. The spot-based presentation relies on being able to accurately
378 // locate two or more fingers on the touch pad.
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800379 mParameters.gestureMode = getDeviceContext().hasInputProperty(INPUT_PROP_SEMI_MT)
Michael Wright227c5542020-07-02 18:30:52 +0100380 ? Parameters::GestureMode::SINGLE_TOUCH
381 : Parameters::GestureMode::MULTI_TOUCH;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700382
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700383 std::string gestureModeString;
384 if (getDeviceContext().getConfiguration().tryGetProperty("touch.gestureMode",
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800385 gestureModeString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700386 if (gestureModeString == "single-touch") {
Michael Wright227c5542020-07-02 18:30:52 +0100387 mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700388 } else if (gestureModeString == "multi-touch") {
Michael Wright227c5542020-07-02 18:30:52 +0100389 mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700390 } else if (gestureModeString != "default") {
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700391 ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700392 }
393 }
394
Ambrus Weisz7bc23bf2022-10-04 13:13:07 +0000395 configureDeviceType();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700396
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800397 mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700398
Michael Wright227c5542020-07-02 18:30:52 +0100399 mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700400 getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware",
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800401 mParameters.orientationAware);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700402
Michael Wrighta9cf4192022-12-01 23:46:39 +0000403 mParameters.orientation = ui::ROTATION_0;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700404 std::string orientationString;
405 if (getDeviceContext().getConfiguration().tryGetProperty("touch.orientation",
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700406 orientationString)) {
407 if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) {
408 ALOGW("The configuration 'touch.orientation' is only supported for touchscreens.");
409 } else if (orientationString == "ORIENTATION_90") {
Michael Wrighta9cf4192022-12-01 23:46:39 +0000410 mParameters.orientation = ui::ROTATION_90;
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700411 } else if (orientationString == "ORIENTATION_180") {
Michael Wrighta9cf4192022-12-01 23:46:39 +0000412 mParameters.orientation = ui::ROTATION_180;
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700413 } else if (orientationString == "ORIENTATION_270") {
Michael Wrighta9cf4192022-12-01 23:46:39 +0000414 mParameters.orientation = ui::ROTATION_270;
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700415 } else if (orientationString != "ORIENTATION_0") {
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700416 ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str());
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700417 }
418 }
419
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700420 mParameters.hasAssociatedDisplay = false;
421 mParameters.associatedDisplayIsExternal = false;
422 if (mParameters.orientationAware ||
Michael Wright227c5542020-07-02 18:30:52 +0100423 mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN ||
Ambrus Weisz7bc23bf2022-10-04 13:13:07 +0000424 mParameters.deviceType == Parameters::DeviceType::POINTER ||
425 (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION &&
426 getDeviceContext().getAssociatedViewport())) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700427 mParameters.hasAssociatedDisplay = true;
Michael Wright227c5542020-07-02 18:30:52 +0100428 if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800429 mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700430 std::string uniqueDisplayId;
431 getDeviceContext().getConfiguration().tryGetProperty("touch.displayId",
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800432 uniqueDisplayId);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700433 mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
434 }
435 }
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800436 if (getDeviceContext().getAssociatedDisplayPort()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700437 mParameters.hasAssociatedDisplay = true;
438 }
439
440 // Initial downs on external touch devices should wake the device.
441 // Normally we don't do this for internal touch screens to prevent them from waking
442 // up in your pocket but you can enable it using the input device configuration.
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800443 mParameters.wake = getDeviceContext().isExternal();
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -0700444 getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake);
Prabir Pradhan167c2702022-09-14 00:37:24 +0000445
446 mParameters.supportsUsi = false;
447 getDeviceContext().getConfiguration().tryGetProperty("touch.supportsUsi",
448 mParameters.supportsUsi);
Yuncheol Heo50c19b12022-11-02 20:33:08 -0700449
450 mParameters.enableForInactiveViewport = false;
451 getDeviceContext().getConfiguration().tryGetProperty("touch.enableForInactiveViewport",
452 mParameters.enableForInactiveViewport);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700453}
454
Ambrus Weisz7bc23bf2022-10-04 13:13:07 +0000455void TouchInputMapper::configureDeviceType() {
456 if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) {
457 // The device is a touch screen.
458 mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
459 } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) {
460 // The device is a pointing device like a track pad.
461 mParameters.deviceType = Parameters::DeviceType::POINTER;
462 } else {
463 // The device is a touch pad of unknown purpose.
464 mParameters.deviceType = Parameters::DeviceType::POINTER;
465 }
466
467 // Type association takes precedence over the device type found in the idc file.
468 std::string deviceTypeString = getDeviceContext().getDeviceTypeAssociation().value_or("");
469 if (deviceTypeString.empty()) {
470 getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType", deviceTypeString);
471 }
472 if (deviceTypeString == "touchScreen") {
473 mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
474 } else if (deviceTypeString == "touchNavigation") {
475 mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION;
476 } else if (deviceTypeString == "pointer") {
477 mParameters.deviceType = Parameters::DeviceType::POINTER;
478 } else if (deviceTypeString != "default" && deviceTypeString != "") {
479 ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str());
480 }
481}
482
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700483void TouchInputMapper::dumpParameters(std::string& dump) {
484 dump += INDENT3 "Parameters:\n";
485
Dominik Laskowski75788452021-02-09 18:51:25 -0800486 dump += INDENT4 "GestureMode: " + ftl::enum_string(mParameters.gestureMode) + "\n";
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700487
Dominik Laskowski75788452021-02-09 18:51:25 -0800488 dump += INDENT4 "DeviceType: " + ftl::enum_string(mParameters.deviceType) + "\n";
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700489
490 dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, "
491 "displayId='%s'\n",
492 toString(mParameters.hasAssociatedDisplay),
493 toString(mParameters.associatedDisplayIsExternal),
494 mParameters.uniqueDisplayId.c_str());
495 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
Dominik Laskowski75788452021-02-09 18:51:25 -0800496 dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n";
Prabir Pradhan167c2702022-09-14 00:37:24 +0000497 dump += StringPrintf(INDENT4 "SupportsUsi: %s\n", toString(mParameters.supportsUsi));
Yuncheol Heo50c19b12022-11-02 20:33:08 -0700498 dump += StringPrintf(INDENT4 "EnableForInactiveViewport: %s\n",
499 toString(mParameters.enableForInactiveViewport));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700500}
501
502void TouchInputMapper::configureRawPointerAxes() {
503 mRawPointerAxes.clear();
504}
505
506void TouchInputMapper::dumpRawPointerAxes(std::string& dump) {
507 dump += INDENT3 "Raw Touch Axes:\n";
508 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
509 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
510 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
511 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor");
512 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor");
513 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor");
514 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor");
515 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation");
516 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance");
517 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX");
518 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY");
519 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId");
520 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
521}
522
523bool TouchInputMapper::hasExternalStylus() const {
524 return mExternalStylusConnected;
525}
526
527/**
528 * Determine which DisplayViewport to use.
Arthur Hung6d5b4b22022-01-21 07:21:10 +0000529 * 1. If a device has associated display, get the matching viewport.
Garfield Tan888a6a42020-01-09 11:39:16 -0800530 * 2. Always use the suggested viewport from WindowManagerService for pointers.
Arthur Hung6d5b4b22022-01-21 07:21:10 +0000531 * 3. Get the matching viewport by either unique id in idc file or by the display type
532 * (internal or external).
Garfield Tan888a6a42020-01-09 11:39:16 -0800533 * 4. Otherwise, use a non-display viewport.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700534 */
535std::optional<DisplayViewport> TouchInputMapper::findViewport() {
Nathaniel R. Lewisd5665332018-02-22 13:31:42 -0800536 if (mParameters.hasAssociatedDisplay && mDeviceMode != DeviceMode::UNSCALED) {
Arthur Hung6d5b4b22022-01-21 07:21:10 +0000537 if (getDeviceContext().getAssociatedViewport()) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800538 return getDeviceContext().getAssociatedViewport();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700539 }
540
Christine Franks2a2293c2022-01-18 11:51:16 -0800541 const std::optional<std::string> associatedDisplayUniqueId =
542 getDeviceContext().getAssociatedDisplayUniqueId();
543 if (associatedDisplayUniqueId) {
544 return getDeviceContext().getAssociatedViewport();
545 }
546
Michael Wright227c5542020-07-02 18:30:52 +0100547 if (mDeviceMode == DeviceMode::POINTER) {
Garfield Tan888a6a42020-01-09 11:39:16 -0800548 std::optional<DisplayViewport> viewport =
549 mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
550 if (viewport) {
551 return viewport;
552 } else {
553 ALOGW("Can't find designated display viewport with ID %" PRId32 " for pointers.",
554 mConfig.defaultPointerDisplayId);
555 }
556 }
557
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700558 // Check if uniqueDisplayId is specified in idc file.
559 if (!mParameters.uniqueDisplayId.empty()) {
560 return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId);
561 }
562
563 ViewportType viewportTypeToUse;
564 if (mParameters.associatedDisplayIsExternal) {
Michael Wrightfe3de7d2020-07-02 19:05:30 +0100565 viewportTypeToUse = ViewportType::EXTERNAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700566 } else {
Michael Wrightfe3de7d2020-07-02 19:05:30 +0100567 viewportTypeToUse = ViewportType::INTERNAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700568 }
569
570 std::optional<DisplayViewport> viewport =
571 mConfig.getDisplayViewportByType(viewportTypeToUse);
Michael Wrightfe3de7d2020-07-02 19:05:30 +0100572 if (!viewport && viewportTypeToUse == ViewportType::EXTERNAL) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700573 ALOGW("Input device %s should be associated with external display, "
574 "fallback to internal one for the external viewport is not found.",
575 getDeviceName().c_str());
Michael Wrightfe3de7d2020-07-02 19:05:30 +0100576 viewport = mConfig.getDisplayViewportByType(ViewportType::INTERNAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700577 }
578
579 return viewport;
580 }
581
582 // No associated display, return a non-display viewport.
583 DisplayViewport newViewport;
584 // Raw width and height in the natural orientation.
585 int32_t rawWidth = mRawPointerAxes.getRawWidth();
586 int32_t rawHeight = mRawPointerAxes.getRawHeight();
587 newViewport.setNonDisplayViewport(rawWidth, rawHeight);
588 return std::make_optional(newViewport);
589}
590
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800591int32_t TouchInputMapper::clampResolution(const char* axisName, int32_t resolution) const {
592 if (resolution < 0) {
593 ALOGE("Invalid %s resolution %" PRId32 " for device %s", axisName, resolution,
594 getDeviceName().c_str());
595 return 0;
596 }
597 return resolution;
598}
599
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800600void TouchInputMapper::initializeSizeRanges() {
601 if (mCalibration.sizeCalibration == Calibration::SizeCalibration::NONE) {
602 mSizeScale = 0.0f;
603 return;
604 }
605
606 // Size of diagonal axis.
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000607 const float diagonalSize = hypotf(mDisplayBounds.width, mDisplayBounds.height);
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800608
609 // Size factors.
610 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {
611 mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
612 } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
613 mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
614 } else {
615 mSizeScale = 0.0f;
616 }
617
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700618 mOrientedRanges.touchMajor = InputDeviceInfo::MotionRange{
619 .axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR,
620 .source = mSource,
621 .min = 0,
622 .max = diagonalSize,
623 .flat = 0,
624 .fuzz = 0,
625 .resolution = 0,
626 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800627
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800628 if (mRawPointerAxes.touchMajor.valid) {
629 mRawPointerAxes.touchMajor.resolution =
630 clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution);
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700631 mOrientedRanges.touchMajor->resolution = mRawPointerAxes.touchMajor.resolution;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800632 }
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800633
634 mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700635 mOrientedRanges.touchMinor->axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800636 if (mRawPointerAxes.touchMinor.valid) {
637 mRawPointerAxes.touchMinor.resolution =
638 clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution);
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700639 mOrientedRanges.touchMinor->resolution = mRawPointerAxes.touchMinor.resolution;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800640 }
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800641
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700642 mOrientedRanges.toolMajor = InputDeviceInfo::MotionRange{
643 .axis = AMOTION_EVENT_AXIS_TOOL_MAJOR,
644 .source = mSource,
645 .min = 0,
646 .max = diagonalSize,
647 .flat = 0,
648 .fuzz = 0,
649 .resolution = 0,
650 };
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800651 if (mRawPointerAxes.toolMajor.valid) {
652 mRawPointerAxes.toolMajor.resolution =
653 clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution);
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700654 mOrientedRanges.toolMajor->resolution = mRawPointerAxes.toolMajor.resolution;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800655 }
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800656
657 mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700658 mOrientedRanges.toolMinor->axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800659 if (mRawPointerAxes.toolMinor.valid) {
660 mRawPointerAxes.toolMinor.resolution =
661 clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution);
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700662 mOrientedRanges.toolMinor->resolution = mRawPointerAxes.toolMinor.resolution;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800663 }
664
665 if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700666 mOrientedRanges.touchMajor->resolution *= mGeometricScale;
667 mOrientedRanges.touchMinor->resolution *= mGeometricScale;
668 mOrientedRanges.toolMajor->resolution *= mGeometricScale;
669 mOrientedRanges.toolMinor->resolution *= mGeometricScale;
Siarhei Vishniakou12c0fcb2021-12-17 13:40:44 -0800670 } else {
671 // Support for other calibrations can be added here.
672 ALOGW("%s calibration is not supported for size ranges at the moment. "
673 "Using raw resolution instead",
674 ftl::enum_string(mCalibration.sizeCalibration).c_str());
675 }
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800676
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700677 mOrientedRanges.size = InputDeviceInfo::MotionRange{
678 .axis = AMOTION_EVENT_AXIS_SIZE,
679 .source = mSource,
680 .min = 0,
681 .max = 1.0,
682 .flat = 0,
683 .fuzz = 0,
684 .resolution = 0,
685 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800686}
687
688void TouchInputMapper::initializeOrientedRanges() {
689 // Configure X and Y factors.
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000690 mXScale = float(mDisplayBounds.width) / mRawPointerAxes.getRawWidth();
691 mYScale = float(mDisplayBounds.height) / mRawPointerAxes.getRawHeight();
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800692 mXPrecision = 1.0f / mXScale;
693 mYPrecision = 1.0f / mYScale;
694
695 mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
696 mOrientedRanges.x.source = mSource;
697 mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
698 mOrientedRanges.y.source = mSource;
699
700 // Scale factor for terms that are not oriented in a particular axis.
701 // If the pixels are square then xScale == yScale otherwise we fake it
702 // by choosing an average.
703 mGeometricScale = avg(mXScale, mYScale);
704
705 initializeSizeRanges();
706
707 // Pressure factors.
708 mPressureScale = 0;
709 float pressureMax = 1.0;
710 if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
711 mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700712 if (mCalibration.pressureScale) {
713 mPressureScale = *mCalibration.pressureScale;
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800714 pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
715 } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) {
716 mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
717 }
718 }
719
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700720 mOrientedRanges.pressure = InputDeviceInfo::MotionRange{
721 .axis = AMOTION_EVENT_AXIS_PRESSURE,
722 .source = mSource,
723 .min = 0,
724 .max = pressureMax,
725 .flat = 0,
726 .fuzz = 0,
727 .resolution = 0,
728 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800729
730 // Tilt
731 mTiltXCenter = 0;
732 mTiltXScale = 0;
733 mTiltYCenter = 0;
734 mTiltYScale = 0;
735 mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
736 if (mHaveTilt) {
737 mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue);
738 mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue);
739 mTiltXScale = M_PI / 180;
740 mTiltYScale = M_PI / 180;
741
742 if (mRawPointerAxes.tiltX.resolution) {
743 mTiltXScale = 1.0 / mRawPointerAxes.tiltX.resolution;
744 }
745 if (mRawPointerAxes.tiltY.resolution) {
746 mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution;
747 }
748
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700749 mOrientedRanges.tilt = InputDeviceInfo::MotionRange{
750 .axis = AMOTION_EVENT_AXIS_TILT,
751 .source = mSource,
752 .min = 0,
753 .max = M_PI_2,
754 .flat = 0,
755 .fuzz = 0,
756 .resolution = 0,
757 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800758 }
759
760 // Orientation
761 mOrientationScale = 0;
762 if (mHaveTilt) {
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700763 mOrientedRanges.orientation = InputDeviceInfo::MotionRange{
764 .axis = AMOTION_EVENT_AXIS_ORIENTATION,
765 .source = mSource,
766 .min = -M_PI,
767 .max = M_PI,
768 .flat = 0,
769 .fuzz = 0,
770 .resolution = 0,
771 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800772
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800773 } else if (mCalibration.orientationCalibration != Calibration::OrientationCalibration::NONE) {
774 if (mCalibration.orientationCalibration ==
775 Calibration::OrientationCalibration::INTERPOLATED) {
776 if (mRawPointerAxes.orientation.valid) {
777 if (mRawPointerAxes.orientation.maxValue > 0) {
778 mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
779 } else if (mRawPointerAxes.orientation.minValue < 0) {
780 mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
781 } else {
782 mOrientationScale = 0;
783 }
784 }
785 }
786
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700787 mOrientedRanges.orientation = InputDeviceInfo::MotionRange{
788 .axis = AMOTION_EVENT_AXIS_ORIENTATION,
789 .source = mSource,
790 .min = -M_PI_2,
791 .max = M_PI_2,
792 .flat = 0,
793 .fuzz = 0,
794 .resolution = 0,
795 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800796 }
797
798 // Distance
799 mDistanceScale = 0;
800 if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
801 if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700802 mDistanceScale = mCalibration.distanceScale.value_or(1.0f);
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800803 }
804
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700805 mOrientedRanges.distance = InputDeviceInfo::MotionRange{
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800806
Siarhei Vishniakou24210882022-07-15 09:42:04 -0700807 .axis = AMOTION_EVENT_AXIS_DISTANCE,
808 .source = mSource,
809 .min = mRawPointerAxes.distance.minValue * mDistanceScale,
810 .max = mRawPointerAxes.distance.maxValue * mDistanceScale,
811 .flat = 0,
812 .fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale,
813 .resolution = 0,
814 };
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800815 }
816
817 // Compute oriented precision, scales and ranges.
818 // Note that the maximum value reported is an inclusive maximum value so it is one
819 // unit less than the total width or height of the display.
820 switch (mInputDeviceOrientation) {
Michael Wrighta9cf4192022-12-01 23:46:39 +0000821 case ui::ROTATION_90:
822 case ui::ROTATION_270:
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800823 mOrientedXPrecision = mYPrecision;
824 mOrientedYPrecision = mXPrecision;
825
826 mOrientedRanges.x.min = 0;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000827 mOrientedRanges.x.max = mDisplayBounds.height - 1;
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800828 mOrientedRanges.x.flat = 0;
829 mOrientedRanges.x.fuzz = 0;
830 mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
831
832 mOrientedRanges.y.min = 0;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000833 mOrientedRanges.y.max = mDisplayBounds.width - 1;
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800834 mOrientedRanges.y.flat = 0;
835 mOrientedRanges.y.fuzz = 0;
836 mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
837 break;
838
839 default:
840 mOrientedXPrecision = mXPrecision;
841 mOrientedYPrecision = mYPrecision;
842
843 mOrientedRanges.x.min = 0;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000844 mOrientedRanges.x.max = mDisplayBounds.width - 1;
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800845 mOrientedRanges.x.flat = 0;
846 mOrientedRanges.x.fuzz = 0;
847 mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
848
849 mOrientedRanges.y.min = 0;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000850 mOrientedRanges.y.max = mDisplayBounds.height - 1;
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800851 mOrientedRanges.y.flat = 0;
852 mOrientedRanges.y.fuzz = 0;
853 mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
854 break;
855 }
856}
857
Prabir Pradhan1728b212021-10-19 16:00:03 -0700858void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +0000859 const DeviceMode oldDeviceMode = mDeviceMode;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700860
861 resolveExternalStylusPresence();
862
863 // Determine device mode.
Michael Wright227c5542020-07-02 18:30:52 +0100864 if (mParameters.deviceType == Parameters::DeviceType::POINTER &&
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000865 mConfig.pointerGesturesEnabled && !mConfig.pointerCaptureRequest.enable) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700866 mSource = AINPUT_SOURCE_MOUSE;
Michael Wright227c5542020-07-02 18:30:52 +0100867 mDeviceMode = DeviceMode::POINTER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700868 if (hasStylus()) {
869 mSource |= AINPUT_SOURCE_STYLUS;
Harry Cutts16a24cc2022-10-26 15:22:19 +0000870 } else {
871 mSource |= AINPUT_SOURCE_TOUCHPAD;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700872 }
Garfield Tanc734e4f2021-01-15 20:01:39 -0800873 } else if (isTouchScreen()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700874 mSource = AINPUT_SOURCE_TOUCHSCREEN;
Michael Wright227c5542020-07-02 18:30:52 +0100875 mDeviceMode = DeviceMode::DIRECT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700876 if (hasStylus()) {
877 mSource |= AINPUT_SOURCE_STYLUS;
878 }
879 if (hasExternalStylus()) {
880 mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
881 }
Michael Wright227c5542020-07-02 18:30:52 +0100882 } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700883 mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
Michael Wright227c5542020-07-02 18:30:52 +0100884 mDeviceMode = DeviceMode::NAVIGATION;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700885 } else {
886 mSource = AINPUT_SOURCE_TOUCHPAD;
Michael Wright227c5542020-07-02 18:30:52 +0100887 mDeviceMode = DeviceMode::UNSCALED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700888 }
889
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +0000890 const std::optional<DisplayViewport> newViewportOpt = findViewport();
891
892 // Ensure the device is valid and can be used.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700893 if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
894 ALOGW("Touch device '%s' did not report support for X or Y axis! "
895 "The device will be inoperable.",
896 getDeviceName().c_str());
Michael Wright227c5542020-07-02 18:30:52 +0100897 mDeviceMode = DeviceMode::DISABLED;
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +0000898 } else if (!newViewportOpt) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700899 ALOGI("Touch device '%s' could not query the properties of its associated "
900 "display. The device will be inoperable until the display size "
901 "becomes available.",
902 getDeviceName().c_str());
Michael Wright227c5542020-07-02 18:30:52 +0100903 mDeviceMode = DeviceMode::DISABLED;
Yuncheol Heo50c19b12022-11-02 20:33:08 -0700904 } else if (!mParameters.enableForInactiveViewport && !newViewportOpt->isActive) {
Siarhei Vishniakou6f778462020-12-09 23:39:07 +0000905 ALOGI("Disabling %s (device %i) because the associated viewport is not active",
906 getDeviceName().c_str(), getDeviceId());
907 mDeviceMode = DeviceMode::DISABLED;
Siarhei Vishniakou6f778462020-12-09 23:39:07 +0000908 }
909
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700910 // Raw width and height in the natural orientation.
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000911 const ui::Size rawSize{mRawPointerAxes.getRawWidth(), mRawPointerAxes.getRawHeight()};
HQ Liue6983c72022-04-19 22:14:56 +0000912 const int32_t rawXResolution = mRawPointerAxes.x.resolution;
913 const int32_t rawYResolution = mRawPointerAxes.y.resolution;
914 // Calculate the mean resolution when both x and y resolution are set, otherwise set it to 0.
915 const float rawMeanResolution =
916 (rawXResolution > 0 && rawYResolution > 0) ? (rawXResolution + rawYResolution) / 2 : 0;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700917
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +0000918 const DisplayViewport& newViewport = newViewportOpt.value_or(kUninitializedViewport);
919 const bool viewportChanged = mViewport != newViewport;
Prabir Pradhan93a0f912021-04-21 13:47:42 -0700920 bool skipViewportUpdate = false;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700921 if (viewportChanged) {
Prabir Pradhanc0bdeef2022-08-05 22:32:11 +0000922 const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation;
923 const bool viewportDisplayIdChanged = mViewport.displayId != newViewport.displayId;
924 mViewport = newViewport;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700925
Michael Wright227c5542020-07-02 18:30:52 +0100926 if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhan2d613f42022-11-10 20:22:06 +0000927 const auto oldDisplayBounds = mDisplayBounds;
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700928
Prabir Pradhan1728b212021-10-19 16:00:03 -0700929 // Apply the inverse of the input device orientation so that the input device is
930 // configured in the same orientation as the viewport. The input device orientation will
931 // be re-applied by mInputDeviceOrientation.
Michael Wrighta9cf4192022-12-01 23:46:39 +0000932 const ui::Rotation naturalDeviceOrientation =
933 mViewport.orientation - mParameters.orientation;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700934
Prabir Pradhan2d613f42022-11-10 20:22:06 +0000935 std::tie(mDisplayBounds, mPhysicalFrameInDisplay) =
936 getNaturalDisplayInfo(mViewport, naturalDeviceOrientation);
Prabir Pradhan5632d622021-09-06 07:57:20 -0700937
Prabir Pradhan8b89c2f2021-07-29 16:30:14 +0000938 // InputReader works in the un-rotated display coordinate space, so we don't need to do
939 // anything if the device is already orientation-aware. If the device is not
940 // orientation-aware, then we need to apply the inverse rotation of the display so that
941 // when the display rotation is applied later as a part of the per-window transform, we
942 // get the expected screen coordinates.
Prabir Pradhan1728b212021-10-19 16:00:03 -0700943 mInputDeviceOrientation = mParameters.orientationAware
Michael Wrighta9cf4192022-12-01 23:46:39 +0000944 ? ui::ROTATION_0
Prabir Pradhan8b89c2f2021-07-29 16:30:14 +0000945 : getInverseRotation(mViewport.orientation);
946 // For orientation-aware devices that work in the un-rotated coordinate space, the
947 // viewport update should be skipped if it is only a change in the orientation.
Prabir Pradhan3e5ec702022-07-29 16:26:24 +0000948 skipViewportUpdate = !viewportDisplayIdChanged && mParameters.orientationAware &&
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000949 mDisplayBounds == oldDisplayBounds && viewportOrientationChanged;
Prabir Pradhanac1c74f2021-08-20 16:09:32 -0700950
951 // Apply the input device orientation for the device.
Michael Wrighta9cf4192022-12-01 23:46:39 +0000952 mInputDeviceOrientation = mInputDeviceOrientation + mParameters.orientation;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700953 } else {
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000954 mDisplayBounds = rawSize;
955 mPhysicalFrameInDisplay = Rect{mDisplayBounds};
Michael Wrighta9cf4192022-12-01 23:46:39 +0000956 mInputDeviceOrientation = ui::ROTATION_0;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700957 }
958 }
959
960 // If moving between pointer modes, need to reset some state.
961 bool deviceModeChanged = mDeviceMode != oldDeviceMode;
962 if (deviceModeChanged) {
963 mOrientedRanges.clear();
964 }
965
Prabir Pradhan59ecc3b2020-11-20 13:11:47 -0800966 // Create pointer controller if needed, and keep it around if Pointer Capture is enabled to
967 // preserve the cursor position.
Michael Wright227c5542020-07-02 18:30:52 +0100968 if (mDeviceMode == DeviceMode::POINTER ||
Prabir Pradhan59ecc3b2020-11-20 13:11:47 -0800969 (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches) ||
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000970 (mParameters.deviceType == Parameters::DeviceType::POINTER &&
971 mConfig.pointerCaptureRequest.enable)) {
Prabir Pradhanc7ef27e2020-02-03 19:19:15 -0800972 if (mPointerController == nullptr) {
973 mPointerController = getContext()->getPointerController(getDeviceId());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700974 }
Prabir Pradhan5cc1a692021-08-06 14:01:18 +0000975 if (mConfig.pointerCaptureRequest.enable) {
Prabir Pradhan59ecc3b2020-11-20 13:11:47 -0800976 mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
977 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700978 } else {
lilinnandef700b2022-06-17 19:32:01 +0800979 if (mPointerController != nullptr && mDeviceMode == DeviceMode::DIRECT &&
980 !mConfig.showTouches) {
981 mPointerController->clearSpots();
982 }
Michael Wright17db18e2020-06-26 20:51:44 +0100983 mPointerController.reset();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700984 }
985
Prabir Pradhan93a0f912021-04-21 13:47:42 -0700986 if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) {
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000987 ALOGI("Device reconfigured: id=%d, name='%s', size %s, orientation %d, mode %d, "
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700988 "display id %d",
Prabir Pradhan7ddbc952022-11-09 22:03:40 +0000989 getDeviceId(), getDeviceName().c_str(), toString(mDisplayBounds).c_str(),
Prabir Pradhan1728b212021-10-19 16:00:03 -0700990 mInputDeviceOrientation, mDeviceMode, mViewport.displayId);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700991
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700992 configureVirtualKeys();
993
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -0800994 initializeOrientedRanges();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700995
996 // Location
997 updateAffineTransformation();
998
Michael Wright227c5542020-07-02 18:30:52 +0100999 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001000 // Compute pointer gesture detection parameters.
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00001001 float rawDiagonal = hypotf(rawSize.width, rawSize.height);
1002 float displayDiagonal = hypotf(mDisplayBounds.width, mDisplayBounds.height);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001003
1004 // Scale movements such that one whole swipe of the touch pad covers a
1005 // given area relative to the diagonal size of the display when no acceleration
1006 // is applied.
1007 // Assume that the touch pad has a square aspect ratio such that movements in
1008 // X and Y of the same number of raw units cover the same physical distance.
1009 mPointerXMovementScale =
1010 mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal;
1011 mPointerYMovementScale = mPointerXMovementScale;
1012
1013 // Scale zooms to cover a smaller range of the display than movements do.
1014 // This value determines the area around the pointer that is affected by freeform
1015 // pointer gestures.
1016 mPointerXZoomScale =
1017 mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal;
1018 mPointerYZoomScale = mPointerXZoomScale;
1019
HQ Liue6983c72022-04-19 22:14:56 +00001020 // Calculate the min freeform gesture width. It will be 0 when the resolution of any
1021 // axis is non positive value.
1022 const float minFreeformGestureWidth =
1023 rawMeanResolution * MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER;
1024
1025 mPointerGestureMaxSwipeWidth =
1026 std::max(mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal,
1027 minFreeformGestureWidth);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001028 }
1029
1030 // Inform the dispatcher about the changes.
1031 *outResetNeeded = true;
1032 bumpGeneration();
1033 }
1034}
1035
Prabir Pradhan1728b212021-10-19 16:00:03 -07001036void TouchInputMapper::dumpDisplay(std::string& dump) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001037 dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00001038 dump += StringPrintf(INDENT3 "DisplayBounds: %s\n", toString(mDisplayBounds).c_str());
1039 dump += StringPrintf(INDENT3 "PhysicalFrame: %s\n", toString(mPhysicalFrameInDisplay).c_str());
Prabir Pradhan1728b212021-10-19 16:00:03 -07001040 dump += StringPrintf(INDENT3 "InputDeviceOrientation: %d\n", mInputDeviceOrientation);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001041}
1042
1043void TouchInputMapper::configureVirtualKeys() {
1044 std::vector<VirtualKeyDefinition> virtualKeyDefinitions;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001045 getDeviceContext().getVirtualKeyDefinitions(virtualKeyDefinitions);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001046
1047 mVirtualKeys.clear();
1048
1049 if (virtualKeyDefinitions.size() == 0) {
1050 return;
1051 }
1052
1053 int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
1054 int32_t touchScreenTop = mRawPointerAxes.y.minValue;
1055 int32_t touchScreenWidth = mRawPointerAxes.getRawWidth();
1056 int32_t touchScreenHeight = mRawPointerAxes.getRawHeight();
1057
1058 for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) {
1059 VirtualKey virtualKey;
1060
1061 virtualKey.scanCode = virtualKeyDefinition.scanCode;
1062 int32_t keyCode;
1063 int32_t dummyKeyMetaState;
1064 uint32_t flags;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001065 if (getDeviceContext().mapKey(virtualKey.scanCode, 0, 0, &keyCode, &dummyKeyMetaState,
1066 &flags)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001067 ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
1068 continue; // drop the key
1069 }
1070
1071 virtualKey.keyCode = keyCode;
1072 virtualKey.flags = flags;
1073
1074 // convert the key definition's display coordinates into touch coordinates for a hit box
1075 int32_t halfWidth = virtualKeyDefinition.width / 2;
1076 int32_t halfHeight = virtualKeyDefinition.height / 2;
1077
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00001078 virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth /
1079 mDisplayBounds.width +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001080 touchScreenLeft;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00001081 virtualKey.hitRight = (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth /
1082 mDisplayBounds.width +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001083 touchScreenLeft;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00001084 virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight /
1085 mDisplayBounds.height +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001086 touchScreenTop;
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00001087 virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight /
1088 mDisplayBounds.height +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001089 touchScreenTop;
1090 mVirtualKeys.push_back(virtualKey);
1091 }
1092}
1093
1094void TouchInputMapper::dumpVirtualKeys(std::string& dump) {
1095 if (!mVirtualKeys.empty()) {
1096 dump += INDENT3 "Virtual Keys:\n";
1097
1098 for (size_t i = 0; i < mVirtualKeys.size(); i++) {
1099 const VirtualKey& virtualKey = mVirtualKeys[i];
1100 dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
1101 "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
1102 i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft,
1103 virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
1104 }
1105 }
1106}
1107
1108void TouchInputMapper::parseCalibration() {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001109 const PropertyMap& in = getDeviceContext().getConfiguration();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001110 Calibration& out = mCalibration;
1111
1112 // Size
Michael Wright227c5542020-07-02 18:30:52 +01001113 out.sizeCalibration = Calibration::SizeCalibration::DEFAULT;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001114 std::string sizeCalibrationString;
1115 if (in.tryGetProperty("touch.size.calibration", sizeCalibrationString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001116 if (sizeCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001117 out.sizeCalibration = Calibration::SizeCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001118 } else if (sizeCalibrationString == "geometric") {
Michael Wright227c5542020-07-02 18:30:52 +01001119 out.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001120 } else if (sizeCalibrationString == "diameter") {
Michael Wright227c5542020-07-02 18:30:52 +01001121 out.sizeCalibration = Calibration::SizeCalibration::DIAMETER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001122 } else if (sizeCalibrationString == "box") {
Michael Wright227c5542020-07-02 18:30:52 +01001123 out.sizeCalibration = Calibration::SizeCalibration::BOX;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001124 } else if (sizeCalibrationString == "area") {
Michael Wright227c5542020-07-02 18:30:52 +01001125 out.sizeCalibration = Calibration::SizeCalibration::AREA;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001126 } else if (sizeCalibrationString != "default") {
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001127 ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001128 }
1129 }
1130
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001131 float sizeScale;
1132
1133 if (in.tryGetProperty("touch.size.scale", sizeScale)) {
1134 out.sizeScale = sizeScale;
1135 }
1136 float sizeBias;
1137 if (in.tryGetProperty("touch.size.bias", sizeBias)) {
1138 out.sizeBias = sizeBias;
1139 }
1140 bool sizeIsSummed;
1141 if (in.tryGetProperty("touch.size.isSummed", sizeIsSummed)) {
1142 out.sizeIsSummed = sizeIsSummed;
1143 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001144
1145 // Pressure
Michael Wright227c5542020-07-02 18:30:52 +01001146 out.pressureCalibration = Calibration::PressureCalibration::DEFAULT;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001147 std::string pressureCalibrationString;
1148 if (in.tryGetProperty("touch.pressure.calibration", pressureCalibrationString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001149 if (pressureCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001150 out.pressureCalibration = Calibration::PressureCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001151 } else if (pressureCalibrationString == "physical") {
Michael Wright227c5542020-07-02 18:30:52 +01001152 out.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001153 } else if (pressureCalibrationString == "amplitude") {
Michael Wright227c5542020-07-02 18:30:52 +01001154 out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001155 } else if (pressureCalibrationString != "default") {
1156 ALOGW("Invalid value for touch.pressure.calibration: '%s'",
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001157 pressureCalibrationString.c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001158 }
1159 }
1160
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001161 float pressureScale;
1162 if (in.tryGetProperty("touch.pressure.scale", pressureScale)) {
1163 out.pressureScale = pressureScale;
1164 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001165
1166 // Orientation
Michael Wright227c5542020-07-02 18:30:52 +01001167 out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001168 std::string orientationCalibrationString;
1169 if (in.tryGetProperty("touch.orientation.calibration", orientationCalibrationString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001170 if (orientationCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001171 out.orientationCalibration = Calibration::OrientationCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001172 } else if (orientationCalibrationString == "interpolated") {
Michael Wright227c5542020-07-02 18:30:52 +01001173 out.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001174 } else if (orientationCalibrationString == "vector") {
Michael Wright227c5542020-07-02 18:30:52 +01001175 out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001176 } else if (orientationCalibrationString != "default") {
1177 ALOGW("Invalid value for touch.orientation.calibration: '%s'",
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001178 orientationCalibrationString.c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001179 }
1180 }
1181
1182 // Distance
Michael Wright227c5542020-07-02 18:30:52 +01001183 out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001184 std::string distanceCalibrationString;
1185 if (in.tryGetProperty("touch.distance.calibration", distanceCalibrationString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001186 if (distanceCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001187 out.distanceCalibration = Calibration::DistanceCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001188 } else if (distanceCalibrationString == "scaled") {
Michael Wright227c5542020-07-02 18:30:52 +01001189 out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001190 } else if (distanceCalibrationString != "default") {
1191 ALOGW("Invalid value for touch.distance.calibration: '%s'",
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001192 distanceCalibrationString.c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001193 }
1194 }
1195
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001196 float distanceScale;
1197 if (in.tryGetProperty("touch.distance.scale", distanceScale)) {
1198 out.distanceScale = distanceScale;
1199 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001200
Michael Wright227c5542020-07-02 18:30:52 +01001201 out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT;
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001202 std::string coverageCalibrationString;
1203 if (in.tryGetProperty("touch.coverage.calibration", coverageCalibrationString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001204 if (coverageCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001205 out.coverageCalibration = Calibration::CoverageCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001206 } else if (coverageCalibrationString == "box") {
Michael Wright227c5542020-07-02 18:30:52 +01001207 out.coverageCalibration = Calibration::CoverageCalibration::BOX;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001208 } else if (coverageCalibrationString != "default") {
1209 ALOGW("Invalid value for touch.coverage.calibration: '%s'",
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -07001210 coverageCalibrationString.c_str());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001211 }
1212 }
1213}
1214
1215void TouchInputMapper::resolveCalibration() {
1216 // Size
1217 if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001218 if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DEFAULT) {
1219 mCalibration.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001220 }
1221 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001222 mCalibration.sizeCalibration = Calibration::SizeCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001223 }
1224
1225 // Pressure
1226 if (mRawPointerAxes.pressure.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001227 if (mCalibration.pressureCalibration == Calibration::PressureCalibration::DEFAULT) {
1228 mCalibration.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001229 }
1230 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001231 mCalibration.pressureCalibration = Calibration::PressureCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001232 }
1233
1234 // Orientation
1235 if (mRawPointerAxes.orientation.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001236 if (mCalibration.orientationCalibration == Calibration::OrientationCalibration::DEFAULT) {
1237 mCalibration.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001238 }
1239 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001240 mCalibration.orientationCalibration = Calibration::OrientationCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001241 }
1242
1243 // Distance
1244 if (mRawPointerAxes.distance.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001245 if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::DEFAULT) {
1246 mCalibration.distanceCalibration = Calibration::DistanceCalibration::SCALED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001247 }
1248 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001249 mCalibration.distanceCalibration = Calibration::DistanceCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001250 }
1251
1252 // Coverage
Michael Wright227c5542020-07-02 18:30:52 +01001253 if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::DEFAULT) {
1254 mCalibration.coverageCalibration = Calibration::CoverageCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001255 }
1256}
1257
1258void TouchInputMapper::dumpCalibration(std::string& dump) {
1259 dump += INDENT3 "Calibration:\n";
1260
Siarhei Vishniakou4e837cc2021-12-20 23:24:33 -08001261 dump += INDENT4 "touch.size.calibration: ";
1262 dump += ftl::enum_string(mCalibration.sizeCalibration) + "\n";
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001263
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001264 if (mCalibration.sizeScale) {
1265 dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", *mCalibration.sizeScale);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001266 }
1267
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001268 if (mCalibration.sizeBias) {
1269 dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", *mCalibration.sizeBias);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001270 }
1271
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001272 if (mCalibration.sizeIsSummed) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001273 dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n",
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001274 toString(*mCalibration.sizeIsSummed));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001275 }
1276
1277 // Pressure
1278 switch (mCalibration.pressureCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001279 case Calibration::PressureCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001280 dump += INDENT4 "touch.pressure.calibration: none\n";
1281 break;
Michael Wright227c5542020-07-02 18:30:52 +01001282 case Calibration::PressureCalibration::PHYSICAL:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001283 dump += INDENT4 "touch.pressure.calibration: physical\n";
1284 break;
Michael Wright227c5542020-07-02 18:30:52 +01001285 case Calibration::PressureCalibration::AMPLITUDE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001286 dump += INDENT4 "touch.pressure.calibration: amplitude\n";
1287 break;
1288 default:
1289 ALOG_ASSERT(false);
1290 }
1291
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001292 if (mCalibration.pressureScale) {
1293 dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", *mCalibration.pressureScale);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001294 }
1295
1296 // Orientation
1297 switch (mCalibration.orientationCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001298 case Calibration::OrientationCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001299 dump += INDENT4 "touch.orientation.calibration: none\n";
1300 break;
Michael Wright227c5542020-07-02 18:30:52 +01001301 case Calibration::OrientationCalibration::INTERPOLATED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001302 dump += INDENT4 "touch.orientation.calibration: interpolated\n";
1303 break;
Michael Wright227c5542020-07-02 18:30:52 +01001304 case Calibration::OrientationCalibration::VECTOR:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001305 dump += INDENT4 "touch.orientation.calibration: vector\n";
1306 break;
1307 default:
1308 ALOG_ASSERT(false);
1309 }
1310
1311 // Distance
1312 switch (mCalibration.distanceCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001313 case Calibration::DistanceCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001314 dump += INDENT4 "touch.distance.calibration: none\n";
1315 break;
Michael Wright227c5542020-07-02 18:30:52 +01001316 case Calibration::DistanceCalibration::SCALED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001317 dump += INDENT4 "touch.distance.calibration: scaled\n";
1318 break;
1319 default:
1320 ALOG_ASSERT(false);
1321 }
1322
Siarhei Vishniakou24210882022-07-15 09:42:04 -07001323 if (mCalibration.distanceScale) {
1324 dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", *mCalibration.distanceScale);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001325 }
1326
1327 switch (mCalibration.coverageCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001328 case Calibration::CoverageCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001329 dump += INDENT4 "touch.coverage.calibration: none\n";
1330 break;
Michael Wright227c5542020-07-02 18:30:52 +01001331 case Calibration::CoverageCalibration::BOX:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001332 dump += INDENT4 "touch.coverage.calibration: box\n";
1333 break;
1334 default:
1335 ALOG_ASSERT(false);
1336 }
1337}
1338
1339void TouchInputMapper::dumpAffineTransformation(std::string& dump) {
1340 dump += INDENT3 "Affine Transformation:\n";
1341
1342 dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
1343 dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
1344 dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
1345 dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
1346 dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
1347 dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
1348}
1349
1350void TouchInputMapper::updateAffineTransformation() {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001351 mAffineTransform = getPolicy()->getTouchAffineTransformation(getDeviceContext().getDescriptor(),
Prabir Pradhan1728b212021-10-19 16:00:03 -07001352 mInputDeviceOrientation);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001353}
1354
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001355std::list<NotifyArgs> TouchInputMapper::reset(nsecs_t when) {
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00001356 std::list<NotifyArgs> out = cancelTouch(when, when);
1357 updateTouchSpots();
1358
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001359 mCursorButtonAccumulator.reset(getDeviceContext());
1360 mCursorScrollAccumulator.reset(getDeviceContext());
Prabir Pradhan4f05b5f2022-10-11 21:24:07 +00001361 mTouchButtonAccumulator.reset();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001362
1363 mPointerVelocityControl.reset();
1364 mWheelXVelocityControl.reset();
1365 mWheelYVelocityControl.reset();
1366
1367 mRawStatesPending.clear();
1368 mCurrentRawState.clear();
1369 mCurrentCookedState.clear();
1370 mLastRawState.clear();
1371 mLastCookedState.clear();
Michael Wright227c5542020-07-02 18:30:52 +01001372 mPointerUsage = PointerUsage::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001373 mSentHoverEnter = false;
1374 mHavePointerIds = false;
1375 mCurrentMotionAborted = false;
1376 mDownTime = 0;
1377
1378 mCurrentVirtualKey.down = false;
1379
1380 mPointerGesture.reset();
1381 mPointerSimple.reset();
1382 resetExternalStylus();
1383
1384 if (mPointerController != nullptr) {
Michael Wrightca5bede2020-07-02 00:00:29 +01001385 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001386 mPointerController->clearSpots();
1387 }
1388
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00001389 return out += InputMapper::reset(when);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001390}
1391
1392void TouchInputMapper::resetExternalStylus() {
1393 mExternalStylusState.clear();
Prabir Pradhan8d9ba912022-11-11 22:26:33 +00001394 mFusedStylusPointerId.reset();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001395 mExternalStylusFusionTimeout = LLONG_MAX;
1396 mExternalStylusDataPending = false;
Prabir Pradhan124ea442022-10-28 20:27:44 +00001397 mExternalStylusButtonsApplied = 0;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001398}
1399
1400void TouchInputMapper::clearStylusDataPendingFlags() {
1401 mExternalStylusDataPending = false;
1402 mExternalStylusFusionTimeout = LLONG_MAX;
1403}
1404
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001405std::list<NotifyArgs> TouchInputMapper::process(const RawEvent* rawEvent) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001406 mCursorButtonAccumulator.process(rawEvent);
1407 mCursorScrollAccumulator.process(rawEvent);
1408 mTouchButtonAccumulator.process(rawEvent);
1409
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001410 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001411 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001412 out += sync(rawEvent->when, rawEvent->readTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001413 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001414 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001415}
1416
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001417std::list<NotifyArgs> TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) {
1418 std::list<NotifyArgs> out;
Prabir Pradhanafabcde2022-09-27 19:32:43 +00001419 if (mDeviceMode == DeviceMode::DISABLED) {
1420 // Only save the last pending state when the device is disabled.
1421 mRawStatesPending.clear();
1422 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001423 // Push a new state.
1424 mRawStatesPending.emplace_back();
1425
Siarhei Vishniakou57479982021-03-03 01:32:21 +00001426 RawState& next = mRawStatesPending.back();
1427 next.clear();
1428 next.when = when;
1429 next.readTime = readTime;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001430
1431 // Sync button state.
Siarhei Vishniakou57479982021-03-03 01:32:21 +00001432 next.buttonState =
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001433 mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState();
1434
1435 // Sync scroll
Siarhei Vishniakou57479982021-03-03 01:32:21 +00001436 next.rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
1437 next.rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001438 mCursorScrollAccumulator.finishSync();
1439
1440 // Sync touch
Siarhei Vishniakou57479982021-03-03 01:32:21 +00001441 syncTouch(when, &next);
1442
1443 // The last RawState is the actually second to last, since we just added a new state
1444 const RawState& last =
1445 mRawStatesPending.size() == 1 ? mCurrentRawState : mRawStatesPending.rbegin()[1];
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001446
Prabir Pradhan61a243a2022-11-16 23:47:36 +00001447 std::tie(next.when, next.readTime) =
1448 applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(), when,
1449 readTime, last.when);
Prabir Pradhan2f37bcb2022-11-08 20:41:28 +00001450
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001451 // Assign pointer ids.
1452 if (!mHavePointerIds) {
1453 assignPointerIds(last, next);
1454 }
1455
Harry Cutts45483602022-08-24 14:36:48 +00001456 ALOGD_IF(DEBUG_RAW_EVENTS,
1457 "syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
1458 "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x",
1459 last.rawPointerData.pointerCount, next.rawPointerData.pointerCount,
1460 last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value,
1461 last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value,
1462 next.rawPointerData.canceledIdBits.value);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001463
Arthur Hung9ad18942021-06-19 02:04:46 +00001464 if (!next.rawPointerData.touchingIdBits.isEmpty() &&
1465 !next.rawPointerData.hoveringIdBits.isEmpty() &&
1466 last.rawPointerData.hoveringIdBits != next.rawPointerData.hoveringIdBits) {
1467 ALOGI("Multi-touch contains some hovering ids 0x%08x",
1468 next.rawPointerData.hoveringIdBits.value);
1469 }
1470
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001471 out += processRawTouches(false /*timeout*/);
1472 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001473}
1474
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001475std::list<NotifyArgs> TouchInputMapper::processRawTouches(bool timeout) {
1476 std::list<NotifyArgs> out;
Michael Wright227c5542020-07-02 18:30:52 +01001477 if (mDeviceMode == DeviceMode::DISABLED) {
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00001478 // Do not process raw event while the device is disabled.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001479 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001480 }
1481
1482 // Drain any pending touch states. The invariant here is that the mCurrentRawState is always
1483 // valid and must go through the full cook and dispatch cycle. This ensures that anything
1484 // touching the current state will only observe the events that have been dispatched to the
1485 // rest of the pipeline.
1486 const size_t N = mRawStatesPending.size();
1487 size_t count;
1488 for (count = 0; count < N; count++) {
1489 const RawState& next = mRawStatesPending[count];
1490
1491 // A failure to assign the stylus id means that we're waiting on stylus data
1492 // and so should defer the rest of the pipeline.
1493 if (assignExternalStylusId(next, timeout)) {
1494 break;
1495 }
1496
1497 // All ready to go.
1498 clearStylusDataPendingFlags();
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00001499 mCurrentRawState = next;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001500 if (mCurrentRawState.when < mLastRawState.when) {
1501 mCurrentRawState.when = mLastRawState.when;
Siarhei Vishniakou58ba3d12021-02-11 01:31:07 +00001502 mCurrentRawState.readTime = mLastRawState.readTime;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001503 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001504 out += cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001505 }
1506 if (count != 0) {
1507 mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
1508 }
1509
1510 if (mExternalStylusDataPending) {
1511 if (timeout) {
1512 nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
1513 clearStylusDataPendingFlags();
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00001514 mCurrentRawState = mLastRawState;
Harry Cutts45483602022-08-24 14:36:48 +00001515 ALOGD_IF(DEBUG_STYLUS_FUSION,
1516 "Timeout expired, synthesizing event with new stylus data");
Siarhei Vishniakou58ba3d12021-02-11 01:31:07 +00001517 const nsecs_t readTime = when; // consider this synthetic event to be zero latency
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001518 out += cookAndDispatch(when, readTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001519 } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
1520 mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
1521 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
1522 }
1523 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001524 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001525}
1526
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001527std::list<NotifyArgs> TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) {
1528 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001529 // Always start with a clean state.
1530 mCurrentCookedState.clear();
1531
1532 // Apply stylus buttons to current raw state.
1533 applyExternalStylusButtonState(when);
1534
1535 // Handle policy on initial down or hover events.
1536 bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&
1537 mCurrentRawState.rawPointerData.pointerCount != 0;
1538
1539 uint32_t policyFlags = 0;
1540 bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
1541 if (initialDown || buttonsPressed) {
1542 // If this is a touch screen, hide the pointer on an initial down.
Michael Wright227c5542020-07-02 18:30:52 +01001543 if (mDeviceMode == DeviceMode::DIRECT) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001544 getContext()->fadePointer();
1545 }
1546
1547 if (mParameters.wake) {
1548 policyFlags |= POLICY_FLAG_WAKE;
1549 }
1550 }
1551
1552 // Consume raw off-screen touches before cooking pointer data.
1553 // If touches are consumed, subsequent code will not receive any pointer data.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001554 bool consumed;
1555 out += consumeRawTouches(when, readTime, policyFlags, consumed /*byref*/);
1556 if (consumed) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001557 mCurrentRawState.rawPointerData.clear();
1558 }
1559
1560 // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
1561 // with cooked pointer data that has the same ids and indices as the raw data.
1562 // The following code can use either the raw or cooked data, as needed.
1563 cookPointerData();
1564
1565 // Apply stylus pressure to current cooked state.
1566 applyExternalStylusTouchState(when);
1567
1568 // Synthesize key down from raw buttons if needed.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001569 out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
1570 mSource, mViewport.displayId, policyFlags,
1571 mLastCookedState.buttonState, mCurrentCookedState.buttonState);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001572
1573 // Dispatch the touches either directly or by translation through a pointer on screen.
Michael Wright227c5542020-07-02 18:30:52 +01001574 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001575 for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) {
1576 uint32_t id = idBits.clearFirstMarkedBit();
1577 const RawPointerData::Pointer& pointer =
1578 mCurrentRawState.rawPointerData.pointerForId(id);
Prabir Pradhane5626962022-10-27 20:30:53 +00001579 if (isStylusToolType(pointer.toolType)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001580 mCurrentCookedState.stylusIdBits.markBit(id);
1581 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER ||
1582 pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
1583 mCurrentCookedState.fingerIdBits.markBit(id);
1584 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
1585 mCurrentCookedState.mouseIdBits.markBit(id);
1586 }
1587 }
1588 for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty();) {
1589 uint32_t id = idBits.clearFirstMarkedBit();
1590 const RawPointerData::Pointer& pointer =
1591 mCurrentRawState.rawPointerData.pointerForId(id);
Prabir Pradhane5626962022-10-27 20:30:53 +00001592 if (isStylusToolType(pointer.toolType)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001593 mCurrentCookedState.stylusIdBits.markBit(id);
1594 }
1595 }
1596
1597 // Stylus takes precedence over all tools, then mouse, then finger.
1598 PointerUsage pointerUsage = mPointerUsage;
1599 if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
1600 mCurrentCookedState.mouseIdBits.clear();
1601 mCurrentCookedState.fingerIdBits.clear();
Michael Wright227c5542020-07-02 18:30:52 +01001602 pointerUsage = PointerUsage::STYLUS;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001603 } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
1604 mCurrentCookedState.fingerIdBits.clear();
Michael Wright227c5542020-07-02 18:30:52 +01001605 pointerUsage = PointerUsage::MOUSE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001606 } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
1607 isPointerDown(mCurrentRawState.buttonState)) {
Michael Wright227c5542020-07-02 18:30:52 +01001608 pointerUsage = PointerUsage::GESTURES;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001609 }
1610
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001611 out += dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001612 } else {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001613 if (!mCurrentMotionAborted) {
Prabir Pradhan9eb4e692022-04-27 13:19:15 +00001614 updateTouchSpots();
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001615 out += dispatchButtonRelease(when, readTime, policyFlags);
1616 out += dispatchHoverExit(when, readTime, policyFlags);
1617 out += dispatchTouches(when, readTime, policyFlags);
1618 out += dispatchHoverEnterAndMove(when, readTime, policyFlags);
1619 out += dispatchButtonPress(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001620 }
1621
1622 if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
1623 mCurrentMotionAborted = false;
1624 }
1625 }
1626
1627 // Synthesize key up from raw buttons if needed.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001628 out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(),
1629 mSource, mViewport.displayId, policyFlags,
1630 mLastCookedState.buttonState, mCurrentCookedState.buttonState);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001631
1632 // Clear some transient state.
1633 mCurrentRawState.rawVScroll = 0;
1634 mCurrentRawState.rawHScroll = 0;
1635
1636 // Copy current touch to last touch in preparation for the next cycle.
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00001637 mLastRawState = mCurrentRawState;
1638 mLastCookedState = mCurrentCookedState;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001639 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001640}
1641
Garfield Tanc734e4f2021-01-15 20:01:39 -08001642void TouchInputMapper::updateTouchSpots() {
1643 if (!mConfig.showTouches || mPointerController == nullptr) {
1644 return;
1645 }
1646
1647 // Update touch spots when this is a touchscreen even when it's not enabled so that we can
1648 // clear touch spots.
1649 if (mDeviceMode != DeviceMode::DIRECT &&
1650 (mDeviceMode != DeviceMode::DISABLED || !isTouchScreen())) {
1651 return;
1652 }
1653
1654 mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
1655 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
1656
1657 mPointerController->setButtonState(mCurrentRawState.buttonState);
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00001658 mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords.cbegin(),
1659 mCurrentCookedState.cookedPointerData.idToIndex.cbegin(),
Prabir Pradhande69f8a2021-11-18 16:40:34 +00001660 mCurrentCookedState.cookedPointerData.touchingIdBits,
1661 mViewport.displayId);
Garfield Tanc734e4f2021-01-15 20:01:39 -08001662}
1663
1664bool TouchInputMapper::isTouchScreen() {
1665 return mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
1666 mParameters.hasAssociatedDisplay;
1667}
1668
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001669void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
Prabir Pradhan124ea442022-10-28 20:27:44 +00001670 if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus()) {
1671 // If any of the external buttons are already pressed by the touch device, ignore them.
1672 const int32_t pressedButtons = ~mCurrentRawState.buttonState & mExternalStylusState.buttons;
1673 const int32_t releasedButtons =
1674 mExternalStylusButtonsApplied & ~mExternalStylusState.buttons;
1675
1676 mCurrentRawState.buttonState |= pressedButtons;
1677 mCurrentRawState.buttonState &= ~releasedButtons;
1678
1679 mExternalStylusButtonsApplied |= pressedButtons;
1680 mExternalStylusButtonsApplied &= ~releasedButtons;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001681 }
1682}
1683
1684void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
1685 CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
1686 const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001687 if (!mFusedStylusPointerId || !currentPointerData.isTouching(*mFusedStylusPointerId)) {
1688 return;
1689 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001690
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001691 float pressure = lastPointerData.isTouching(*mFusedStylusPointerId)
1692 ? lastPointerData.pointerCoordsForId(*mFusedStylusPointerId)
1693 .getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)
1694 : 0.f;
1695 if (mExternalStylusState.pressure && *mExternalStylusState.pressure > 0.f) {
1696 pressure = *mExternalStylusState.pressure;
1697 }
1698 PointerCoords& coords = currentPointerData.editPointerCoordsWithId(*mFusedStylusPointerId);
1699 coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001700
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001701 if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001702 PointerProperties& properties =
Prabir Pradhan8d9ba912022-11-11 22:26:33 +00001703 currentPointerData.editPointerPropertiesWithId(*mFusedStylusPointerId);
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001704 properties.toolType = mExternalStylusState.toolType;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001705 }
1706}
1707
1708bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
Michael Wright227c5542020-07-02 18:30:52 +01001709 if (mDeviceMode != DeviceMode::DIRECT || !hasExternalStylus()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001710 return false;
1711 }
1712
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001713 // Check if the stylus pointer has gone up.
Prabir Pradhan8d9ba912022-11-11 22:26:33 +00001714 if (mFusedStylusPointerId &&
1715 !state.rawPointerData.touchingIdBits.hasBit(*mFusedStylusPointerId)) {
Harry Cutts45483602022-08-24 14:36:48 +00001716 ALOGD_IF(DEBUG_STYLUS_FUSION, "Stylus pointer is going up");
Prabir Pradhan8d9ba912022-11-11 22:26:33 +00001717 mFusedStylusPointerId.reset();
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001718 return false;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001719 }
1720
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001721 const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&
1722 state.rawPointerData.pointerCount != 0;
1723 if (!initialDown) {
1724 return false;
1725 }
1726
1727 if (!mExternalStylusState.pressure) {
1728 ALOGD_IF(DEBUG_STYLUS_FUSION, "Stylus does not support pressure, no pointer fusion needed");
1729 return false;
1730 }
1731
1732 if (*mExternalStylusState.pressure != 0.0f) {
1733 ALOGD_IF(DEBUG_STYLUS_FUSION, "Have both stylus and touch data, beginning fusion");
1734 mFusedStylusPointerId = state.rawPointerData.touchingIdBits.firstMarkedBit();
1735 return false;
1736 }
1737
1738 if (timeout) {
1739 ALOGD_IF(DEBUG_STYLUS_FUSION, "Timeout expired, assuming touch is not a stylus.");
1740 mFusedStylusPointerId.reset();
1741 mExternalStylusFusionTimeout = LLONG_MAX;
1742 return false;
1743 }
1744
1745 // We are waiting for the external stylus to report a pressure value. Withhold touches from
1746 // being processed until we either get pressure data or timeout.
1747 if (mExternalStylusFusionTimeout == LLONG_MAX) {
1748 mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
1749 }
1750 ALOGD_IF(DEBUG_STYLUS_FUSION,
1751 "No stylus data but stylus is connected, requesting timeout (%" PRId64 "ms)",
1752 mExternalStylusFusionTimeout);
1753 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
1754 return true;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001755}
1756
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001757std::list<NotifyArgs> TouchInputMapper::timeoutExpired(nsecs_t when) {
1758 std::list<NotifyArgs> out;
Michael Wright227c5542020-07-02 18:30:52 +01001759 if (mDeviceMode == DeviceMode::POINTER) {
1760 if (mPointerUsage == PointerUsage::GESTURES) {
Siarhei Vishniakou58ba3d12021-02-11 01:31:07 +00001761 // Since this is a synthetic event, we can consider its latency to be zero
1762 const nsecs_t readTime = when;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001763 out += dispatchPointerGestures(when, readTime, 0 /*policyFlags*/, true /*isTimeout*/);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001764 }
Michael Wright227c5542020-07-02 18:30:52 +01001765 } else if (mDeviceMode == DeviceMode::DIRECT) {
Prabir Pradhan7d04c4b2022-10-28 19:23:26 +00001766 if (mExternalStylusFusionTimeout <= when) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001767 out += processRawTouches(true /*timeout*/);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001768 } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
1769 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
1770 }
1771 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001772 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001773}
1774
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001775std::list<NotifyArgs> TouchInputMapper::updateExternalStylusState(const StylusState& state) {
1776 std::list<NotifyArgs> out;
Prabir Pradhan124ea442022-10-28 20:27:44 +00001777 const bool buttonsChanged = mExternalStylusState.buttons != state.buttons;
Prabir Pradhan3f7545f2022-10-19 16:56:39 +00001778 mExternalStylusState = state;
Prabir Pradhan8d9ba912022-11-11 22:26:33 +00001779 if (mFusedStylusPointerId || mExternalStylusFusionTimeout != LLONG_MAX || buttonsChanged) {
Prabir Pradhan124ea442022-10-28 20:27:44 +00001780 // The following three cases are handled here:
1781 // - We're in the middle of a fused stream of data;
1782 // - We're waiting on external stylus data before dispatching the initial down; or
1783 // - Only the button state, which is not reported through a specific pointer, has changed.
1784 // Go ahead and dispatch now that we have fresh stylus data.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001785 mExternalStylusDataPending = true;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001786 out += processRawTouches(false /*timeout*/);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001787 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001788 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001789}
1790
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001791std::list<NotifyArgs> TouchInputMapper::consumeRawTouches(nsecs_t when, nsecs_t readTime,
1792 uint32_t policyFlags, bool& outConsumed) {
1793 outConsumed = false;
1794 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001795 // Check for release of a virtual key.
1796 if (mCurrentVirtualKey.down) {
1797 if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
1798 // Pointer went up while virtual key was down.
1799 mCurrentVirtualKey.down = false;
1800 if (!mCurrentVirtualKey.ignored) {
Harry Cutts45483602022-08-24 14:36:48 +00001801 ALOGD_IF(DEBUG_VIRTUAL_KEYS,
1802 "VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
1803 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001804 out.push_back(dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP,
1805 AKEY_EVENT_FLAG_FROM_SYSTEM |
1806 AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001807 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001808 outConsumed = true;
1809 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001810 }
1811
1812 if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
1813 uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
1814 const RawPointerData::Pointer& pointer =
1815 mCurrentRawState.rawPointerData.pointerForId(id);
1816 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
1817 if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
1818 // Pointer is still within the space of the virtual key.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001819 outConsumed = true;
1820 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001821 }
1822 }
1823
1824 // Pointer left virtual key area or another pointer also went down.
1825 // Send key cancellation but do not consume the touch yet.
1826 // This is useful when the user swipes through from the virtual key area
1827 // into the main display surface.
1828 mCurrentVirtualKey.down = false;
1829 if (!mCurrentVirtualKey.ignored) {
Harry Cutts45483602022-08-24 14:36:48 +00001830 ALOGD_IF(DEBUG_VIRTUAL_KEYS, "VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
1831 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001832 out.push_back(dispatchVirtualKey(when, readTime, policyFlags, AKEY_EVENT_ACTION_UP,
1833 AKEY_EVENT_FLAG_FROM_SYSTEM |
1834 AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY |
1835 AKEY_EVENT_FLAG_CANCELED));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001836 }
1837 }
1838
1839 if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() &&
1840 !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
1841 // Pointer just went down. Check for virtual key press or off-screen touches.
1842 uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
1843 const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
Prabir Pradhan1728b212021-10-19 16:00:03 -07001844 // Skip checking whether the pointer is inside the physical frame if the device is in
1845 // unscaled mode.
1846 if (!isPointInsidePhysicalFrame(pointer.x, pointer.y) &&
1847 mDeviceMode != DeviceMode::UNSCALED) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001848 // If exactly one pointer went down, check for virtual key hit.
1849 // Otherwise we will drop the entire stroke.
1850 if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
1851 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
1852 if (virtualKey) {
1853 mCurrentVirtualKey.down = true;
1854 mCurrentVirtualKey.downTime = when;
1855 mCurrentVirtualKey.keyCode = virtualKey->keyCode;
1856 mCurrentVirtualKey.scanCode = virtualKey->scanCode;
1857 mCurrentVirtualKey.ignored =
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001858 getContext()->shouldDropVirtualKey(when, virtualKey->keyCode,
1859 virtualKey->scanCode);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001860
1861 if (!mCurrentVirtualKey.ignored) {
Harry Cutts45483602022-08-24 14:36:48 +00001862 ALOGD_IF(DEBUG_VIRTUAL_KEYS,
1863 "VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
1864 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001865 out.push_back(dispatchVirtualKey(when, readTime, policyFlags,
1866 AKEY_EVENT_ACTION_DOWN,
1867 AKEY_EVENT_FLAG_FROM_SYSTEM |
1868 AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001869 }
1870 }
1871 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001872 outConsumed = true;
1873 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001874 }
1875 }
1876
1877 // Disable all virtual key touches that happen within a short time interval of the
1878 // most recent touch within the screen area. The idea is to filter out stray
1879 // virtual key presses when interacting with the touch screen.
1880 //
1881 // Problems we're trying to solve:
1882 //
1883 // 1. While scrolling a list or dragging the window shade, the user swipes down into a
1884 // virtual key area that is implemented by a separate touch panel and accidentally
1885 // triggers a virtual key.
1886 //
1887 // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
1888 // area and accidentally triggers a virtual key. This often happens when virtual keys
1889 // are layed out below the screen near to where the on screen keyboard's space bar
1890 // is displayed.
1891 if (mConfig.virtualKeyQuietTime > 0 &&
1892 !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001893 getContext()->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001894 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001895 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001896}
1897
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001898NotifyKeyArgs TouchInputMapper::dispatchVirtualKey(nsecs_t when, nsecs_t readTime,
1899 uint32_t policyFlags, int32_t keyEventAction,
1900 int32_t keyEventFlags) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001901 int32_t keyCode = mCurrentVirtualKey.keyCode;
1902 int32_t scanCode = mCurrentVirtualKey.scanCode;
1903 nsecs_t downTime = mCurrentVirtualKey.downTime;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001904 int32_t metaState = getContext()->getGlobalMetaState();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001905 policyFlags |= POLICY_FLAG_VIRTUAL;
1906
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001907 return NotifyKeyArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
1908 AINPUT_SOURCE_KEYBOARD, mViewport.displayId, policyFlags, keyEventAction,
1909 keyEventFlags, keyCode, scanCode, metaState, downTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001910}
1911
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001912std::list<NotifyArgs> TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime,
1913 uint32_t policyFlags) {
1914 std::list<NotifyArgs> out;
lilinnan687e58f2022-07-19 16:00:50 +08001915 if (mCurrentMotionAborted) {
1916 // Current motion event was already aborted.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001917 return out;
lilinnan687e58f2022-07-19 16:00:50 +08001918 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001919 BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
1920 if (!currentIdBits.isEmpty()) {
1921 int32_t metaState = getContext()->getGlobalMetaState();
1922 int32_t buttonState = mCurrentCookedState.buttonState;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001923 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00001924 AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
1925 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001926 mCurrentCookedState.cookedPointerData.pointerProperties,
1927 mCurrentCookedState.cookedPointerData.pointerCoords,
1928 mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits,
1929 -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime,
1930 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001931 mCurrentMotionAborted = true;
1932 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001933 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001934}
1935
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00001936// Updates pointer coords and properties for pointers with specified ids that have moved.
1937// Returns true if any of them changed.
1938static bool updateMovedPointers(const PropertiesArray& inProperties, CoordsArray& inCoords,
1939 const IdToIndexArray& inIdToIndex, PropertiesArray& outProperties,
1940 CoordsArray& outCoords, IdToIndexArray& outIdToIndex,
1941 BitSet32 idBits) {
1942 bool changed = false;
1943 while (!idBits.isEmpty()) {
1944 uint32_t id = idBits.clearFirstMarkedBit();
1945 uint32_t inIndex = inIdToIndex[id];
1946 uint32_t outIndex = outIdToIndex[id];
1947
1948 const PointerProperties& curInProperties = inProperties[inIndex];
1949 const PointerCoords& curInCoords = inCoords[inIndex];
1950 PointerProperties& curOutProperties = outProperties[outIndex];
1951 PointerCoords& curOutCoords = outCoords[outIndex];
1952
1953 if (curInProperties != curOutProperties) {
1954 curOutProperties.copyFrom(curInProperties);
1955 changed = true;
1956 }
1957
1958 if (curInCoords != curOutCoords) {
1959 curOutCoords.copyFrom(curInCoords);
1960 changed = true;
1961 }
1962 }
1963 return changed;
1964}
1965
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001966std::list<NotifyArgs> TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime,
1967 uint32_t policyFlags) {
1968 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001969 BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
1970 BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
1971 int32_t metaState = getContext()->getGlobalMetaState();
1972 int32_t buttonState = mCurrentCookedState.buttonState;
1973
1974 if (currentIdBits == lastIdBits) {
1975 if (!currentIdBits.isEmpty()) {
1976 // No pointer id changes so this is a move event.
1977 // The listener takes care of batching moves so we don't have to deal with that here.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07001978 out.push_back(
1979 dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE,
1980 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
1981 mCurrentCookedState.cookedPointerData.pointerProperties,
1982 mCurrentCookedState.cookedPointerData.pointerCoords,
1983 mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits,
1984 -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime,
1985 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001986 }
1987 } else {
1988 // There may be pointers going up and pointers going down and pointers moving
1989 // all at the same time.
1990 BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
1991 BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
1992 BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
1993 BitSet32 dispatchedIdBits(lastIdBits.value);
1994
1995 // Update last coordinates of pointers that have moved so that we observe the new
1996 // pointer positions at the same time as other pointers that have just gone up.
1997 bool moveNeeded =
1998 updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties,
1999 mCurrentCookedState.cookedPointerData.pointerCoords,
2000 mCurrentCookedState.cookedPointerData.idToIndex,
2001 mLastCookedState.cookedPointerData.pointerProperties,
2002 mLastCookedState.cookedPointerData.pointerCoords,
2003 mLastCookedState.cookedPointerData.idToIndex, moveIdBits);
2004 if (buttonState != mLastCookedState.buttonState) {
2005 moveNeeded = true;
2006 }
2007
2008 // Dispatch pointer up events.
2009 while (!upIdBits.isEmpty()) {
2010 uint32_t upId = upIdBits.clearFirstMarkedBit();
arthurhungcc7f9802020-04-30 17:55:40 +08002011 bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId);
arthurhung17d64842021-01-21 16:01:27 +08002012 if (isCanceled) {
2013 ALOGI("Canceling pointer %d for the palm event was detected.", upId);
2014 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002015 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2016 AMOTION_EVENT_ACTION_POINTER_UP, 0,
2017 isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState,
2018 buttonState, 0,
2019 mLastCookedState.cookedPointerData.pointerProperties,
2020 mLastCookedState.cookedPointerData.pointerCoords,
2021 mLastCookedState.cookedPointerData.idToIndex,
2022 dispatchedIdBits, upId, mOrientedXPrecision,
2023 mOrientedYPrecision, mDownTime,
2024 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002025 dispatchedIdBits.clearBit(upId);
arthurhungcc7f9802020-04-30 17:55:40 +08002026 mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002027 }
2028
2029 // Dispatch move events if any of the remaining pointers moved from their old locations.
2030 // Although applications receive new locations as part of individual pointer up
2031 // events, they do not generally handle them except when presented in a move event.
2032 if (moveNeeded && !moveIdBits.isEmpty()) {
2033 ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002034 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2035 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
2036 mCurrentCookedState.cookedPointerData.pointerProperties,
2037 mCurrentCookedState.cookedPointerData.pointerCoords,
2038 mCurrentCookedState.cookedPointerData.idToIndex,
2039 dispatchedIdBits, -1, mOrientedXPrecision,
2040 mOrientedYPrecision, mDownTime,
2041 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002042 }
2043
2044 // Dispatch pointer down events using the new pointer locations.
2045 while (!downIdBits.isEmpty()) {
2046 uint32_t downId = downIdBits.clearFirstMarkedBit();
2047 dispatchedIdBits.markBit(downId);
2048
2049 if (dispatchedIdBits.count() == 1) {
2050 // First pointer is going down. Set down time.
2051 mDownTime = when;
2052 }
2053
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002054 out.push_back(
2055 dispatchMotion(when, readTime, policyFlags, mSource,
2056 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState,
2057 0, mCurrentCookedState.cookedPointerData.pointerProperties,
2058 mCurrentCookedState.cookedPointerData.pointerCoords,
2059 mCurrentCookedState.cookedPointerData.idToIndex,
2060 dispatchedIdBits, downId, mOrientedXPrecision,
2061 mOrientedYPrecision, mDownTime, MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002062 }
2063 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002064 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002065}
2066
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002067std::list<NotifyArgs> TouchInputMapper::dispatchHoverExit(nsecs_t when, nsecs_t readTime,
2068 uint32_t policyFlags) {
2069 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002070 if (mSentHoverEnter &&
2071 (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() ||
2072 !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
2073 int32_t metaState = getContext()->getGlobalMetaState();
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002074 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2075 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
2076 mLastCookedState.buttonState, 0,
2077 mLastCookedState.cookedPointerData.pointerProperties,
2078 mLastCookedState.cookedPointerData.pointerCoords,
2079 mLastCookedState.cookedPointerData.idToIndex,
2080 mLastCookedState.cookedPointerData.hoveringIdBits, -1,
2081 mOrientedXPrecision, mOrientedYPrecision, mDownTime,
2082 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002083 mSentHoverEnter = false;
2084 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002085 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002086}
2087
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002088std::list<NotifyArgs> TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, nsecs_t readTime,
2089 uint32_t policyFlags) {
2090 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002091 if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() &&
2092 !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
2093 int32_t metaState = getContext()->getGlobalMetaState();
2094 if (!mSentHoverEnter) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002095 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2096 AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
2097 mCurrentRawState.buttonState, 0,
2098 mCurrentCookedState.cookedPointerData.pointerProperties,
2099 mCurrentCookedState.cookedPointerData.pointerCoords,
2100 mCurrentCookedState.cookedPointerData.idToIndex,
2101 mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
2102 mOrientedXPrecision, mOrientedYPrecision, mDownTime,
2103 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002104 mSentHoverEnter = true;
2105 }
2106
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002107 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2108 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
2109 mCurrentRawState.buttonState, 0,
2110 mCurrentCookedState.cookedPointerData.pointerProperties,
2111 mCurrentCookedState.cookedPointerData.pointerCoords,
2112 mCurrentCookedState.cookedPointerData.idToIndex,
2113 mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
2114 mOrientedXPrecision, mOrientedYPrecision, mDownTime,
2115 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002116 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002117 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002118}
2119
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002120std::list<NotifyArgs> TouchInputMapper::dispatchButtonRelease(nsecs_t when, nsecs_t readTime,
2121 uint32_t policyFlags) {
2122 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002123 BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
2124 const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
2125 const int32_t metaState = getContext()->getGlobalMetaState();
2126 int32_t buttonState = mLastCookedState.buttonState;
2127 while (!releasedButtons.isEmpty()) {
2128 int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
2129 buttonState &= ~actionButton;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002130 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2131 AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
2132 metaState, buttonState, 0,
Prabir Pradhan211ba622022-10-31 21:09:21 +00002133 mLastCookedState.cookedPointerData.pointerProperties,
2134 mLastCookedState.cookedPointerData.pointerCoords,
2135 mLastCookedState.cookedPointerData.idToIndex, idBits, -1,
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002136 mOrientedXPrecision, mOrientedYPrecision, mDownTime,
2137 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002138 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002139 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002140}
2141
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002142std::list<NotifyArgs> TouchInputMapper::dispatchButtonPress(nsecs_t when, nsecs_t readTime,
2143 uint32_t policyFlags) {
2144 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002145 BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
2146 const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
2147 const int32_t metaState = getContext()->getGlobalMetaState();
2148 int32_t buttonState = mLastCookedState.buttonState;
2149 while (!pressedButtons.isEmpty()) {
2150 int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
2151 buttonState |= actionButton;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002152 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2153 AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, metaState,
2154 buttonState, 0,
2155 mCurrentCookedState.cookedPointerData.pointerProperties,
2156 mCurrentCookedState.cookedPointerData.pointerCoords,
2157 mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
2158 mOrientedXPrecision, mOrientedYPrecision, mDownTime,
2159 MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002160 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002161 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002162}
2163
2164const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
2165 if (!cookedPointerData.touchingIdBits.isEmpty()) {
2166 return cookedPointerData.touchingIdBits;
2167 }
2168 return cookedPointerData.hoveringIdBits;
2169}
2170
2171void TouchInputMapper::cookPointerData() {
2172 uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
2173
2174 mCurrentCookedState.cookedPointerData.clear();
2175 mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
2176 mCurrentCookedState.cookedPointerData.hoveringIdBits =
2177 mCurrentRawState.rawPointerData.hoveringIdBits;
2178 mCurrentCookedState.cookedPointerData.touchingIdBits =
2179 mCurrentRawState.rawPointerData.touchingIdBits;
arthurhungcc7f9802020-04-30 17:55:40 +08002180 mCurrentCookedState.cookedPointerData.canceledIdBits =
2181 mCurrentRawState.rawPointerData.canceledIdBits;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002182
2183 if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
2184 mCurrentCookedState.buttonState = 0;
2185 } else {
2186 mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
2187 }
2188
2189 // Walk through the the active pointers and map device coordinates onto
Prabir Pradhan1728b212021-10-19 16:00:03 -07002190 // display coordinates and adjust for display orientation.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002191 for (uint32_t i = 0; i < currentPointerCount; i++) {
2192 const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
2193
2194 // Size
2195 float touchMajor, touchMinor, toolMajor, toolMinor, size;
2196 switch (mCalibration.sizeCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002197 case Calibration::SizeCalibration::GEOMETRIC:
2198 case Calibration::SizeCalibration::DIAMETER:
2199 case Calibration::SizeCalibration::BOX:
2200 case Calibration::SizeCalibration::AREA:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002201 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
2202 touchMajor = in.touchMajor;
2203 touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
2204 toolMajor = in.toolMajor;
2205 toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
2206 size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor)
2207 : in.touchMajor;
2208 } else if (mRawPointerAxes.touchMajor.valid) {
2209 toolMajor = touchMajor = in.touchMajor;
2210 toolMinor = touchMinor =
2211 mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
2212 size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor)
2213 : in.touchMajor;
2214 } else if (mRawPointerAxes.toolMajor.valid) {
2215 touchMajor = toolMajor = in.toolMajor;
2216 touchMinor = toolMinor =
2217 mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
2218 size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor)
2219 : in.toolMajor;
2220 } else {
2221 ALOG_ASSERT(false,
2222 "No touch or tool axes. "
2223 "Size calibration should have been resolved to NONE.");
2224 touchMajor = 0;
2225 touchMinor = 0;
2226 toolMajor = 0;
2227 toolMinor = 0;
2228 size = 0;
2229 }
2230
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002231 if (mCalibration.sizeIsSummed && *mCalibration.sizeIsSummed) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002232 uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count();
2233 if (touchingCount > 1) {
2234 touchMajor /= touchingCount;
2235 touchMinor /= touchingCount;
2236 toolMajor /= touchingCount;
2237 toolMinor /= touchingCount;
2238 size /= touchingCount;
2239 }
2240 }
2241
Michael Wright227c5542020-07-02 18:30:52 +01002242 if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002243 touchMajor *= mGeometricScale;
2244 touchMinor *= mGeometricScale;
2245 toolMajor *= mGeometricScale;
2246 toolMinor *= mGeometricScale;
Michael Wright227c5542020-07-02 18:30:52 +01002247 } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::AREA) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002248 touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
2249 touchMinor = touchMajor;
2250 toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
2251 toolMinor = toolMajor;
Michael Wright227c5542020-07-02 18:30:52 +01002252 } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DIAMETER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002253 touchMinor = touchMajor;
2254 toolMinor = toolMajor;
2255 }
2256
Siarhei Vishniakou07247342022-07-15 14:27:37 -07002257 mCalibration.applySizeScaleAndBias(touchMajor);
2258 mCalibration.applySizeScaleAndBias(touchMinor);
2259 mCalibration.applySizeScaleAndBias(toolMajor);
2260 mCalibration.applySizeScaleAndBias(toolMinor);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002261 size *= mSizeScale;
2262 break;
Siarhei Vishniakou07247342022-07-15 14:27:37 -07002263 case Calibration::SizeCalibration::DEFAULT:
2264 LOG_ALWAYS_FATAL("Resolution should not be 'DEFAULT' at this point");
2265 break;
2266 case Calibration::SizeCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002267 touchMajor = 0;
2268 touchMinor = 0;
2269 toolMajor = 0;
2270 toolMinor = 0;
2271 size = 0;
2272 break;
2273 }
2274
2275 // Pressure
2276 float pressure;
2277 switch (mCalibration.pressureCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002278 case Calibration::PressureCalibration::PHYSICAL:
2279 case Calibration::PressureCalibration::AMPLITUDE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002280 pressure = in.pressure * mPressureScale;
2281 break;
2282 default:
2283 pressure = in.isHovering ? 0 : 1;
2284 break;
2285 }
2286
2287 // Tilt and Orientation
2288 float tilt;
2289 float orientation;
2290 if (mHaveTilt) {
2291 float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
2292 float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
2293 orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
2294 tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
2295 } else {
2296 tilt = 0;
2297
2298 switch (mCalibration.orientationCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002299 case Calibration::OrientationCalibration::INTERPOLATED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002300 orientation = in.orientation * mOrientationScale;
2301 break;
Michael Wright227c5542020-07-02 18:30:52 +01002302 case Calibration::OrientationCalibration::VECTOR: {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002303 int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
2304 int32_t c2 = signExtendNybble(in.orientation & 0x0f);
2305 if (c1 != 0 || c2 != 0) {
2306 orientation = atan2f(c1, c2) * 0.5f;
2307 float confidence = hypotf(c1, c2);
2308 float scale = 1.0f + confidence / 16.0f;
2309 touchMajor *= scale;
2310 touchMinor /= scale;
2311 toolMajor *= scale;
2312 toolMinor /= scale;
2313 } else {
2314 orientation = 0;
2315 }
2316 break;
2317 }
2318 default:
2319 orientation = 0;
2320 }
2321 }
2322
2323 // Distance
2324 float distance;
2325 switch (mCalibration.distanceCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002326 case Calibration::DistanceCalibration::SCALED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002327 distance = in.distance * mDistanceScale;
2328 break;
2329 default:
2330 distance = 0;
2331 }
2332
2333 // Coverage
2334 int32_t rawLeft, rawTop, rawRight, rawBottom;
2335 switch (mCalibration.coverageCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002336 case Calibration::CoverageCalibration::BOX:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002337 rawLeft = (in.toolMinor & 0xffff0000) >> 16;
2338 rawRight = in.toolMinor & 0x0000ffff;
2339 rawBottom = in.toolMajor & 0x0000ffff;
2340 rawTop = (in.toolMajor & 0xffff0000) >> 16;
2341 break;
2342 default:
2343 rawLeft = rawTop = rawRight = rawBottom = 0;
2344 break;
2345 }
2346
2347 // Adjust X,Y coords for device calibration
2348 // TODO: Adjust coverage coords?
2349 float xTransformed = in.x, yTransformed = in.y;
2350 mAffineTransform.applyTo(xTransformed, yTransformed);
Arthur Hung05de5772019-09-26 18:31:26 +08002351 rotateAndScale(xTransformed, yTransformed);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002352
Prabir Pradhan1728b212021-10-19 16:00:03 -07002353 // Adjust X, Y, and coverage coords for input device orientation.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002354 float left, top, right, bottom;
2355
Prabir Pradhan1728b212021-10-19 16:00:03 -07002356 switch (mInputDeviceOrientation) {
Michael Wrighta9cf4192022-12-01 23:46:39 +00002357 case ui::ROTATION_90:
Prabir Pradhan1728b212021-10-19 16:00:03 -07002358 left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
2359 right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
2360 bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
2361 top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002362 orientation -= M_PI_2;
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002363 if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002364 orientation +=
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002365 (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002366 }
2367 break;
Michael Wrighta9cf4192022-12-01 23:46:39 +00002368 case ui::ROTATION_180:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002369 left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
2370 right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
Prabir Pradhan1728b212021-10-19 16:00:03 -07002371 bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
2372 top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002373 orientation -= M_PI;
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002374 if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002375 orientation +=
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002376 (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002377 }
2378 break;
Michael Wrighta9cf4192022-12-01 23:46:39 +00002379 case ui::ROTATION_270:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002380 left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
2381 right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
Prabir Pradhan1728b212021-10-19 16:00:03 -07002382 bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
2383 top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002384 orientation += M_PI_2;
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002385 if (mOrientedRanges.orientation && orientation > mOrientedRanges.orientation->max) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002386 orientation -=
Siarhei Vishniakou24210882022-07-15 09:42:04 -07002387 (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002388 }
2389 break;
2390 default:
Prabir Pradhan1728b212021-10-19 16:00:03 -07002391 left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale;
2392 right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale;
2393 bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale;
2394 top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002395 break;
2396 }
2397
2398 // Write output coords.
2399 PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
2400 out.clear();
Arthur Hung4197f6b2020-03-16 15:39:59 +08002401 out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed);
2402 out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002403 out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
2404 out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
2405 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
2406 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
2407 out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
2408 out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
2409 out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
Michael Wright227c5542020-07-02 18:30:52 +01002410 if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002411 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
2412 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
2413 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
2414 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
2415 } else {
2416 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
2417 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
2418 }
2419
Chris Ye364fdb52020-08-05 15:07:56 -07002420 // Write output relative fields if applicable.
Nathaniel R. Lewisadb58ea2019-08-21 04:46:29 +00002421 uint32_t id = in.id;
2422 if (mSource == AINPUT_SOURCE_TOUCHPAD &&
2423 mLastCookedState.cookedPointerData.hasPointerCoordsForId(id)) {
2424 const PointerCoords& p = mLastCookedState.cookedPointerData.pointerCoordsForId(id);
2425 float dx = xTransformed - p.getAxisValue(AMOTION_EVENT_AXIS_X);
2426 float dy = yTransformed - p.getAxisValue(AMOTION_EVENT_AXIS_Y);
2427 out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, dx);
2428 out.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, dy);
2429 }
2430
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002431 // Write output properties.
2432 PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i];
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002433 properties.clear();
2434 properties.id = id;
2435 properties.toolType = in.toolType;
2436
Nathaniel R. Lewisadb58ea2019-08-21 04:46:29 +00002437 // Write id index and mark id as valid.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002438 mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
Nathaniel R. Lewisadb58ea2019-08-21 04:46:29 +00002439 mCurrentCookedState.cookedPointerData.validIdBits.markBit(id);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002440 }
2441}
2442
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002443std::list<NotifyArgs> TouchInputMapper::dispatchPointerUsage(nsecs_t when, nsecs_t readTime,
2444 uint32_t policyFlags,
2445 PointerUsage pointerUsage) {
2446 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002447 if (pointerUsage != mPointerUsage) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002448 out += abortPointerUsage(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002449 mPointerUsage = pointerUsage;
2450 }
2451
2452 switch (mPointerUsage) {
Michael Wright227c5542020-07-02 18:30:52 +01002453 case PointerUsage::GESTURES:
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002454 out += dispatchPointerGestures(when, readTime, policyFlags, false /*isTimeout*/);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002455 break;
Michael Wright227c5542020-07-02 18:30:52 +01002456 case PointerUsage::STYLUS:
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002457 out += dispatchPointerStylus(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002458 break;
Michael Wright227c5542020-07-02 18:30:52 +01002459 case PointerUsage::MOUSE:
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002460 out += dispatchPointerMouse(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002461 break;
Michael Wright227c5542020-07-02 18:30:52 +01002462 case PointerUsage::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002463 break;
2464 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002465 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002466}
2467
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002468std::list<NotifyArgs> TouchInputMapper::abortPointerUsage(nsecs_t when, nsecs_t readTime,
2469 uint32_t policyFlags) {
2470 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002471 switch (mPointerUsage) {
Michael Wright227c5542020-07-02 18:30:52 +01002472 case PointerUsage::GESTURES:
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002473 out += abortPointerGestures(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002474 break;
Michael Wright227c5542020-07-02 18:30:52 +01002475 case PointerUsage::STYLUS:
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002476 out += abortPointerStylus(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002477 break;
Michael Wright227c5542020-07-02 18:30:52 +01002478 case PointerUsage::MOUSE:
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002479 out += abortPointerMouse(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002480 break;
Michael Wright227c5542020-07-02 18:30:52 +01002481 case PointerUsage::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002482 break;
2483 }
2484
Michael Wright227c5542020-07-02 18:30:52 +01002485 mPointerUsage = PointerUsage::NONE;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002486 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002487}
2488
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002489std::list<NotifyArgs> TouchInputMapper::dispatchPointerGestures(nsecs_t when, nsecs_t readTime,
2490 uint32_t policyFlags,
2491 bool isTimeout) {
2492 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002493 // Update current gesture coordinates.
2494 bool cancelPreviousGesture, finishPreviousGesture;
2495 bool sendEvents =
2496 preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
2497 if (!sendEvents) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002498 return {};
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002499 }
2500 if (finishPreviousGesture) {
2501 cancelPreviousGesture = false;
2502 }
2503
2504 // Update the pointer presentation and spots.
Michael Wright227c5542020-07-02 18:30:52 +01002505 if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
Michael Wrightca5bede2020-07-02 00:00:29 +01002506 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002507 if (finishPreviousGesture || cancelPreviousGesture) {
2508 mPointerController->clearSpots();
2509 }
2510
Michael Wright227c5542020-07-02 18:30:52 +01002511 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00002512 mPointerController->setSpots(mPointerGesture.currentGestureCoords.cbegin(),
2513 mPointerGesture.currentGestureIdToIndex.cbegin(),
Prabir Pradhande69f8a2021-11-18 16:40:34 +00002514 mPointerGesture.currentGestureIdBits,
2515 mPointerController->getDisplayId());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002516 }
2517 } else {
Michael Wrightca5bede2020-07-02 00:00:29 +01002518 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002519 }
2520
2521 // Show or hide the pointer if needed.
2522 switch (mPointerGesture.currentGestureMode) {
Michael Wright227c5542020-07-02 18:30:52 +01002523 case PointerGesture::Mode::NEUTRAL:
2524 case PointerGesture::Mode::QUIET:
2525 if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH &&
2526 mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002527 // Remind the user of where the pointer is after finishing a gesture with spots.
Michael Wrightca5bede2020-07-02 00:00:29 +01002528 mPointerController->unfade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002529 }
2530 break;
Michael Wright227c5542020-07-02 18:30:52 +01002531 case PointerGesture::Mode::TAP:
2532 case PointerGesture::Mode::TAP_DRAG:
2533 case PointerGesture::Mode::BUTTON_CLICK_OR_DRAG:
2534 case PointerGesture::Mode::HOVER:
2535 case PointerGesture::Mode::PRESS:
2536 case PointerGesture::Mode::SWIPE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002537 // Unfade the pointer when the current gesture manipulates the
2538 // area directly under the pointer.
Michael Wrightca5bede2020-07-02 00:00:29 +01002539 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002540 break;
Michael Wright227c5542020-07-02 18:30:52 +01002541 case PointerGesture::Mode::FREEFORM:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002542 // Fade the pointer when the current gesture manipulates a different
2543 // area and there are spots to guide the user experience.
Michael Wright227c5542020-07-02 18:30:52 +01002544 if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
Michael Wrightca5bede2020-07-02 00:00:29 +01002545 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002546 } else {
Michael Wrightca5bede2020-07-02 00:00:29 +01002547 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002548 }
2549 break;
2550 }
2551
2552 // Send events!
2553 int32_t metaState = getContext()->getGlobalMetaState();
2554 int32_t buttonState = mCurrentCookedState.buttonState;
Harry Cutts2800fb02022-09-15 13:49:23 +00002555 const MotionClassification classification =
2556 mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE
2557 ? MotionClassification::TWO_FINGER_SWIPE
2558 : MotionClassification::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002559
Prabir Pradhan47cf0a02021-03-11 20:30:57 -08002560 uint32_t flags = 0;
2561
2562 if (!PointerGesture::canGestureAffectWindowFocus(mPointerGesture.currentGestureMode)) {
2563 flags |= AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
2564 }
2565
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002566 // Update last coordinates of pointers that have moved so that we observe the new
2567 // pointer positions at the same time as other pointers that have just gone up.
Michael Wright227c5542020-07-02 18:30:52 +01002568 bool down = mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP ||
2569 mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG ||
2570 mPointerGesture.currentGestureMode == PointerGesture::Mode::BUTTON_CLICK_OR_DRAG ||
2571 mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
2572 mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE ||
2573 mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002574 bool moveNeeded = false;
2575 if (down && !cancelPreviousGesture && !finishPreviousGesture &&
2576 !mPointerGesture.lastGestureIdBits.isEmpty() &&
2577 !mPointerGesture.currentGestureIdBits.isEmpty()) {
2578 BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value &
2579 mPointerGesture.lastGestureIdBits.value);
2580 moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties,
2581 mPointerGesture.currentGestureCoords,
2582 mPointerGesture.currentGestureIdToIndex,
2583 mPointerGesture.lastGestureProperties,
2584 mPointerGesture.lastGestureCoords,
2585 mPointerGesture.lastGestureIdToIndex, movedGestureIdBits);
2586 if (buttonState != mLastCookedState.buttonState) {
2587 moveNeeded = true;
2588 }
2589 }
2590
2591 // Send motion events for all pointers that went up or were canceled.
2592 BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
2593 if (!dispatchedGestureIdBits.isEmpty()) {
2594 if (cancelPreviousGesture) {
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00002595 const uint32_t cancelFlags = flags | AMOTION_EVENT_FLAG_CANCELED;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002596 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00002597 AMOTION_EVENT_ACTION_CANCEL, 0, cancelFlags, metaState,
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002598 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2599 mPointerGesture.lastGestureProperties,
2600 mPointerGesture.lastGestureCoords,
2601 mPointerGesture.lastGestureIdToIndex,
2602 dispatchedGestureIdBits, -1, 0, 0,
2603 mPointerGesture.downTime, classification));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002604
2605 dispatchedGestureIdBits.clear();
2606 } else {
2607 BitSet32 upGestureIdBits;
2608 if (finishPreviousGesture) {
2609 upGestureIdBits = dispatchedGestureIdBits;
2610 } else {
2611 upGestureIdBits.value =
2612 dispatchedGestureIdBits.value & ~mPointerGesture.currentGestureIdBits.value;
2613 }
2614 while (!upGestureIdBits.isEmpty()) {
2615 uint32_t id = upGestureIdBits.clearFirstMarkedBit();
2616
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002617 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2618 AMOTION_EVENT_ACTION_POINTER_UP, 0, flags, metaState,
2619 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2620 mPointerGesture.lastGestureProperties,
2621 mPointerGesture.lastGestureCoords,
2622 mPointerGesture.lastGestureIdToIndex,
2623 dispatchedGestureIdBits, id, 0, 0,
2624 mPointerGesture.downTime, classification));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002625
2626 dispatchedGestureIdBits.clearBit(id);
2627 }
2628 }
2629 }
2630
2631 // Send motion events for all pointers that moved.
2632 if (moveNeeded) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002633 out.push_back(
2634 dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0,
2635 flags, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2636 mPointerGesture.currentGestureProperties,
2637 mPointerGesture.currentGestureCoords,
2638 mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1,
2639 0, 0, mPointerGesture.downTime, classification));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002640 }
2641
2642 // Send motion events for all pointers that went down.
2643 if (down) {
2644 BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value &
2645 ~dispatchedGestureIdBits.value);
2646 while (!downGestureIdBits.isEmpty()) {
2647 uint32_t id = downGestureIdBits.clearFirstMarkedBit();
2648 dispatchedGestureIdBits.markBit(id);
2649
2650 if (dispatchedGestureIdBits.count() == 1) {
2651 mPointerGesture.downTime = when;
2652 }
2653
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002654 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2655 AMOTION_EVENT_ACTION_POINTER_DOWN, 0, flags, metaState,
2656 buttonState, 0, mPointerGesture.currentGestureProperties,
2657 mPointerGesture.currentGestureCoords,
2658 mPointerGesture.currentGestureIdToIndex,
2659 dispatchedGestureIdBits, id, 0, 0,
2660 mPointerGesture.downTime, classification));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002661 }
2662 }
2663
2664 // Send motion events for hover.
Michael Wright227c5542020-07-02 18:30:52 +01002665 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) {
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002666 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
2667 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState,
2668 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2669 mPointerGesture.currentGestureProperties,
2670 mPointerGesture.currentGestureCoords,
2671 mPointerGesture.currentGestureIdToIndex,
2672 mPointerGesture.currentGestureIdBits, -1, 0, 0,
2673 mPointerGesture.downTime, MotionClassification::NONE));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002674 } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) {
2675 // Synthesize a hover move event after all pointers go up to indicate that
2676 // the pointer is hovering again even if the user is not currently touching
2677 // the touch pad. This ensures that a view will receive a fresh hover enter
2678 // event after a tap.
Prabir Pradhande69f8a2021-11-18 16:40:34 +00002679 float x, y;
2680 mPointerController->getPosition(&x, &y);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002681
2682 PointerProperties pointerProperties;
2683 pointerProperties.clear();
2684 pointerProperties.id = 0;
2685 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
2686
2687 PointerCoords pointerCoords;
2688 pointerCoords.clear();
2689 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
2690 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
2691
2692 const int32_t displayId = mPointerController->getDisplayId();
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002693 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
2694 mSource, displayId, policyFlags,
2695 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState,
2696 buttonState, MotionClassification::NONE,
2697 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
2698 &pointerCoords, 0, 0, x, y, mPointerGesture.downTime,
2699 /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002700 }
2701
2702 // Update state.
2703 mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
2704 if (!down) {
2705 mPointerGesture.lastGestureIdBits.clear();
2706 } else {
2707 mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
2708 for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty();) {
2709 uint32_t id = idBits.clearFirstMarkedBit();
2710 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
2711 mPointerGesture.lastGestureProperties[index].copyFrom(
2712 mPointerGesture.currentGestureProperties[index]);
2713 mPointerGesture.lastGestureCoords[index].copyFrom(
2714 mPointerGesture.currentGestureCoords[index]);
2715 mPointerGesture.lastGestureIdToIndex[id] = index;
2716 }
2717 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002718 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002719}
2720
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002721std::list<NotifyArgs> TouchInputMapper::abortPointerGestures(nsecs_t when, nsecs_t readTime,
2722 uint32_t policyFlags) {
Harry Cutts2800fb02022-09-15 13:49:23 +00002723 const MotionClassification classification =
2724 mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE
2725 ? MotionClassification::TWO_FINGER_SWIPE
2726 : MotionClassification::NONE;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002727 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002728 // Cancel previously dispatches pointers.
2729 if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
2730 int32_t metaState = getContext()->getGlobalMetaState();
2731 int32_t buttonState = mCurrentRawState.buttonState;
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002732 out.push_back(dispatchMotion(when, readTime, policyFlags, mSource,
Prabir Pradhanf5b4d7a2022-10-03 15:45:50 +00002733 AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
2734 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002735 mPointerGesture.lastGestureProperties,
2736 mPointerGesture.lastGestureCoords,
2737 mPointerGesture.lastGestureIdToIndex,
2738 mPointerGesture.lastGestureIdBits, -1, 0, 0,
2739 mPointerGesture.downTime, classification));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002740 }
2741
2742 // Reset the current pointer gesture.
2743 mPointerGesture.reset();
2744 mPointerVelocityControl.reset();
2745
2746 // Remove any current spots.
2747 if (mPointerController != nullptr) {
Michael Wrightca5bede2020-07-02 00:00:29 +01002748 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002749 mPointerController->clearSpots();
2750 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07002751 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002752}
2753
2754bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture,
2755 bool* outFinishPreviousGesture, bool isTimeout) {
2756 *outCancelPreviousGesture = false;
2757 *outFinishPreviousGesture = false;
2758
2759 // Handle TAP timeout.
2760 if (isTimeout) {
Harry Cutts45483602022-08-24 14:36:48 +00002761 ALOGD_IF(DEBUG_GESTURES, "Gestures: Processing timeout");
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002762
Michael Wright227c5542020-07-02 18:30:52 +01002763 if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002764 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
2765 // The tap/drag timeout has not yet expired.
2766 getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime +
2767 mConfig.pointerGestureTapDragInterval);
2768 } else {
2769 // The tap is finished.
Harry Cutts45483602022-08-24 14:36:48 +00002770 ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP finished");
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002771 *outFinishPreviousGesture = true;
2772
2773 mPointerGesture.activeGestureId = -1;
Michael Wright227c5542020-07-02 18:30:52 +01002774 mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002775 mPointerGesture.currentGestureIdBits.clear();
2776
2777 mPointerVelocityControl.reset();
2778 return true;
2779 }
2780 }
2781
2782 // We did not handle this timeout.
2783 return false;
2784 }
2785
2786 const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
2787 const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
2788
2789 // Update the velocity tracker.
2790 {
Yeabkal Wubshit384ab0f2022-09-09 16:39:18 +00002791 std::vector<float> positionsX;
2792 std::vector<float> positionsY;
Siarhei Vishniakouae0f9902020-09-14 19:23:31 -05002793 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002794 uint32_t id = idBits.clearFirstMarkedBit();
2795 const RawPointerData::Pointer& pointer =
2796 mCurrentRawState.rawPointerData.pointerForId(id);
Yeabkal Wubshit384ab0f2022-09-09 16:39:18 +00002797 positionsX.push_back(pointer.x * mPointerXMovementScale);
2798 positionsY.push_back(pointer.y * mPointerYMovementScale);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002799 }
2800 mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
Yeabkal Wubshit384ab0f2022-09-09 16:39:18 +00002801 {{AMOTION_EVENT_AXIS_X, positionsX},
2802 {AMOTION_EVENT_AXIS_Y, positionsY}});
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002803 }
2804
2805 // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
2806 // to NEUTRAL, then we should not generate tap event.
Michael Wright227c5542020-07-02 18:30:52 +01002807 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER &&
2808 mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP &&
2809 mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP_DRAG) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002810 mPointerGesture.resetTap();
2811 }
2812
2813 // Pick a new active touch id if needed.
2814 // Choose an arbitrary pointer that just went down, if there is one.
2815 // Otherwise choose an arbitrary remaining pointer.
2816 // This guarantees we always have an active touch id when there is at least one pointer.
2817 // We keep the same active touch id for as long as possible.
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002818 if (mPointerGesture.activeTouchId < 0) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002819 if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002820 mPointerGesture.activeTouchId = mCurrentCookedState.fingerIdBits.firstMarkedBit();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002821 mPointerGesture.firstTouchTime = when;
2822 }
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002823 } else if (!mCurrentCookedState.fingerIdBits.hasBit(mPointerGesture.activeTouchId)) {
2824 mPointerGesture.activeTouchId = !mCurrentCookedState.fingerIdBits.isEmpty()
2825 ? mCurrentCookedState.fingerIdBits.firstMarkedBit()
2826 : -1;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002827 }
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002828 const int32_t& activeTouchId = mPointerGesture.activeTouchId;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002829
2830 // Switch states based on button and pointer state.
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002831 if (checkForTouchpadQuietTime(when)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002832 // Case 1: Quiet time. (QUIET)
Harry Cutts45483602022-08-24 14:36:48 +00002833 ALOGD_IF(DEBUG_GESTURES, "Gestures: QUIET for next %0.3fms",
2834 (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) *
2835 0.000001f);
Michael Wright227c5542020-07-02 18:30:52 +01002836 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::QUIET) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002837 *outFinishPreviousGesture = true;
2838 }
2839
2840 mPointerGesture.activeGestureId = -1;
Michael Wright227c5542020-07-02 18:30:52 +01002841 mPointerGesture.currentGestureMode = PointerGesture::Mode::QUIET;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002842 mPointerGesture.currentGestureIdBits.clear();
2843
2844 mPointerVelocityControl.reset();
2845 } else if (isPointerDown(mCurrentRawState.buttonState)) {
2846 // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
2847 // The pointer follows the active touch point.
2848 // Emit DOWN, MOVE, UP events at the pointer location.
2849 //
2850 // Only the active touch matters; other fingers are ignored. This policy helps
2851 // to handle the case where the user places a second finger on the touch pad
2852 // to apply the necessary force to depress an integrated button below the surface.
2853 // We don't want the second finger to be delivered to applications.
2854 //
2855 // For this to work well, we need to make sure to track the pointer that is really
2856 // active. If the user first puts one finger down to click then adds another
2857 // finger to drag then the active pointer should switch to the finger that is
2858 // being dragged.
Harry Cutts45483602022-08-24 14:36:48 +00002859 ALOGD_IF(DEBUG_GESTURES,
2860 "Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, currentFingerCount=%d",
2861 activeTouchId, currentFingerCount);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002862 // Reset state when just starting.
Michael Wright227c5542020-07-02 18:30:52 +01002863 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::BUTTON_CLICK_OR_DRAG) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002864 *outFinishPreviousGesture = true;
2865 mPointerGesture.activeGestureId = 0;
2866 }
2867
2868 // Switch pointers if needed.
2869 // Find the fastest pointer and follow it.
2870 if (activeTouchId >= 0 && currentFingerCount > 1) {
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002871 const auto [bestId, bestSpeed] = getFastestFinger();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002872 if (bestId >= 0 && bestId != activeTouchId) {
Harry Cuttsbea6ce52022-10-14 15:17:30 +00002873 mPointerGesture.activeTouchId = bestId;
Harry Cutts45483602022-08-24 14:36:48 +00002874 ALOGD_IF(DEBUG_GESTURES,
2875 "Gestures: BUTTON_CLICK_OR_DRAG switched pointers, bestId=%d, "
2876 "bestSpeed=%0.3f",
2877 bestId, bestSpeed);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002878 }
2879 }
2880
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002881 if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002882 // When using spots, the click will occur at the position of the anchor
2883 // spot and all other spots will move there.
Harry Cutts714d1ad2022-08-24 16:36:43 +00002884 moveMousePointerFromPointerDelta(when, activeTouchId);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002885 } else {
2886 mPointerVelocityControl.reset();
2887 }
2888
Prabir Pradhande69f8a2021-11-18 16:40:34 +00002889 float x, y;
2890 mPointerController->getPosition(&x, &y);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002891
Michael Wright227c5542020-07-02 18:30:52 +01002892 mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002893 mPointerGesture.currentGestureIdBits.clear();
2894 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
2895 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
2896 mPointerGesture.currentGestureProperties[0].clear();
2897 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
2898 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
2899 mPointerGesture.currentGestureCoords[0].clear();
2900 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
2901 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
2902 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
2903 } else if (currentFingerCount == 0) {
2904 // Case 3. No fingers down and button is not pressed. (NEUTRAL)
Michael Wright227c5542020-07-02 18:30:52 +01002905 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::NEUTRAL) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002906 *outFinishPreviousGesture = true;
2907 }
2908
2909 // Watch for taps coming out of HOVER or TAP_DRAG mode.
2910 // Checking for taps after TAP_DRAG allows us to detect double-taps.
2911 bool tapped = false;
Michael Wright227c5542020-07-02 18:30:52 +01002912 if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::HOVER ||
2913 mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002914 lastFingerCount == 1) {
2915 if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
Prabir Pradhande69f8a2021-11-18 16:40:34 +00002916 float x, y;
2917 mPointerController->getPosition(&x, &y);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002918 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
2919 fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
Harry Cutts45483602022-08-24 14:36:48 +00002920 ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP");
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002921
2922 mPointerGesture.tapUpTime = when;
2923 getContext()->requestTimeoutAtTime(when +
2924 mConfig.pointerGestureTapDragInterval);
2925
2926 mPointerGesture.activeGestureId = 0;
Michael Wright227c5542020-07-02 18:30:52 +01002927 mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002928 mPointerGesture.currentGestureIdBits.clear();
2929 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
2930 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
2931 mPointerGesture.currentGestureProperties[0].clear();
2932 mPointerGesture.currentGestureProperties[0].id =
2933 mPointerGesture.activeGestureId;
2934 mPointerGesture.currentGestureProperties[0].toolType =
2935 AMOTION_EVENT_TOOL_TYPE_FINGER;
2936 mPointerGesture.currentGestureCoords[0].clear();
2937 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
2938 mPointerGesture.tapX);
2939 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
2940 mPointerGesture.tapY);
2941 mPointerGesture.currentGestureCoords[0]
2942 .setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
2943
2944 tapped = true;
2945 } else {
Harry Cutts45483602022-08-24 14:36:48 +00002946 ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP, deltaX=%f, deltaY=%f",
2947 x - mPointerGesture.tapX, y - mPointerGesture.tapY);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002948 }
2949 } else {
Siarhei Vishniakou465e1c02021-12-09 10:47:29 -08002950 if (DEBUG_GESTURES) {
2951 if (mPointerGesture.tapDownTime != LLONG_MIN) {
2952 ALOGD("Gestures: Not a TAP, %0.3fms since down",
2953 (when - mPointerGesture.tapDownTime) * 0.000001f);
2954 } else {
2955 ALOGD("Gestures: Not a TAP, incompatible mode transitions");
2956 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002957 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002958 }
2959 }
2960
2961 mPointerVelocityControl.reset();
2962
2963 if (!tapped) {
Harry Cutts45483602022-08-24 14:36:48 +00002964 ALOGD_IF(DEBUG_GESTURES, "Gestures: NEUTRAL");
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002965 mPointerGesture.activeGestureId = -1;
Michael Wright227c5542020-07-02 18:30:52 +01002966 mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002967 mPointerGesture.currentGestureIdBits.clear();
2968 }
2969 } else if (currentFingerCount == 1) {
2970 // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
2971 // The pointer follows the active touch point.
2972 // When in HOVER, emit HOVER_MOVE events at the pointer location.
2973 // When in TAP_DRAG, emit MOVE events at the pointer location.
2974 ALOG_ASSERT(activeTouchId >= 0);
2975
Michael Wright227c5542020-07-02 18:30:52 +01002976 mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER;
2977 if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002978 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
Prabir Pradhande69f8a2021-11-18 16:40:34 +00002979 float x, y;
2980 mPointerController->getPosition(&x, &y);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002981 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
2982 fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
Michael Wright227c5542020-07-02 18:30:52 +01002983 mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002984 } else {
Harry Cutts45483602022-08-24 14:36:48 +00002985 ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
2986 x - mPointerGesture.tapX, y - mPointerGesture.tapY);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002987 }
2988 } else {
Harry Cutts45483602022-08-24 14:36:48 +00002989 ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP_DRAG, %0.3fms time since up",
2990 (when - mPointerGesture.tapUpTime) * 0.000001f);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002991 }
Michael Wright227c5542020-07-02 18:30:52 +01002992 } else if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) {
2993 mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002994 }
2995
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002996 if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002997 // When using spots, the hover or drag will occur at the position of the anchor spot.
Harry Cutts714d1ad2022-08-24 16:36:43 +00002998 moveMousePointerFromPointerDelta(when, activeTouchId);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002999 } else {
3000 mPointerVelocityControl.reset();
3001 }
3002
3003 bool down;
Michael Wright227c5542020-07-02 18:30:52 +01003004 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG) {
Harry Cutts45483602022-08-24 14:36:48 +00003005 ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP_DRAG");
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003006 down = true;
3007 } else {
Harry Cutts45483602022-08-24 14:36:48 +00003008 ALOGD_IF(DEBUG_GESTURES, "Gestures: HOVER");
Michael Wright227c5542020-07-02 18:30:52 +01003009 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003010 *outFinishPreviousGesture = true;
3011 }
3012 mPointerGesture.activeGestureId = 0;
3013 down = false;
3014 }
3015
Prabir Pradhande69f8a2021-11-18 16:40:34 +00003016 float x, y;
3017 mPointerController->getPosition(&x, &y);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003018
3019 mPointerGesture.currentGestureIdBits.clear();
3020 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
3021 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
3022 mPointerGesture.currentGestureProperties[0].clear();
3023 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
3024 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
3025 mPointerGesture.currentGestureCoords[0].clear();
3026 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
3027 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
3028 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
3029 down ? 1.0f : 0.0f);
3030
3031 if (lastFingerCount == 0 && currentFingerCount != 0) {
3032 mPointerGesture.resetTap();
3033 mPointerGesture.tapDownTime = when;
3034 mPointerGesture.tapX = x;
3035 mPointerGesture.tapY = y;
3036 }
3037 } else {
3038 // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
Harry Cuttsbea6ce52022-10-14 15:17:30 +00003039 prepareMultiFingerPointerGestures(when, outCancelPreviousGesture, outFinishPreviousGesture);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003040 }
3041
3042 mPointerController->setButtonState(mCurrentRawState.buttonState);
3043
Siarhei Vishniakou465e1c02021-12-09 10:47:29 -08003044 if (DEBUG_GESTURES) {
3045 ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
3046 "currentGestureMode=%d, currentGestureIdBits=0x%08x, "
3047 "lastGestureMode=%d, lastGestureIdBits=0x%08x",
3048 toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
3049 mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value,
3050 mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value);
3051 for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty();) {
3052 uint32_t id = idBits.clearFirstMarkedBit();
3053 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
3054 const PointerProperties& properties = mPointerGesture.currentGestureProperties[index];
3055 const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
3056 ALOGD(" currentGesture[%d]: index=%d, toolType=%d, "
3057 "x=%0.3f, y=%0.3f, pressure=%0.3f",
3058 id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
3059 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
3060 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
3061 }
3062 for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty();) {
3063 uint32_t id = idBits.clearFirstMarkedBit();
3064 uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
3065 const PointerProperties& properties = mPointerGesture.lastGestureProperties[index];
3066 const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
3067 ALOGD(" lastGesture[%d]: index=%d, toolType=%d, "
3068 "x=%0.3f, y=%0.3f, pressure=%0.3f",
3069 id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
3070 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
3071 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
3072 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003073 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003074 return true;
3075}
3076
Harry Cuttsbea6ce52022-10-14 15:17:30 +00003077bool TouchInputMapper::checkForTouchpadQuietTime(nsecs_t when) {
3078 if (mPointerGesture.activeTouchId < 0) {
3079 mPointerGesture.resetQuietTime();
3080 return false;
3081 }
3082
3083 if (when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval) {
3084 return true;
3085 }
3086
3087 const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
3088 bool isQuietTime = false;
3089 if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::PRESS ||
3090 mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE ||
3091 mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) &&
3092 currentFingerCount < 2) {
3093 // Enter quiet time when exiting swipe or freeform state.
3094 // This is to prevent accidentally entering the hover state and flinging the
3095 // pointer when finishing a swipe and there is still one pointer left onscreen.
3096 isQuietTime = true;
3097 } else if (mPointerGesture.lastGestureMode == PointerGesture::Mode::BUTTON_CLICK_OR_DRAG &&
3098 currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) {
3099 // Enter quiet time when releasing the button and there are still two or more
3100 // fingers down. This may indicate that one finger was used to press the button
3101 // but it has not gone up yet.
3102 isQuietTime = true;
3103 }
3104 if (isQuietTime) {
3105 mPointerGesture.quietTime = when;
3106 }
3107 return isQuietTime;
3108}
3109
3110std::pair<int32_t, float> TouchInputMapper::getFastestFinger() {
3111 int32_t bestId = -1;
3112 float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
3113 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
3114 uint32_t id = idBits.clearFirstMarkedBit();
3115 std::optional<float> vx =
3116 mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, id);
3117 std::optional<float> vy =
3118 mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, id);
3119 if (vx && vy) {
3120 float speed = hypotf(*vx, *vy);
3121 if (speed > bestSpeed) {
3122 bestId = id;
3123 bestSpeed = speed;
3124 }
3125 }
3126 }
3127 return std::make_pair(bestId, bestSpeed);
3128}
3129
3130void TouchInputMapper::prepareMultiFingerPointerGestures(nsecs_t when, bool* cancelPreviousGesture,
3131 bool* finishPreviousGesture) {
3132 // We need to provide feedback for each finger that goes down so we cannot wait for the fingers
3133 // to move before deciding what to do.
3134 //
3135 // The ambiguous case is deciding what to do when there are two fingers down but they have not
3136 // moved enough to determine whether they are part of a drag or part of a freeform gesture, or
3137 // just a press or long-press at the pointer location.
3138 //
3139 // When there are two fingers we start with the PRESS hypothesis and we generate a down at the
3140 // pointer location.
3141 //
3142 // When the two fingers move enough or when additional fingers are added, we make a decision to
3143 // transition into SWIPE or FREEFORM mode accordingly.
3144 const int32_t activeTouchId = mPointerGesture.activeTouchId;
3145 ALOG_ASSERT(activeTouchId >= 0);
3146
3147 const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
3148 const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
3149 bool settled =
3150 when >= mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval;
3151 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::PRESS &&
3152 mPointerGesture.lastGestureMode != PointerGesture::Mode::SWIPE &&
3153 mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
3154 *finishPreviousGesture = true;
3155 } else if (!settled && currentFingerCount > lastFingerCount) {
3156 // Additional pointers have gone down but not yet settled.
3157 // Reset the gesture.
3158 ALOGD_IF(DEBUG_GESTURES,
3159 "Gestures: Resetting gesture since additional pointers went down for "
3160 "MULTITOUCH, settle time remaining %0.3fms",
3161 (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval -
3162 when) * 0.000001f);
3163 *cancelPreviousGesture = true;
3164 } else {
3165 // Continue previous gesture.
3166 mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
3167 }
3168
3169 if (*finishPreviousGesture || *cancelPreviousGesture) {
3170 mPointerGesture.currentGestureMode = PointerGesture::Mode::PRESS;
3171 mPointerGesture.activeGestureId = 0;
3172 mPointerGesture.referenceIdBits.clear();
3173 mPointerVelocityControl.reset();
3174
3175 // Use the centroid and pointer location as the reference points for the gesture.
3176 ALOGD_IF(DEBUG_GESTURES,
3177 "Gestures: Using centroid as reference for MULTITOUCH, settle time remaining "
3178 "%0.3fms",
3179 (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval -
3180 when) * 0.000001f);
3181 mCurrentRawState.rawPointerData
3182 .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX,
3183 &mPointerGesture.referenceTouchY);
3184 mPointerController->getPosition(&mPointerGesture.referenceGestureX,
3185 &mPointerGesture.referenceGestureY);
3186 }
3187
3188 // Clear the reference deltas for fingers not yet included in the reference calculation.
3189 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value &
3190 ~mPointerGesture.referenceIdBits.value);
3191 !idBits.isEmpty();) {
3192 uint32_t id = idBits.clearFirstMarkedBit();
3193 mPointerGesture.referenceDeltas[id].dx = 0;
3194 mPointerGesture.referenceDeltas[id].dy = 0;
3195 }
3196 mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
3197
3198 // Add delta for all fingers and calculate a common movement delta.
3199 int32_t commonDeltaRawX = 0, commonDeltaRawY = 0;
3200 BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value &
3201 mCurrentCookedState.fingerIdBits.value);
3202 for (BitSet32 idBits(commonIdBits); !idBits.isEmpty();) {
3203 bool first = (idBits == commonIdBits);
3204 uint32_t id = idBits.clearFirstMarkedBit();
3205 const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id);
3206 const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id);
3207 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
3208 delta.dx += cpd.x - lpd.x;
3209 delta.dy += cpd.y - lpd.y;
3210
3211 if (first) {
3212 commonDeltaRawX = delta.dx;
3213 commonDeltaRawY = delta.dy;
3214 } else {
3215 commonDeltaRawX = calculateCommonVector(commonDeltaRawX, delta.dx);
3216 commonDeltaRawY = calculateCommonVector(commonDeltaRawY, delta.dy);
3217 }
3218 }
3219
3220 // Consider transitions from PRESS to SWIPE or MULTITOUCH.
3221 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS) {
3222 float dist[MAX_POINTER_ID + 1];
3223 int32_t distOverThreshold = 0;
3224 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
3225 uint32_t id = idBits.clearFirstMarkedBit();
3226 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
3227 dist[id] = hypotf(delta.dx * mPointerXZoomScale, delta.dy * mPointerYZoomScale);
3228 if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) {
3229 distOverThreshold += 1;
3230 }
3231 }
3232
3233 // Only transition when at least two pointers have moved further than
3234 // the minimum distance threshold.
3235 if (distOverThreshold >= 2) {
3236 if (currentFingerCount > 2) {
3237 // There are more than two pointers, switch to FREEFORM.
3238 ALOGD_IF(DEBUG_GESTURES,
3239 "Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
3240 currentFingerCount);
3241 *cancelPreviousGesture = true;
3242 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
3243 } else {
3244 // There are exactly two pointers.
3245 BitSet32 idBits(mCurrentCookedState.fingerIdBits);
3246 uint32_t id1 = idBits.clearFirstMarkedBit();
3247 uint32_t id2 = idBits.firstMarkedBit();
3248 const RawPointerData::Pointer& p1 =
3249 mCurrentRawState.rawPointerData.pointerForId(id1);
3250 const RawPointerData::Pointer& p2 =
3251 mCurrentRawState.rawPointerData.pointerForId(id2);
3252 float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
3253 if (mutualDistance > mPointerGestureMaxSwipeWidth) {
3254 // There are two pointers but they are too far apart for a SWIPE,
3255 // switch to FREEFORM.
3256 ALOGD_IF(DEBUG_GESTURES,
3257 "Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
3258 mutualDistance, mPointerGestureMaxSwipeWidth);
3259 *cancelPreviousGesture = true;
3260 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
3261 } else {
3262 // There are two pointers. Wait for both pointers to start moving
3263 // before deciding whether this is a SWIPE or FREEFORM gesture.
3264 float dist1 = dist[id1];
3265 float dist2 = dist[id2];
3266 if (dist1 >= mConfig.pointerGestureMultitouchMinDistance &&
3267 dist2 >= mConfig.pointerGestureMultitouchMinDistance) {
3268 // Calculate the dot product of the displacement vectors.
3269 // When the vectors are oriented in approximately the same direction,
3270 // the angle betweeen them is near zero and the cosine of the angle
3271 // approaches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) *
3272 // mag(v2).
3273 PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
3274 PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
3275 float dx1 = delta1.dx * mPointerXZoomScale;
3276 float dy1 = delta1.dy * mPointerYZoomScale;
3277 float dx2 = delta2.dx * mPointerXZoomScale;
3278 float dy2 = delta2.dy * mPointerYZoomScale;
3279 float dot = dx1 * dx2 + dy1 * dy2;
3280 float cosine = dot / (dist1 * dist2); // denominator always > 0
3281 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) {
3282 // Pointers are moving in the same direction. Switch to SWIPE.
3283 ALOGD_IF(DEBUG_GESTURES,
3284 "Gestures: PRESS transitioned to SWIPE, "
3285 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
3286 "cosine %0.3f >= %0.3f",
3287 dist1, mConfig.pointerGestureMultitouchMinDistance, dist2,
3288 mConfig.pointerGestureMultitouchMinDistance, cosine,
3289 mConfig.pointerGestureSwipeTransitionAngleCosine);
3290 mPointerGesture.currentGestureMode = PointerGesture::Mode::SWIPE;
3291 } else {
3292 // Pointers are moving in different directions. Switch to FREEFORM.
3293 ALOGD_IF(DEBUG_GESTURES,
3294 "Gestures: PRESS transitioned to FREEFORM, "
3295 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
3296 "cosine %0.3f < %0.3f",
3297 dist1, mConfig.pointerGestureMultitouchMinDistance, dist2,
3298 mConfig.pointerGestureMultitouchMinDistance, cosine,
3299 mConfig.pointerGestureSwipeTransitionAngleCosine);
3300 *cancelPreviousGesture = true;
3301 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
3302 }
3303 }
3304 }
3305 }
3306 }
3307 } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
3308 // Switch from SWIPE to FREEFORM if additional pointers go down.
3309 // Cancel previous gesture.
3310 if (currentFingerCount > 2) {
3311 ALOGD_IF(DEBUG_GESTURES,
3312 "Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2",
3313 currentFingerCount);
3314 *cancelPreviousGesture = true;
3315 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
3316 }
3317 }
3318
3319 // Move the reference points based on the overall group motion of the fingers
3320 // except in PRESS mode while waiting for a transition to occur.
3321 if (mPointerGesture.currentGestureMode != PointerGesture::Mode::PRESS &&
3322 (commonDeltaRawX || commonDeltaRawY)) {
3323 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
3324 uint32_t id = idBits.clearFirstMarkedBit();
3325 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
3326 delta.dx = 0;
3327 delta.dy = 0;
3328 }
3329
3330 mPointerGesture.referenceTouchX += commonDeltaRawX;
3331 mPointerGesture.referenceTouchY += commonDeltaRawY;
3332
3333 float commonDeltaX = commonDeltaRawX * mPointerXMovementScale;
3334 float commonDeltaY = commonDeltaRawY * mPointerYMovementScale;
3335
3336 rotateDelta(mInputDeviceOrientation, &commonDeltaX, &commonDeltaY);
3337 mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
3338
3339 mPointerGesture.referenceGestureX += commonDeltaX;
3340 mPointerGesture.referenceGestureY += commonDeltaY;
3341 }
3342
3343 // Report gestures.
3344 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
3345 mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
3346 // PRESS or SWIPE mode.
3347 ALOGD_IF(DEBUG_GESTURES,
3348 "Gestures: PRESS or SWIPE activeTouchId=%d, activeGestureId=%d, "
3349 "currentTouchPointerCount=%d",
3350 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
3351 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
3352
3353 mPointerGesture.currentGestureIdBits.clear();
3354 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
3355 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
3356 mPointerGesture.currentGestureProperties[0].clear();
3357 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
3358 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
3359 mPointerGesture.currentGestureCoords[0].clear();
3360 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
3361 mPointerGesture.referenceGestureX);
3362 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
3363 mPointerGesture.referenceGestureY);
3364 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
3365 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
3366 float xOffset = static_cast<float>(commonDeltaRawX) /
3367 (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue);
3368 float yOffset = static_cast<float>(commonDeltaRawY) /
3369 (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue);
3370 mPointerGesture.currentGestureCoords[0]
3371 .setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, xOffset);
3372 mPointerGesture.currentGestureCoords[0]
3373 .setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, yOffset);
3374 }
3375 } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
3376 // FREEFORM mode.
3377 ALOGD_IF(DEBUG_GESTURES,
3378 "Gestures: FREEFORM activeTouchId=%d, activeGestureId=%d, "
3379 "currentTouchPointerCount=%d",
3380 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
3381 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
3382
3383 mPointerGesture.currentGestureIdBits.clear();
3384
3385 BitSet32 mappedTouchIdBits;
3386 BitSet32 usedGestureIdBits;
3387 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
3388 // Initially, assign the active gesture id to the active touch point
3389 // if there is one. No other touch id bits are mapped yet.
3390 if (!*cancelPreviousGesture) {
3391 mappedTouchIdBits.markBit(activeTouchId);
3392 usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
3393 mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
3394 mPointerGesture.activeGestureId;
3395 } else {
3396 mPointerGesture.activeGestureId = -1;
3397 }
3398 } else {
3399 // Otherwise, assume we mapped all touches from the previous frame.
3400 // Reuse all mappings that are still applicable.
3401 mappedTouchIdBits.value =
3402 mLastCookedState.fingerIdBits.value & mCurrentCookedState.fingerIdBits.value;
3403 usedGestureIdBits = mPointerGesture.lastGestureIdBits;
3404
3405 // Check whether we need to choose a new active gesture id because the
3406 // current went went up.
3407 for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value &
3408 ~mCurrentCookedState.fingerIdBits.value);
3409 !upTouchIdBits.isEmpty();) {
3410 uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
3411 uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
3412 if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
3413 mPointerGesture.activeGestureId = -1;
3414 break;
3415 }
3416 }
3417 }
3418
3419 ALOGD_IF(DEBUG_GESTURES,
3420 "Gestures: FREEFORM follow up mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
3421 "activeGestureId=%d",
3422 mappedTouchIdBits.value, usedGestureIdBits.value, mPointerGesture.activeGestureId);
3423
3424 BitSet32 idBits(mCurrentCookedState.fingerIdBits);
3425 for (uint32_t i = 0; i < currentFingerCount; i++) {
3426 uint32_t touchId = idBits.clearFirstMarkedBit();
3427 uint32_t gestureId;
3428 if (!mappedTouchIdBits.hasBit(touchId)) {
3429 gestureId = usedGestureIdBits.markFirstUnmarkedBit();
3430 mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
3431 ALOGD_IF(DEBUG_GESTURES,
3432 "Gestures: FREEFORM new mapping for touch id %d -> gesture id %d", touchId,
3433 gestureId);
3434 } else {
3435 gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
3436 ALOGD_IF(DEBUG_GESTURES,
3437 "Gestures: FREEFORM existing mapping for touch id %d -> gesture id %d",
3438 touchId, gestureId);
3439 }
3440 mPointerGesture.currentGestureIdBits.markBit(gestureId);
3441 mPointerGesture.currentGestureIdToIndex[gestureId] = i;
3442
3443 const RawPointerData::Pointer& pointer =
3444 mCurrentRawState.rawPointerData.pointerForId(touchId);
3445 float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale;
3446 float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale;
3447 rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
3448
3449 mPointerGesture.currentGestureProperties[i].clear();
3450 mPointerGesture.currentGestureProperties[i].id = gestureId;
3451 mPointerGesture.currentGestureProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
3452 mPointerGesture.currentGestureCoords[i].clear();
3453 mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X,
3454 mPointerGesture.referenceGestureX +
3455 deltaX);
3456 mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y,
3457 mPointerGesture.referenceGestureY +
3458 deltaY);
3459 mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
3460 }
3461
3462 if (mPointerGesture.activeGestureId < 0) {
3463 mPointerGesture.activeGestureId = mPointerGesture.currentGestureIdBits.firstMarkedBit();
3464 ALOGD_IF(DEBUG_GESTURES, "Gestures: FREEFORM new activeGestureId=%d",
3465 mPointerGesture.activeGestureId);
3466 }
3467 }
3468}
3469
Harry Cutts714d1ad2022-08-24 16:36:43 +00003470void TouchInputMapper::moveMousePointerFromPointerDelta(nsecs_t when, uint32_t pointerId) {
3471 const RawPointerData::Pointer& currentPointer =
3472 mCurrentRawState.rawPointerData.pointerForId(pointerId);
3473 const RawPointerData::Pointer& lastPointer =
3474 mLastRawState.rawPointerData.pointerForId(pointerId);
3475 float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
3476 float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
3477
3478 rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
3479 mPointerVelocityControl.move(when, &deltaX, &deltaY);
3480
3481 mPointerController->move(deltaX, deltaY);
3482}
3483
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003484std::list<NotifyArgs> TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime,
3485 uint32_t policyFlags) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003486 mPointerSimple.currentCoords.clear();
3487 mPointerSimple.currentProperties.clear();
3488
3489 bool down, hovering;
3490 if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
3491 uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit();
3492 uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id];
Prabir Pradhande69f8a2021-11-18 16:40:34 +00003493 mPointerController
3494 ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(),
3495 mCurrentCookedState.cookedPointerData.pointerCoords[index].getY());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003496
3497 hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
3498 down = !hovering;
3499
Prabir Pradhande69f8a2021-11-18 16:40:34 +00003500 float x, y;
3501 mPointerController->getPosition(&x, &y);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003502 mPointerSimple.currentCoords.copyFrom(
3503 mCurrentCookedState.cookedPointerData.pointerCoords[index]);
3504 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
3505 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
3506 mPointerSimple.currentProperties.id = 0;
3507 mPointerSimple.currentProperties.toolType =
3508 mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType;
3509 } else {
3510 down = false;
3511 hovering = false;
3512 }
3513
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003514 return dispatchPointerSimple(when, readTime, policyFlags, down, hovering);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003515}
3516
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003517std::list<NotifyArgs> TouchInputMapper::abortPointerStylus(nsecs_t when, nsecs_t readTime,
3518 uint32_t policyFlags) {
3519 return abortPointerSimple(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003520}
3521
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003522std::list<NotifyArgs> TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs_t readTime,
3523 uint32_t policyFlags) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003524 mPointerSimple.currentCoords.clear();
3525 mPointerSimple.currentProperties.clear();
3526
3527 bool down, hovering;
3528 if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
3529 uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003530 if (mLastCookedState.mouseIdBits.hasBit(id)) {
Harry Cutts714d1ad2022-08-24 16:36:43 +00003531 moveMousePointerFromPointerDelta(when, id);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003532 } else {
3533 mPointerVelocityControl.reset();
3534 }
3535
3536 down = isPointerDown(mCurrentRawState.buttonState);
3537 hovering = !down;
3538
Prabir Pradhande69f8a2021-11-18 16:40:34 +00003539 float x, y;
3540 mPointerController->getPosition(&x, &y);
Harry Cutts714d1ad2022-08-24 16:36:43 +00003541 uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003542 mPointerSimple.currentCoords.copyFrom(
3543 mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
3544 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
3545 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
3546 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
3547 hovering ? 0.0f : 1.0f);
3548 mPointerSimple.currentProperties.id = 0;
3549 mPointerSimple.currentProperties.toolType =
3550 mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
3551 } else {
3552 mPointerVelocityControl.reset();
3553
3554 down = false;
3555 hovering = false;
3556 }
3557
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003558 return dispatchPointerSimple(when, readTime, policyFlags, down, hovering);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003559}
3560
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003561std::list<NotifyArgs> TouchInputMapper::abortPointerMouse(nsecs_t when, nsecs_t readTime,
3562 uint32_t policyFlags) {
3563 std::list<NotifyArgs> out = abortPointerSimple(when, readTime, policyFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003564
3565 mPointerVelocityControl.reset();
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003566
3567 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003568}
3569
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003570std::list<NotifyArgs> TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime,
3571 uint32_t policyFlags, bool down,
3572 bool hovering) {
Prabir Pradhanb80b6c02022-11-02 20:05:13 +00003573 LOG_ALWAYS_FATAL_IF(mDeviceMode != DeviceMode::POINTER,
3574 "%s cannot be used when the device is not in POINTER mode.", __func__);
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003575 std::list<NotifyArgs> out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003576 int32_t metaState = getContext()->getGlobalMetaState();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003577
3578 if (down || hovering) {
Michael Wrightca5bede2020-07-02 00:00:29 +01003579 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003580 mPointerController->clearSpots();
3581 mPointerController->setButtonState(mCurrentRawState.buttonState);
Michael Wrightca5bede2020-07-02 00:00:29 +01003582 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003583 } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
Michael Wrightca5bede2020-07-02 00:00:29 +01003584 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003585 }
Garfield Tan9514d782020-11-10 16:37:23 -08003586 int32_t displayId = mPointerController->getDisplayId();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003587
Prabir Pradhande69f8a2021-11-18 16:40:34 +00003588 float xCursorPosition, yCursorPosition;
3589 mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003590
3591 if (mPointerSimple.down && !down) {
3592 mPointerSimple.down = false;
3593
3594 // Send up.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003595 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3596 mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0,
3597 0, metaState, mLastRawState.buttonState,
3598 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3599 &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
3600 mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
3601 yCursorPosition, mPointerSimple.downTime,
3602 /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003603 }
3604
3605 if (mPointerSimple.hovering && !hovering) {
3606 mPointerSimple.hovering = false;
3607
3608 // Send hover exit.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003609 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3610 mSource, displayId, policyFlags,
3611 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
3612 mLastRawState.buttonState, MotionClassification::NONE,
3613 AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3614 &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
3615 mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
3616 yCursorPosition, mPointerSimple.downTime,
3617 /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003618 }
3619
3620 if (down) {
3621 if (!mPointerSimple.down) {
3622 mPointerSimple.down = true;
3623 mPointerSimple.downTime = when;
3624
3625 // Send down.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003626 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3627 mSource, displayId, policyFlags,
3628 AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState,
3629 mCurrentRawState.buttonState, MotionClassification::NONE,
3630 AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3631 &mPointerSimple.currentProperties,
3632 &mPointerSimple.currentCoords, mOrientedXPrecision,
3633 mOrientedYPrecision, xCursorPosition, yCursorPosition,
3634 mPointerSimple.downTime, /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003635 }
3636
3637 // Send move.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003638 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3639 mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE,
3640 0, 0, metaState, mCurrentRawState.buttonState,
3641 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3642 &mPointerSimple.currentProperties,
3643 &mPointerSimple.currentCoords, mOrientedXPrecision,
3644 mOrientedYPrecision, xCursorPosition, yCursorPosition,
3645 mPointerSimple.downTime, /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003646 }
3647
3648 if (hovering) {
3649 if (!mPointerSimple.hovering) {
3650 mPointerSimple.hovering = true;
3651
3652 // Send hover enter.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003653 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3654 mSource, displayId, policyFlags,
3655 AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
3656 mCurrentRawState.buttonState, MotionClassification::NONE,
3657 AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3658 &mPointerSimple.currentProperties,
3659 &mPointerSimple.currentCoords, mOrientedXPrecision,
3660 mOrientedYPrecision, xCursorPosition, yCursorPosition,
3661 mPointerSimple.downTime, /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003662 }
3663
3664 // Send hover move.
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003665 out.push_back(
3666 NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
3667 displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
3668 metaState, mCurrentRawState.buttonState,
3669 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3670 &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
3671 mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
3672 yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003673 }
3674
3675 if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
3676 float vscroll = mCurrentRawState.rawVScroll;
3677 float hscroll = mCurrentRawState.rawHScroll;
3678 mWheelYVelocityControl.move(when, nullptr, &vscroll);
3679 mWheelXVelocityControl.move(when, &hscroll, nullptr);
3680
3681 // Send scroll.
3682 PointerCoords pointerCoords;
3683 pointerCoords.copyFrom(mPointerSimple.currentCoords);
3684 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
3685 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
3686
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003687 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3688 mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL,
3689 0, 0, metaState, mCurrentRawState.buttonState,
3690 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3691 &mPointerSimple.currentProperties, &pointerCoords,
3692 mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
3693 yCursorPosition, mPointerSimple.downTime,
3694 /* videoFrames */ {}));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003695 }
3696
3697 // Save state.
3698 if (down || hovering) {
3699 mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords);
3700 mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties);
Prabir Pradhanb80b6c02022-11-02 20:05:13 +00003701 mPointerSimple.displayId = displayId;
3702 mPointerSimple.source = mSource;
3703 mPointerSimple.lastCursorX = xCursorPosition;
3704 mPointerSimple.lastCursorY = yCursorPosition;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003705 } else {
3706 mPointerSimple.reset();
3707 }
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003708 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003709}
3710
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003711std::list<NotifyArgs> TouchInputMapper::abortPointerSimple(nsecs_t when, nsecs_t readTime,
3712 uint32_t policyFlags) {
Prabir Pradhanb80b6c02022-11-02 20:05:13 +00003713 std::list<NotifyArgs> out;
3714 if (mPointerSimple.down || mPointerSimple.hovering) {
3715 int32_t metaState = getContext()->getGlobalMetaState();
3716 out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
3717 mPointerSimple.source, mPointerSimple.displayId, policyFlags,
3718 AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED,
3719 metaState, mLastRawState.buttonState,
3720 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3721 &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
3722 mOrientedXPrecision, mOrientedYPrecision,
3723 mPointerSimple.lastCursorX, mPointerSimple.lastCursorY,
3724 mPointerSimple.downTime,
3725 /* videoFrames */ {}));
3726 if (mPointerController != nullptr) {
3727 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
3728 }
3729 }
3730 mPointerSimple.reset();
3731 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003732}
3733
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003734NotifyMotionArgs TouchInputMapper::dispatchMotion(
3735 nsecs_t when, nsecs_t readTime, uint32_t policyFlags, uint32_t source, int32_t action,
3736 int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState,
Prabir Pradhand6ccedb2022-09-27 21:04:06 +00003737 int32_t edgeFlags, const PropertiesArray& properties, const CoordsArray& coords,
3738 const IdToIndexArray& idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision,
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003739 float yPrecision, nsecs_t downTime, MotionClassification classification) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003740 PointerCoords pointerCoords[MAX_POINTERS];
3741 PointerProperties pointerProperties[MAX_POINTERS];
3742 uint32_t pointerCount = 0;
3743 while (!idBits.isEmpty()) {
3744 uint32_t id = idBits.clearFirstMarkedBit();
3745 uint32_t index = idToIndex[id];
3746 pointerProperties[pointerCount].copyFrom(properties[index]);
3747 pointerCoords[pointerCount].copyFrom(coords[index]);
3748
3749 if (changedId >= 0 && id == uint32_t(changedId)) {
3750 action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
3751 }
3752
3753 pointerCount += 1;
3754 }
3755
3756 ALOG_ASSERT(pointerCount != 0);
3757
3758 if (changedId >= 0 && pointerCount == 1) {
3759 // Replace initial down and final up action.
3760 // We can compare the action without masking off the changed pointer index
3761 // because we know the index is 0.
3762 if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
3763 action = AMOTION_EVENT_ACTION_DOWN;
3764 } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
arthurhungcc7f9802020-04-30 17:55:40 +08003765 if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) {
3766 action = AMOTION_EVENT_ACTION_CANCEL;
3767 } else {
3768 action = AMOTION_EVENT_ACTION_UP;
3769 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003770 } else {
3771 // Can't happen.
3772 ALOG_ASSERT(false);
3773 }
3774 }
3775 float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
3776 float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
Michael Wright227c5542020-07-02 18:30:52 +01003777 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhande69f8a2021-11-18 16:40:34 +00003778 mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003779 }
3780 const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
3781 const int32_t deviceId = getDeviceId();
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08003782 std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003783 std::for_each(frames.begin(), frames.end(),
Prabir Pradhan1728b212021-10-19 16:00:03 -07003784 [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003785 return NotifyMotionArgs(getContext()->getNextId(), when, readTime, deviceId, source, displayId,
3786 policyFlags, action, actionButton, flags, metaState, buttonState,
3787 classification, edgeFlags, pointerCount, pointerProperties,
3788 pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
3789 downTime, std::move(frames));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003790}
3791
Siarhei Vishniakou2935db72022-09-22 13:35:22 -07003792std::list<NotifyArgs> TouchInputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) {
3793 std::list<NotifyArgs> out;
3794 out += abortPointerUsage(when, readTime, 0 /*policyFlags*/);
3795 out += abortTouches(when, readTime, 0 /* policyFlags*/);
3796 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003797}
3798
Prabir Pradhan1728b212021-10-19 16:00:03 -07003799// Transform input device coordinates to display panel coordinates.
3800void TouchInputMapper::rotateAndScale(float& x, float& y) const {
Arthur Hung4197f6b2020-03-16 15:39:59 +08003801 const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
3802 const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
3803
arthurhunga36b28e2020-12-29 20:28:15 +08003804 const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
3805 const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;
3806
Prabir Pradhan1728b212021-10-19 16:00:03 -07003807 // Rotate to display coordinate.
Arthur Hung4197f6b2020-03-16 15:39:59 +08003808 // 0 - no swap and reverse.
3809 // 90 - swap x/y and reverse y.
3810 // 180 - reverse x, y.
3811 // 270 - swap x/y and reverse x.
Prabir Pradhan1728b212021-10-19 16:00:03 -07003812 switch (mInputDeviceOrientation) {
Michael Wrighta9cf4192022-12-01 23:46:39 +00003813 case ui::ROTATION_0:
Prabir Pradhan1728b212021-10-19 16:00:03 -07003814 x = xScaled;
3815 y = yScaled;
Arthur Hung4197f6b2020-03-16 15:39:59 +08003816 break;
Michael Wrighta9cf4192022-12-01 23:46:39 +00003817 case ui::ROTATION_90:
Prabir Pradhan1728b212021-10-19 16:00:03 -07003818 y = xScaledMax;
3819 x = yScaled;
Arthur Hung05de5772019-09-26 18:31:26 +08003820 break;
Michael Wrighta9cf4192022-12-01 23:46:39 +00003821 case ui::ROTATION_180:
Prabir Pradhan1728b212021-10-19 16:00:03 -07003822 x = xScaledMax;
3823 y = yScaledMax;
Arthur Hung05de5772019-09-26 18:31:26 +08003824 break;
Michael Wrighta9cf4192022-12-01 23:46:39 +00003825 case ui::ROTATION_270:
Prabir Pradhan1728b212021-10-19 16:00:03 -07003826 y = xScaled;
3827 x = yScaledMax;
Arthur Hung05de5772019-09-26 18:31:26 +08003828 break;
3829 default:
Arthur Hung4197f6b2020-03-16 15:39:59 +08003830 assert(false);
Arthur Hung05de5772019-09-26 18:31:26 +08003831 }
3832}
3833
Prabir Pradhan1728b212021-10-19 16:00:03 -07003834bool TouchInputMapper::isPointInsidePhysicalFrame(int32_t x, int32_t y) const {
Arthur Hung4197f6b2020-03-16 15:39:59 +08003835 const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
3836 const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;
3837
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003838 return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003839 y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
Prabir Pradhan7ddbc952022-11-09 22:03:40 +00003840 isPointInRect(mPhysicalFrameInDisplay, xScaled, yScaled);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003841}
3842
3843const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
3844 for (const VirtualKey& virtualKey : mVirtualKeys) {
Harry Cutts45483602022-08-24 14:36:48 +00003845 ALOGD_IF(DEBUG_VIRTUAL_KEYS,
3846 "VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
3847 "left=%d, top=%d, right=%d, bottom=%d",
3848 x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft,
3849 virtualKey.hitTop, virtualKey.hitRight, virtualKey.hitBottom);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003850
3851 if (virtualKey.isHit(x, y)) {
3852 return &virtualKey;
3853 }
3854 }
3855
3856 return nullptr;
3857}
3858
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003859void TouchInputMapper::assignPointerIds(const RawState& last, RawState& current) {
3860 uint32_t currentPointerCount = current.rawPointerData.pointerCount;
3861 uint32_t lastPointerCount = last.rawPointerData.pointerCount;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003862
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003863 current.rawPointerData.clearIdBits();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003864
3865 if (currentPointerCount == 0) {
3866 // No pointers to assign.
3867 return;
3868 }
3869
3870 if (lastPointerCount == 0) {
3871 // All pointers are new.
3872 for (uint32_t i = 0; i < currentPointerCount; i++) {
3873 uint32_t id = i;
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003874 current.rawPointerData.pointers[i].id = id;
3875 current.rawPointerData.idToIndex[id] = i;
3876 current.rawPointerData.markIdBit(id, current.rawPointerData.isHovering(i));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003877 }
3878 return;
3879 }
3880
3881 if (currentPointerCount == 1 && lastPointerCount == 1 &&
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003882 current.rawPointerData.pointers[0].toolType == last.rawPointerData.pointers[0].toolType) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003883 // Only one pointer and no change in count so it must have the same id as before.
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003884 uint32_t id = last.rawPointerData.pointers[0].id;
3885 current.rawPointerData.pointers[0].id = id;
3886 current.rawPointerData.idToIndex[id] = 0;
3887 current.rawPointerData.markIdBit(id, current.rawPointerData.isHovering(0));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003888 return;
3889 }
3890
3891 // General case.
3892 // We build a heap of squared euclidean distances between current and last pointers
3893 // associated with the current and last pointer indices. Then, we find the best
3894 // match (by distance) for each current pointer.
3895 // The pointers must have the same tool type but it is possible for them to
3896 // transition from hovering to touching or vice-versa while retaining the same id.
3897 PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
3898
3899 uint32_t heapSize = 0;
3900 for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
3901 currentPointerIndex++) {
3902 for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
3903 lastPointerIndex++) {
3904 const RawPointerData::Pointer& currentPointer =
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003905 current.rawPointerData.pointers[currentPointerIndex];
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003906 const RawPointerData::Pointer& lastPointer =
Siarhei Vishniakou57479982021-03-03 01:32:21 +00003907 last.rawPointerData.pointers[lastPointerIndex];
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003908 if (currentPointer.toolType == lastPointer.toolType) {
3909 int64_t deltaX = currentPointer.x - lastPointer.x;
3910 int64_t deltaY = currentPointer.y - lastPointer.y;
3911
3912 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
3913
3914 // Insert new element into the heap (sift up).
3915 heap[heapSize].currentPointerIndex = currentPointerIndex;
3916 heap[heapSize].lastPointerIndex = lastPointerIndex;
3917 heap[heapSize].distance = distance;
3918 heapSize += 1;
3919 }
3920 }
3921 }
3922
3923 // Heapify
3924 for (uint32_t startIndex = heapSize / 2; startIndex != 0;) {
3925 startIndex -= 1;
3926 for (uint32_t parentIndex = startIndex;;) {
3927 uint32_t childIndex = parentIndex * 2 + 1;
3928 if (childIndex >= heapSize) {
3929 break;
3930 }
3931
3932 if (childIndex + 1 < heapSize &&
3933 heap[childIndex + 1].distance < heap[childIndex].distance) {
3934 childIndex += 1;
3935 }
3936
3937 if (heap[parentIndex].distance <= heap[childIndex].distance) {
3938 break;
3939 }
3940
3941 swap(heap[parentIndex], heap[childIndex]);
3942 parentIndex = childIndex;
3943 }
3944 }
3945
Siarhei Vishniakou465e1c02021-12-09 10:47:29 -08003946 if (DEBUG_POINTER_ASSIGNMENT) {
3947 ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
3948 for (size_t i = 0; i < heapSize; i++) {
3949 ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i,
3950 heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance);
3951 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003952 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003953
3954 // Pull matches out by increasing order of distance.
3955 // To avoid reassigning pointers that have already been matched, the loop keeps track
3956 // of which last and current pointers have been matched using the matchedXXXBits variables.
3957 // It also tracks the used pointer id bits.
3958 BitSet32 matchedLastBits(0);
3959 BitSet32 matchedCurrentBits(0);
3960 BitSet32 usedIdBits(0);
3961 bool first = true;
3962 for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) {
3963 while (heapSize > 0) {
3964 if (first) {
3965 // The first time through the loop, we just consume the root element of
3966 // the heap (the one with smallest distance).
3967 first = false;
3968 } else {
3969 // Previous iterations consumed the root element of the heap.
3970 // Pop root element off of the heap (sift down).
3971 heap[0] = heap[heapSize];
3972 for (uint32_t parentIndex = 0;;) {
3973 uint32_t childIndex = parentIndex * 2 + 1;
3974 if (childIndex >= heapSize) {
3975 break;
3976 }
3977
3978 if (childIndex + 1 < heapSize &&
3979 heap[childIndex + 1].distance < heap[childIndex].distance) {
3980 childIndex += 1;
3981 }
3982
3983 if (heap[parentIndex].distance <= heap[childIndex].distance) {
3984 break;
3985 }
3986
3987 swap(heap[parentIndex], heap[childIndex]);
3988 parentIndex = childIndex;
3989 }
3990
Siarhei Vishniakou465e1c02021-12-09 10:47:29 -08003991 if (DEBUG_POINTER_ASSIGNMENT) {
3992 ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
3993 for (size_t j = 0; j < heapSize; j++) {
3994 ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64,
3995 j, heap[j].currentPointerIndex, heap[j].lastPointerIndex,
3996 heap[j].distance);
3997 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003998 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003999 }
4000
4001 heapSize -= 1;
4002
4003 uint32_t currentPointerIndex = heap[0].currentPointerIndex;
4004 if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
4005
4006 uint32_t lastPointerIndex = heap[0].lastPointerIndex;
4007 if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
4008
4009 matchedCurrentBits.markBit(currentPointerIndex);
4010 matchedLastBits.markBit(lastPointerIndex);
4011
Siarhei Vishniakou57479982021-03-03 01:32:21 +00004012 uint32_t id = last.rawPointerData.pointers[lastPointerIndex].id;
4013 current.rawPointerData.pointers[currentPointerIndex].id = id;
4014 current.rawPointerData.idToIndex[id] = currentPointerIndex;
4015 current.rawPointerData.markIdBit(id,
4016 current.rawPointerData.isHovering(
4017 currentPointerIndex));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004018 usedIdBits.markBit(id);
4019
Harry Cutts45483602022-08-24 14:36:48 +00004020 ALOGD_IF(DEBUG_POINTER_ASSIGNMENT,
4021 "assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 ", id=%" PRIu32
4022 ", distance=%" PRIu64,
4023 lastPointerIndex, currentPointerIndex, id, heap[0].distance);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004024 break;
4025 }
4026 }
4027
4028 // Assign fresh ids to pointers that were not matched in the process.
4029 for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) {
4030 uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
4031 uint32_t id = usedIdBits.markFirstUnmarkedBit();
4032
Siarhei Vishniakou57479982021-03-03 01:32:21 +00004033 current.rawPointerData.pointers[currentPointerIndex].id = id;
4034 current.rawPointerData.idToIndex[id] = currentPointerIndex;
4035 current.rawPointerData.markIdBit(id,
4036 current.rawPointerData.isHovering(currentPointerIndex));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004037
Harry Cutts45483602022-08-24 14:36:48 +00004038 ALOGD_IF(DEBUG_POINTER_ASSIGNMENT,
4039 "assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex,
4040 id);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004041 }
4042}
4043
4044int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
4045 if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
4046 return AKEY_STATE_VIRTUAL;
4047 }
4048
4049 for (const VirtualKey& virtualKey : mVirtualKeys) {
4050 if (virtualKey.keyCode == keyCode) {
4051 return AKEY_STATE_UP;
4052 }
4053 }
4054
4055 return AKEY_STATE_UNKNOWN;
4056}
4057
4058int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
4059 if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
4060 return AKEY_STATE_VIRTUAL;
4061 }
4062
4063 for (const VirtualKey& virtualKey : mVirtualKeys) {
4064 if (virtualKey.scanCode == scanCode) {
4065 return AKEY_STATE_UP;
4066 }
4067 }
4068
4069 return AKEY_STATE_UNKNOWN;
4070}
4071
Siarhei Vishniakou74007942022-06-13 13:57:47 -07004072bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask,
4073 const std::vector<int32_t>& keyCodes,
4074 uint8_t* outFlags) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004075 for (const VirtualKey& virtualKey : mVirtualKeys) {
Siarhei Vishniakou74007942022-06-13 13:57:47 -07004076 for (size_t i = 0; i < keyCodes.size(); i++) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004077 if (virtualKey.keyCode == keyCodes[i]) {
4078 outFlags[i] = 1;
4079 }
4080 }
4081 }
4082
4083 return true;
4084}
4085
4086std::optional<int32_t> TouchInputMapper::getAssociatedDisplayId() {
4087 if (mParameters.hasAssociatedDisplay) {
Michael Wright227c5542020-07-02 18:30:52 +01004088 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004089 return std::make_optional(mPointerController->getDisplayId());
4090 } else {
4091 return std::make_optional(mViewport.displayId);
4092 }
4093 }
4094 return std::nullopt;
4095}
4096
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07004097} // namespace android