blob: 5545f1ca124a56cb925b1a1ee6de77a5e39672a2 [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
23#include "CursorButtonAccumulator.h"
24#include "CursorScrollAccumulator.h"
25#include "TouchButtonAccumulator.h"
26#include "TouchCursorInputMapperCommon.h"
27
28namespace android {
29
30// --- Constants ---
31
32// Maximum amount of latency to add to touch events while waiting for data from an
33// external stylus.
34static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
35
36// Maximum amount of time to wait on touch data before pushing out new pressure data.
37static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
38
39// Artificial latency on synthetic events created from stylus data without corresponding touch
40// data.
41static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
42
43// --- Static Definitions ---
44
45template <typename T>
46inline static void swap(T& a, T& b) {
47 T temp = a;
48 a = b;
49 b = temp;
50}
51
52static float calculateCommonVector(float a, float b) {
53 if (a > 0 && b > 0) {
54 return a < b ? a : b;
55 } else if (a < 0 && b < 0) {
56 return a > b ? a : b;
57 } else {
58 return 0;
59 }
60}
61
62inline static float distance(float x1, float y1, float x2, float y2) {
63 return hypotf(x1 - x2, y1 - y2);
64}
65
66inline static int32_t signExtendNybble(int32_t value) {
67 return value >= 8 ? value - 16 : value;
68}
69
70// --- RawPointerAxes ---
71
72RawPointerAxes::RawPointerAxes() {
73 clear();
74}
75
76void RawPointerAxes::clear() {
77 x.clear();
78 y.clear();
79 pressure.clear();
80 touchMajor.clear();
81 touchMinor.clear();
82 toolMajor.clear();
83 toolMinor.clear();
84 orientation.clear();
85 distance.clear();
86 tiltX.clear();
87 tiltY.clear();
88 trackingId.clear();
89 slot.clear();
90}
91
92// --- RawPointerData ---
93
94RawPointerData::RawPointerData() {
95 clear();
96}
97
98void RawPointerData::clear() {
99 pointerCount = 0;
100 clearIdBits();
101}
102
103void RawPointerData::copyFrom(const RawPointerData& other) {
104 pointerCount = other.pointerCount;
105 hoveringIdBits = other.hoveringIdBits;
106 touchingIdBits = other.touchingIdBits;
107
108 for (uint32_t i = 0; i < pointerCount; i++) {
109 pointers[i] = other.pointers[i];
110
111 int id = pointers[i].id;
112 idToIndex[id] = other.idToIndex[id];
113 }
114}
115
116void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const {
117 float x = 0, y = 0;
118 uint32_t count = touchingIdBits.count();
119 if (count) {
120 for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty();) {
121 uint32_t id = idBits.clearFirstMarkedBit();
122 const Pointer& pointer = pointerForId(id);
123 x += pointer.x;
124 y += pointer.y;
125 }
126 x /= count;
127 y /= count;
128 }
129 *outX = x;
130 *outY = y;
131}
132
133// --- CookedPointerData ---
134
135CookedPointerData::CookedPointerData() {
136 clear();
137}
138
139void CookedPointerData::clear() {
140 pointerCount = 0;
141 hoveringIdBits.clear();
142 touchingIdBits.clear();
143}
144
145void CookedPointerData::copyFrom(const CookedPointerData& other) {
146 pointerCount = other.pointerCount;
147 hoveringIdBits = other.hoveringIdBits;
148 touchingIdBits = other.touchingIdBits;
149
150 for (uint32_t i = 0; i < pointerCount; i++) {
151 pointerProperties[i].copyFrom(other.pointerProperties[i]);
152 pointerCoords[i].copyFrom(other.pointerCoords[i]);
153
154 int id = pointerProperties[i].id;
155 idToIndex[id] = other.idToIndex[id];
156 }
157}
158
159// --- TouchInputMapper ---
160
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800161TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext)
162 : InputMapper(deviceContext),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700163 mSource(0),
Michael Wright227c5542020-07-02 18:30:52 +0100164 mDeviceMode(DeviceMode::DISABLED),
Arthur Hung4197f6b2020-03-16 15:39:59 +0800165 mRawSurfaceWidth(-1),
166 mRawSurfaceHeight(-1),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700167 mSurfaceLeft(0),
168 mSurfaceTop(0),
169 mPhysicalWidth(-1),
170 mPhysicalHeight(-1),
171 mPhysicalLeft(0),
172 mPhysicalTop(0),
173 mSurfaceOrientation(DISPLAY_ORIENTATION_0) {}
174
175TouchInputMapper::~TouchInputMapper() {}
176
177uint32_t TouchInputMapper::getSources() {
178 return mSource;
179}
180
181void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
182 InputMapper::populateDeviceInfo(info);
183
Michael Wright227c5542020-07-02 18:30:52 +0100184 if (mDeviceMode != DeviceMode::DISABLED) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700185 info->addMotionRange(mOrientedRanges.x);
186 info->addMotionRange(mOrientedRanges.y);
187 info->addMotionRange(mOrientedRanges.pressure);
188
189 if (mOrientedRanges.haveSize) {
190 info->addMotionRange(mOrientedRanges.size);
191 }
192
193 if (mOrientedRanges.haveTouchSize) {
194 info->addMotionRange(mOrientedRanges.touchMajor);
195 info->addMotionRange(mOrientedRanges.touchMinor);
196 }
197
198 if (mOrientedRanges.haveToolSize) {
199 info->addMotionRange(mOrientedRanges.toolMajor);
200 info->addMotionRange(mOrientedRanges.toolMinor);
201 }
202
203 if (mOrientedRanges.haveOrientation) {
204 info->addMotionRange(mOrientedRanges.orientation);
205 }
206
207 if (mOrientedRanges.haveDistance) {
208 info->addMotionRange(mOrientedRanges.distance);
209 }
210
211 if (mOrientedRanges.haveTilt) {
212 info->addMotionRange(mOrientedRanges.tilt);
213 }
214
215 if (mCursorScrollAccumulator.haveRelativeVWheel()) {
216 info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
217 0.0f);
218 }
219 if (mCursorScrollAccumulator.haveRelativeHWheel()) {
220 info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
221 0.0f);
222 }
Michael Wright227c5542020-07-02 18:30:52 +0100223 if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700224 const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
225 const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
226 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
227 x.fuzz, x.resolution);
228 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat,
229 y.fuzz, y.resolution);
230 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat,
231 x.fuzz, x.resolution);
232 info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat,
233 y.fuzz, y.resolution);
234 }
235 info->setButtonUnderPad(mParameters.hasButtonUnderPad);
236 }
237}
238
239void TouchInputMapper::dump(std::string& dump) {
240 dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
241 dumpParameters(dump);
242 dumpVirtualKeys(dump);
243 dumpRawPointerAxes(dump);
244 dumpCalibration(dump);
245 dumpAffineTransformation(dump);
246 dumpSurface(dump);
247
248 dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
249 dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
250 dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
251 dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
252 dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
253 dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
254 dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
255 dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
256 dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
257 dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
258 dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
259 dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
260 dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
261 dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
262 dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
263 dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
264 dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
265
266 dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
267 dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n",
268 mLastRawState.rawPointerData.pointerCount);
269 for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
270 const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
271 dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
272 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
273 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
274 "toolType=%d, isHovering=%s\n",
275 i, pointer.id, pointer.x, pointer.y, pointer.pressure,
276 pointer.touchMajor, pointer.touchMinor, pointer.toolMajor,
277 pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY,
278 pointer.distance, pointer.toolType, toString(pointer.isHovering));
279 }
280
281 dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n",
282 mLastCookedState.buttonState);
283 dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
284 mLastCookedState.cookedPointerData.pointerCount);
285 for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
286 const PointerProperties& pointerProperties =
287 mLastCookedState.cookedPointerData.pointerProperties[i];
288 const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
289 dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
290 "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, "
291 "toolMinor=%0.3f, "
292 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
293 "toolType=%d, isHovering=%s\n",
294 i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(),
295 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
296 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
297 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
298 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
299 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
300 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
301 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT),
302 pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE),
303 pointerProperties.toolType,
304 toString(mLastCookedState.cookedPointerData.isHovering(i)));
305 }
306
307 dump += INDENT3 "Stylus Fusion:\n";
308 dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n",
309 toString(mExternalStylusConnected));
310 dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
311 dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
312 mExternalStylusFusionTimeout);
313 dump += INDENT3 "External Stylus State:\n";
314 dumpStylusState(dump, mExternalStylusState);
315
Michael Wright227c5542020-07-02 18:30:52 +0100316 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700317 dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n");
318 dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale);
319 dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale);
320 dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale);
321 dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale);
322 dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth);
323 }
324}
325
326const char* TouchInputMapper::modeToString(DeviceMode deviceMode) {
327 switch (deviceMode) {
Michael Wright227c5542020-07-02 18:30:52 +0100328 case DeviceMode::DISABLED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700329 return "disabled";
Michael Wright227c5542020-07-02 18:30:52 +0100330 case DeviceMode::DIRECT:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700331 return "direct";
Michael Wright227c5542020-07-02 18:30:52 +0100332 case DeviceMode::UNSCALED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700333 return "unscaled";
Michael Wright227c5542020-07-02 18:30:52 +0100334 case DeviceMode::NAVIGATION:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700335 return "navigation";
Michael Wright227c5542020-07-02 18:30:52 +0100336 case DeviceMode::POINTER:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700337 return "pointer";
338 }
339 return "unknown";
340}
341
342void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
343 uint32_t changes) {
344 InputMapper::configure(when, config, changes);
345
346 mConfig = *config;
347
348 if (!changes) { // first time only
349 // Configure basic parameters.
350 configureParameters();
351
352 // Configure common accumulators.
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800353 mCursorScrollAccumulator.configure(getDeviceContext());
354 mTouchButtonAccumulator.configure(getDeviceContext());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700355
356 // Configure absolute axis information.
357 configureRawPointerAxes();
358
359 // Prepare input device calibration.
360 parseCalibration();
361 resolveCalibration();
362 }
363
364 if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
365 // Update location calibration to reflect current settings
366 updateAffineTransformation();
367 }
368
369 if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
370 // Update pointer speed.
371 mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
372 mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
373 mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
374 }
375
376 bool resetNeeded = false;
377 if (!changes ||
378 (changes &
379 (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
380 InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
381 InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
382 InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {
383 // Configure device sources, surface dimensions, orientation and
384 // scaling factors.
385 configureSurface(when, &resetNeeded);
386 }
387
388 if (changes && resetNeeded) {
389 // Send reset, unless this is the first time the device has been configured,
390 // in which case the reader will call reset itself after all mappers are ready.
Garfield Tanc51d1ba2020-01-28 13:24:04 -0800391 NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800392 getListener()->notifyDeviceReset(&args);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700393 }
394}
395
396void TouchInputMapper::resolveExternalStylusPresence() {
397 std::vector<InputDeviceInfo> devices;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800398 getContext()->getExternalStylusDevices(devices);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700399 mExternalStylusConnected = !devices.empty();
400
401 if (!mExternalStylusConnected) {
402 resetExternalStylus();
403 }
404}
405
406void TouchInputMapper::configureParameters() {
407 // Use the pointer presentation mode for devices that do not support distinct
408 // multitouch. The spot-based presentation relies on being able to accurately
409 // locate two or more fingers on the touch pad.
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800410 mParameters.gestureMode = getDeviceContext().hasInputProperty(INPUT_PROP_SEMI_MT)
Michael Wright227c5542020-07-02 18:30:52 +0100411 ? Parameters::GestureMode::SINGLE_TOUCH
412 : Parameters::GestureMode::MULTI_TOUCH;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700413
414 String8 gestureModeString;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800415 if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"),
416 gestureModeString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700417 if (gestureModeString == "single-touch") {
Michael Wright227c5542020-07-02 18:30:52 +0100418 mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700419 } else if (gestureModeString == "multi-touch") {
Michael Wright227c5542020-07-02 18:30:52 +0100420 mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700421 } else if (gestureModeString != "default") {
422 ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
423 }
424 }
425
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800426 if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700427 // The device is a touch screen.
Michael Wright227c5542020-07-02 18:30:52 +0100428 mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800429 } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700430 // The device is a pointing device like a track pad.
Michael Wright227c5542020-07-02 18:30:52 +0100431 mParameters.deviceType = Parameters::DeviceType::POINTER;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800432 } else if (getDeviceContext().hasRelativeAxis(REL_X) ||
433 getDeviceContext().hasRelativeAxis(REL_Y)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700434 // The device is a cursor device with a touch pad attached.
435 // By default don't use the touch pad to move the pointer.
Michael Wright227c5542020-07-02 18:30:52 +0100436 mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700437 } else {
438 // The device is a touch pad of unknown purpose.
Michael Wright227c5542020-07-02 18:30:52 +0100439 mParameters.deviceType = Parameters::DeviceType::POINTER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700440 }
441
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800442 mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700443
444 String8 deviceTypeString;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800445 if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"),
446 deviceTypeString)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700447 if (deviceTypeString == "touchScreen") {
Michael Wright227c5542020-07-02 18:30:52 +0100448 mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700449 } else if (deviceTypeString == "touchPad") {
Michael Wright227c5542020-07-02 18:30:52 +0100450 mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700451 } else if (deviceTypeString == "touchNavigation") {
Michael Wright227c5542020-07-02 18:30:52 +0100452 mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700453 } else if (deviceTypeString == "pointer") {
Michael Wright227c5542020-07-02 18:30:52 +0100454 mParameters.deviceType = Parameters::DeviceType::POINTER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700455 } else if (deviceTypeString != "default") {
456 ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
457 }
458 }
459
Michael Wright227c5542020-07-02 18:30:52 +0100460 mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800461 getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
462 mParameters.orientationAware);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700463
464 mParameters.hasAssociatedDisplay = false;
465 mParameters.associatedDisplayIsExternal = false;
466 if (mParameters.orientationAware ||
Michael Wright227c5542020-07-02 18:30:52 +0100467 mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN ||
468 mParameters.deviceType == Parameters::DeviceType::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700469 mParameters.hasAssociatedDisplay = true;
Michael Wright227c5542020-07-02 18:30:52 +0100470 if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800471 mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700472 String8 uniqueDisplayId;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800473 getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"),
474 uniqueDisplayId);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700475 mParameters.uniqueDisplayId = uniqueDisplayId.c_str();
476 }
477 }
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800478 if (getDeviceContext().getAssociatedDisplayPort()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700479 mParameters.hasAssociatedDisplay = true;
480 }
481
482 // Initial downs on external touch devices should wake the device.
483 // Normally we don't do this for internal touch screens to prevent them from waking
484 // up in your pocket but you can enable it using the input device configuration.
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800485 mParameters.wake = getDeviceContext().isExternal();
486 getDeviceContext().getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700487}
488
489void TouchInputMapper::dumpParameters(std::string& dump) {
490 dump += INDENT3 "Parameters:\n";
491
492 switch (mParameters.gestureMode) {
Michael Wright227c5542020-07-02 18:30:52 +0100493 case Parameters::GestureMode::SINGLE_TOUCH:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700494 dump += INDENT4 "GestureMode: single-touch\n";
495 break;
Michael Wright227c5542020-07-02 18:30:52 +0100496 case Parameters::GestureMode::MULTI_TOUCH:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700497 dump += INDENT4 "GestureMode: multi-touch\n";
498 break;
499 default:
500 assert(false);
501 }
502
503 switch (mParameters.deviceType) {
Michael Wright227c5542020-07-02 18:30:52 +0100504 case Parameters::DeviceType::TOUCH_SCREEN:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700505 dump += INDENT4 "DeviceType: touchScreen\n";
506 break;
Michael Wright227c5542020-07-02 18:30:52 +0100507 case Parameters::DeviceType::TOUCH_PAD:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700508 dump += INDENT4 "DeviceType: touchPad\n";
509 break;
Michael Wright227c5542020-07-02 18:30:52 +0100510 case Parameters::DeviceType::TOUCH_NAVIGATION:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700511 dump += INDENT4 "DeviceType: touchNavigation\n";
512 break;
Michael Wright227c5542020-07-02 18:30:52 +0100513 case Parameters::DeviceType::POINTER:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700514 dump += INDENT4 "DeviceType: pointer\n";
515 break;
516 default:
517 ALOG_ASSERT(false);
518 }
519
520 dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, "
521 "displayId='%s'\n",
522 toString(mParameters.hasAssociatedDisplay),
523 toString(mParameters.associatedDisplayIsExternal),
524 mParameters.uniqueDisplayId.c_str());
525 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
526}
527
528void TouchInputMapper::configureRawPointerAxes() {
529 mRawPointerAxes.clear();
530}
531
532void TouchInputMapper::dumpRawPointerAxes(std::string& dump) {
533 dump += INDENT3 "Raw Touch Axes:\n";
534 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
535 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
536 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
537 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor");
538 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor");
539 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor");
540 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor");
541 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation");
542 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance");
543 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX");
544 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY");
545 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId");
546 dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot");
547}
548
549bool TouchInputMapper::hasExternalStylus() const {
550 return mExternalStylusConnected;
551}
552
553/**
554 * Determine which DisplayViewport to use.
555 * 1. If display port is specified, return the matching viewport. If matching viewport not
556 * found, then return.
Garfield Tan888a6a42020-01-09 11:39:16 -0800557 * 2. Always use the suggested viewport from WindowManagerService for pointers.
558 * 3. If a device has associated display, get the matching viewport by either unique id or by
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700559 * the display type (internal or external).
Garfield Tan888a6a42020-01-09 11:39:16 -0800560 * 4. Otherwise, use a non-display viewport.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700561 */
562std::optional<DisplayViewport> TouchInputMapper::findViewport() {
563 if (mParameters.hasAssociatedDisplay) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800564 const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700565 if (displayPort) {
566 // Find the viewport that contains the same port
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800567 return getDeviceContext().getAssociatedViewport();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700568 }
569
Michael Wright227c5542020-07-02 18:30:52 +0100570 if (mDeviceMode == DeviceMode::POINTER) {
Garfield Tan888a6a42020-01-09 11:39:16 -0800571 std::optional<DisplayViewport> viewport =
572 mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
573 if (viewport) {
574 return viewport;
575 } else {
576 ALOGW("Can't find designated display viewport with ID %" PRId32 " for pointers.",
577 mConfig.defaultPointerDisplayId);
578 }
579 }
580
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700581 // Check if uniqueDisplayId is specified in idc file.
582 if (!mParameters.uniqueDisplayId.empty()) {
583 return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId);
584 }
585
586 ViewportType viewportTypeToUse;
587 if (mParameters.associatedDisplayIsExternal) {
588 viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
589 } else {
590 viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
591 }
592
593 std::optional<DisplayViewport> viewport =
594 mConfig.getDisplayViewportByType(viewportTypeToUse);
595 if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) {
596 ALOGW("Input device %s should be associated with external display, "
597 "fallback to internal one for the external viewport is not found.",
598 getDeviceName().c_str());
599 viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
600 }
601
602 return viewport;
603 }
604
605 // No associated display, return a non-display viewport.
606 DisplayViewport newViewport;
607 // Raw width and height in the natural orientation.
608 int32_t rawWidth = mRawPointerAxes.getRawWidth();
609 int32_t rawHeight = mRawPointerAxes.getRawHeight();
610 newViewport.setNonDisplayViewport(rawWidth, rawHeight);
611 return std::make_optional(newViewport);
612}
613
614void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
Michael Wright227c5542020-07-02 18:30:52 +0100615 DeviceMode oldDeviceMode = mDeviceMode;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700616
617 resolveExternalStylusPresence();
618
619 // Determine device mode.
Michael Wright227c5542020-07-02 18:30:52 +0100620 if (mParameters.deviceType == Parameters::DeviceType::POINTER &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700621 mConfig.pointerGesturesEnabled) {
622 mSource = AINPUT_SOURCE_MOUSE;
Michael Wright227c5542020-07-02 18:30:52 +0100623 mDeviceMode = DeviceMode::POINTER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700624 if (hasStylus()) {
625 mSource |= AINPUT_SOURCE_STYLUS;
626 }
Michael Wright227c5542020-07-02 18:30:52 +0100627 } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700628 mParameters.hasAssociatedDisplay) {
629 mSource = AINPUT_SOURCE_TOUCHSCREEN;
Michael Wright227c5542020-07-02 18:30:52 +0100630 mDeviceMode = DeviceMode::DIRECT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700631 if (hasStylus()) {
632 mSource |= AINPUT_SOURCE_STYLUS;
633 }
634 if (hasExternalStylus()) {
635 mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
636 }
Michael Wright227c5542020-07-02 18:30:52 +0100637 } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700638 mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
Michael Wright227c5542020-07-02 18:30:52 +0100639 mDeviceMode = DeviceMode::NAVIGATION;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700640 } else {
641 mSource = AINPUT_SOURCE_TOUCHPAD;
Michael Wright227c5542020-07-02 18:30:52 +0100642 mDeviceMode = DeviceMode::UNSCALED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700643 }
644
645 // Ensure we have valid X and Y axes.
646 if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
647 ALOGW("Touch device '%s' did not report support for X or Y axis! "
648 "The device will be inoperable.",
649 getDeviceName().c_str());
Michael Wright227c5542020-07-02 18:30:52 +0100650 mDeviceMode = DeviceMode::DISABLED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700651 return;
652 }
653
654 // Get associated display dimensions.
655 std::optional<DisplayViewport> newViewport = findViewport();
656 if (!newViewport) {
657 ALOGI("Touch device '%s' could not query the properties of its associated "
658 "display. The device will be inoperable until the display size "
659 "becomes available.",
660 getDeviceName().c_str());
Michael Wright227c5542020-07-02 18:30:52 +0100661 mDeviceMode = DeviceMode::DISABLED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700662 return;
663 }
664
665 // Raw width and height in the natural orientation.
666 int32_t rawWidth = mRawPointerAxes.getRawWidth();
667 int32_t rawHeight = mRawPointerAxes.getRawHeight();
668
669 bool viewportChanged = mViewport != *newViewport;
670 if (viewportChanged) {
671 mViewport = *newViewport;
672
Michael Wright227c5542020-07-02 18:30:52 +0100673 if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700674 // Convert rotated viewport to natural surface coordinates.
675 int32_t naturalLogicalWidth, naturalLogicalHeight;
676 int32_t naturalPhysicalWidth, naturalPhysicalHeight;
677 int32_t naturalPhysicalLeft, naturalPhysicalTop;
678 int32_t naturalDeviceWidth, naturalDeviceHeight;
679 switch (mViewport.orientation) {
680 case DISPLAY_ORIENTATION_90:
681 naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
682 naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
683 naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
684 naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800685 naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700686 naturalPhysicalTop = mViewport.physicalLeft;
687 naturalDeviceWidth = mViewport.deviceHeight;
688 naturalDeviceHeight = mViewport.deviceWidth;
689 break;
690 case DISPLAY_ORIENTATION_180:
691 naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
692 naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
693 naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
694 naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
695 naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
696 naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom;
697 naturalDeviceWidth = mViewport.deviceWidth;
698 naturalDeviceHeight = mViewport.deviceHeight;
699 break;
700 case DISPLAY_ORIENTATION_270:
701 naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
702 naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
703 naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
704 naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
705 naturalPhysicalLeft = mViewport.physicalTop;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800706 naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700707 naturalDeviceWidth = mViewport.deviceHeight;
708 naturalDeviceHeight = mViewport.deviceWidth;
709 break;
710 case DISPLAY_ORIENTATION_0:
711 default:
712 naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
713 naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
714 naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
715 naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
716 naturalPhysicalLeft = mViewport.physicalLeft;
717 naturalPhysicalTop = mViewport.physicalTop;
718 naturalDeviceWidth = mViewport.deviceWidth;
719 naturalDeviceHeight = mViewport.deviceHeight;
720 break;
721 }
722
723 if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) {
724 ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str());
725 naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight;
726 naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth;
727 }
728
729 mPhysicalWidth = naturalPhysicalWidth;
730 mPhysicalHeight = naturalPhysicalHeight;
731 mPhysicalLeft = naturalPhysicalLeft;
732 mPhysicalTop = naturalPhysicalTop;
733
Arthur Hung4197f6b2020-03-16 15:39:59 +0800734 mRawSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
735 mRawSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700736 mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
737 mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800738 mSurfaceRight = mSurfaceLeft + naturalLogicalWidth;
739 mSurfaceBottom = mSurfaceTop + naturalLogicalHeight;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700740
741 mSurfaceOrientation =
742 mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0;
743 } else {
744 mPhysicalWidth = rawWidth;
745 mPhysicalHeight = rawHeight;
746 mPhysicalLeft = 0;
747 mPhysicalTop = 0;
748
Arthur Hung4197f6b2020-03-16 15:39:59 +0800749 mRawSurfaceWidth = rawWidth;
750 mRawSurfaceHeight = rawHeight;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700751 mSurfaceLeft = 0;
752 mSurfaceTop = 0;
753 mSurfaceOrientation = DISPLAY_ORIENTATION_0;
754 }
755 }
756
757 // If moving between pointer modes, need to reset some state.
758 bool deviceModeChanged = mDeviceMode != oldDeviceMode;
759 if (deviceModeChanged) {
760 mOrientedRanges.clear();
761 }
762
Prabir Pradhanc7ef27e2020-02-03 19:19:15 -0800763 // Create pointer controller if needed.
Michael Wright227c5542020-07-02 18:30:52 +0100764 if (mDeviceMode == DeviceMode::POINTER ||
765 (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches)) {
Prabir Pradhanc7ef27e2020-02-03 19:19:15 -0800766 if (mPointerController == nullptr) {
767 mPointerController = getContext()->getPointerController(getDeviceId());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700768 }
769 } else {
Michael Wright17db18e2020-06-26 20:51:44 +0100770 mPointerController.reset();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700771 }
772
773 if (viewportChanged || deviceModeChanged) {
774 ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
775 "display id %d",
Arthur Hung4197f6b2020-03-16 15:39:59 +0800776 getDeviceId(), getDeviceName().c_str(), mRawSurfaceWidth, mRawSurfaceHeight,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700777 mSurfaceOrientation, mDeviceMode, mViewport.displayId);
778
779 // Configure X and Y factors.
Arthur Hung4197f6b2020-03-16 15:39:59 +0800780 mXScale = float(mRawSurfaceWidth) / rawWidth;
781 mYScale = float(mRawSurfaceHeight) / rawHeight;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700782 mXTranslate = -mSurfaceLeft;
783 mYTranslate = -mSurfaceTop;
784 mXPrecision = 1.0f / mXScale;
785 mYPrecision = 1.0f / mYScale;
786
787 mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
788 mOrientedRanges.x.source = mSource;
789 mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
790 mOrientedRanges.y.source = mSource;
791
792 configureVirtualKeys();
793
794 // Scale factor for terms that are not oriented in a particular axis.
795 // If the pixels are square then xScale == yScale otherwise we fake it
796 // by choosing an average.
797 mGeometricScale = avg(mXScale, mYScale);
798
799 // Size of diagonal axis.
Arthur Hung4197f6b2020-03-16 15:39:59 +0800800 float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700801
802 // Size factors.
Michael Wright227c5542020-07-02 18:30:52 +0100803 if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700804 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {
805 mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
806 } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
807 mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
808 } else {
809 mSizeScale = 0.0f;
810 }
811
812 mOrientedRanges.haveTouchSize = true;
813 mOrientedRanges.haveToolSize = true;
814 mOrientedRanges.haveSize = true;
815
816 mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
817 mOrientedRanges.touchMajor.source = mSource;
818 mOrientedRanges.touchMajor.min = 0;
819 mOrientedRanges.touchMajor.max = diagonalSize;
820 mOrientedRanges.touchMajor.flat = 0;
821 mOrientedRanges.touchMajor.fuzz = 0;
822 mOrientedRanges.touchMajor.resolution = 0;
823
824 mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
825 mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
826
827 mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
828 mOrientedRanges.toolMajor.source = mSource;
829 mOrientedRanges.toolMajor.min = 0;
830 mOrientedRanges.toolMajor.max = diagonalSize;
831 mOrientedRanges.toolMajor.flat = 0;
832 mOrientedRanges.toolMajor.fuzz = 0;
833 mOrientedRanges.toolMajor.resolution = 0;
834
835 mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
836 mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
837
838 mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
839 mOrientedRanges.size.source = mSource;
840 mOrientedRanges.size.min = 0;
841 mOrientedRanges.size.max = 1.0;
842 mOrientedRanges.size.flat = 0;
843 mOrientedRanges.size.fuzz = 0;
844 mOrientedRanges.size.resolution = 0;
845 } else {
846 mSizeScale = 0.0f;
847 }
848
849 // Pressure factors.
850 mPressureScale = 0;
851 float pressureMax = 1.0;
Michael Wright227c5542020-07-02 18:30:52 +0100852 if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
853 mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700854 if (mCalibration.havePressureScale) {
855 mPressureScale = mCalibration.pressureScale;
856 pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
857 } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) {
858 mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
859 }
860 }
861
862 mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
863 mOrientedRanges.pressure.source = mSource;
864 mOrientedRanges.pressure.min = 0;
865 mOrientedRanges.pressure.max = pressureMax;
866 mOrientedRanges.pressure.flat = 0;
867 mOrientedRanges.pressure.fuzz = 0;
868 mOrientedRanges.pressure.resolution = 0;
869
870 // Tilt
871 mTiltXCenter = 0;
872 mTiltXScale = 0;
873 mTiltYCenter = 0;
874 mTiltYScale = 0;
875 mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
876 if (mHaveTilt) {
877 mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue);
878 mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue);
879 mTiltXScale = M_PI / 180;
880 mTiltYScale = M_PI / 180;
881
882 mOrientedRanges.haveTilt = true;
883
884 mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
885 mOrientedRanges.tilt.source = mSource;
886 mOrientedRanges.tilt.min = 0;
887 mOrientedRanges.tilt.max = M_PI_2;
888 mOrientedRanges.tilt.flat = 0;
889 mOrientedRanges.tilt.fuzz = 0;
890 mOrientedRanges.tilt.resolution = 0;
891 }
892
893 // Orientation
894 mOrientationScale = 0;
895 if (mHaveTilt) {
896 mOrientedRanges.haveOrientation = true;
897
898 mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
899 mOrientedRanges.orientation.source = mSource;
900 mOrientedRanges.orientation.min = -M_PI;
901 mOrientedRanges.orientation.max = M_PI;
902 mOrientedRanges.orientation.flat = 0;
903 mOrientedRanges.orientation.fuzz = 0;
904 mOrientedRanges.orientation.resolution = 0;
905 } else if (mCalibration.orientationCalibration !=
Michael Wright227c5542020-07-02 18:30:52 +0100906 Calibration::OrientationCalibration::NONE) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700907 if (mCalibration.orientationCalibration ==
Michael Wright227c5542020-07-02 18:30:52 +0100908 Calibration::OrientationCalibration::INTERPOLATED) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700909 if (mRawPointerAxes.orientation.valid) {
910 if (mRawPointerAxes.orientation.maxValue > 0) {
911 mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
912 } else if (mRawPointerAxes.orientation.minValue < 0) {
913 mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
914 } else {
915 mOrientationScale = 0;
916 }
917 }
918 }
919
920 mOrientedRanges.haveOrientation = true;
921
922 mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
923 mOrientedRanges.orientation.source = mSource;
924 mOrientedRanges.orientation.min = -M_PI_2;
925 mOrientedRanges.orientation.max = M_PI_2;
926 mOrientedRanges.orientation.flat = 0;
927 mOrientedRanges.orientation.fuzz = 0;
928 mOrientedRanges.orientation.resolution = 0;
929 }
930
931 // Distance
932 mDistanceScale = 0;
Michael Wright227c5542020-07-02 18:30:52 +0100933 if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
934 if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700935 if (mCalibration.haveDistanceScale) {
936 mDistanceScale = mCalibration.distanceScale;
937 } else {
938 mDistanceScale = 1.0f;
939 }
940 }
941
942 mOrientedRanges.haveDistance = true;
943
944 mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
945 mOrientedRanges.distance.source = mSource;
946 mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale;
947 mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale;
948 mOrientedRanges.distance.flat = 0;
949 mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale;
950 mOrientedRanges.distance.resolution = 0;
951 }
952
953 // Compute oriented precision, scales and ranges.
954 // Note that the maximum value reported is an inclusive maximum value so it is one
955 // unit less than the total width or height of surface.
956 switch (mSurfaceOrientation) {
957 case DISPLAY_ORIENTATION_90:
958 case DISPLAY_ORIENTATION_270:
959 mOrientedXPrecision = mYPrecision;
960 mOrientedYPrecision = mXPrecision;
961
962 mOrientedRanges.x.min = mYTranslate;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800963 mOrientedRanges.x.max = mRawSurfaceHeight + mYTranslate - 1;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700964 mOrientedRanges.x.flat = 0;
965 mOrientedRanges.x.fuzz = 0;
966 mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;
967
968 mOrientedRanges.y.min = mXTranslate;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800969 mOrientedRanges.y.max = mRawSurfaceWidth + mXTranslate - 1;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700970 mOrientedRanges.y.flat = 0;
971 mOrientedRanges.y.fuzz = 0;
972 mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
973 break;
974
975 default:
976 mOrientedXPrecision = mXPrecision;
977 mOrientedYPrecision = mYPrecision;
978
979 mOrientedRanges.x.min = mXTranslate;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800980 mOrientedRanges.x.max = mRawSurfaceWidth + mXTranslate - 1;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700981 mOrientedRanges.x.flat = 0;
982 mOrientedRanges.x.fuzz = 0;
983 mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;
984
985 mOrientedRanges.y.min = mYTranslate;
Arthur Hung4197f6b2020-03-16 15:39:59 +0800986 mOrientedRanges.y.max = mRawSurfaceHeight + mYTranslate - 1;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700987 mOrientedRanges.y.flat = 0;
988 mOrientedRanges.y.fuzz = 0;
989 mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
990 break;
991 }
992
993 // Location
994 updateAffineTransformation();
995
Michael Wright227c5542020-07-02 18:30:52 +0100996 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700997 // Compute pointer gesture detection parameters.
998 float rawDiagonal = hypotf(rawWidth, rawHeight);
Arthur Hung4197f6b2020-03-16 15:39:59 +0800999 float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001000
1001 // Scale movements such that one whole swipe of the touch pad covers a
1002 // given area relative to the diagonal size of the display when no acceleration
1003 // is applied.
1004 // Assume that the touch pad has a square aspect ratio such that movements in
1005 // X and Y of the same number of raw units cover the same physical distance.
1006 mPointerXMovementScale =
1007 mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal;
1008 mPointerYMovementScale = mPointerXMovementScale;
1009
1010 // Scale zooms to cover a smaller range of the display than movements do.
1011 // This value determines the area around the pointer that is affected by freeform
1012 // pointer gestures.
1013 mPointerXZoomScale =
1014 mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal;
1015 mPointerYZoomScale = mPointerXZoomScale;
1016
1017 // Max width between pointers to detect a swipe gesture is more than some fraction
1018 // of the diagonal axis of the touch pad. Touches that are wider than this are
1019 // translated into freeform gestures.
1020 mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;
1021
1022 // Abort current pointer usages because the state has changed.
1023 abortPointerUsage(when, 0 /*policyFlags*/);
1024 }
1025
1026 // Inform the dispatcher about the changes.
1027 *outResetNeeded = true;
1028 bumpGeneration();
1029 }
1030}
1031
1032void TouchInputMapper::dumpSurface(std::string& dump) {
1033 dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
Arthur Hung4197f6b2020-03-16 15:39:59 +08001034 dump += StringPrintf(INDENT3 "RawSurfaceWidth: %dpx\n", mRawSurfaceWidth);
1035 dump += StringPrintf(INDENT3 "RawSurfaceHeight: %dpx\n", mRawSurfaceHeight);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001036 dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
1037 dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
Arthur Hung4197f6b2020-03-16 15:39:59 +08001038 dump += StringPrintf(INDENT3 "SurfaceRight: %d\n", mSurfaceRight);
1039 dump += StringPrintf(INDENT3 "SurfaceBottom: %d\n", mSurfaceBottom);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001040 dump += StringPrintf(INDENT3 "PhysicalWidth: %dpx\n", mPhysicalWidth);
1041 dump += StringPrintf(INDENT3 "PhysicalHeight: %dpx\n", mPhysicalHeight);
1042 dump += StringPrintf(INDENT3 "PhysicalLeft: %d\n", mPhysicalLeft);
1043 dump += StringPrintf(INDENT3 "PhysicalTop: %d\n", mPhysicalTop);
1044 dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
1045}
1046
1047void TouchInputMapper::configureVirtualKeys() {
1048 std::vector<VirtualKeyDefinition> virtualKeyDefinitions;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001049 getDeviceContext().getVirtualKeyDefinitions(virtualKeyDefinitions);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001050
1051 mVirtualKeys.clear();
1052
1053 if (virtualKeyDefinitions.size() == 0) {
1054 return;
1055 }
1056
1057 int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
1058 int32_t touchScreenTop = mRawPointerAxes.y.minValue;
1059 int32_t touchScreenWidth = mRawPointerAxes.getRawWidth();
1060 int32_t touchScreenHeight = mRawPointerAxes.getRawHeight();
1061
1062 for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) {
1063 VirtualKey virtualKey;
1064
1065 virtualKey.scanCode = virtualKeyDefinition.scanCode;
1066 int32_t keyCode;
1067 int32_t dummyKeyMetaState;
1068 uint32_t flags;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001069 if (getDeviceContext().mapKey(virtualKey.scanCode, 0, 0, &keyCode, &dummyKeyMetaState,
1070 &flags)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001071 ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
1072 continue; // drop the key
1073 }
1074
1075 virtualKey.keyCode = keyCode;
1076 virtualKey.flags = flags;
1077
1078 // convert the key definition's display coordinates into touch coordinates for a hit box
1079 int32_t halfWidth = virtualKeyDefinition.width / 2;
1080 int32_t halfHeight = virtualKeyDefinition.height / 2;
1081
1082 virtualKey.hitLeft =
Arthur Hung4197f6b2020-03-16 15:39:59 +08001083 (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mRawSurfaceWidth +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001084 touchScreenLeft;
1085 virtualKey.hitRight =
Arthur Hung4197f6b2020-03-16 15:39:59 +08001086 (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mRawSurfaceWidth +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001087 touchScreenLeft;
Arthur Hung4197f6b2020-03-16 15:39:59 +08001088 virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight /
1089 mRawSurfaceHeight +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001090 touchScreenTop;
Arthur Hung4197f6b2020-03-16 15:39:59 +08001091 virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight /
1092 mRawSurfaceHeight +
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001093 touchScreenTop;
1094 mVirtualKeys.push_back(virtualKey);
1095 }
1096}
1097
1098void TouchInputMapper::dumpVirtualKeys(std::string& dump) {
1099 if (!mVirtualKeys.empty()) {
1100 dump += INDENT3 "Virtual Keys:\n";
1101
1102 for (size_t i = 0; i < mVirtualKeys.size(); i++) {
1103 const VirtualKey& virtualKey = mVirtualKeys[i];
1104 dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
1105 "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
1106 i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft,
1107 virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
1108 }
1109 }
1110}
1111
1112void TouchInputMapper::parseCalibration() {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001113 const PropertyMap& in = getDeviceContext().getConfiguration();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001114 Calibration& out = mCalibration;
1115
1116 // Size
Michael Wright227c5542020-07-02 18:30:52 +01001117 out.sizeCalibration = Calibration::SizeCalibration::DEFAULT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001118 String8 sizeCalibrationString;
1119 if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
1120 if (sizeCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001121 out.sizeCalibration = Calibration::SizeCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001122 } else if (sizeCalibrationString == "geometric") {
Michael Wright227c5542020-07-02 18:30:52 +01001123 out.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001124 } else if (sizeCalibrationString == "diameter") {
Michael Wright227c5542020-07-02 18:30:52 +01001125 out.sizeCalibration = Calibration::SizeCalibration::DIAMETER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001126 } else if (sizeCalibrationString == "box") {
Michael Wright227c5542020-07-02 18:30:52 +01001127 out.sizeCalibration = Calibration::SizeCalibration::BOX;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001128 } else if (sizeCalibrationString == "area") {
Michael Wright227c5542020-07-02 18:30:52 +01001129 out.sizeCalibration = Calibration::SizeCalibration::AREA;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001130 } else if (sizeCalibrationString != "default") {
1131 ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string());
1132 }
1133 }
1134
1135 out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale);
1136 out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias);
1137 out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed);
1138
1139 // Pressure
Michael Wright227c5542020-07-02 18:30:52 +01001140 out.pressureCalibration = Calibration::PressureCalibration::DEFAULT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001141 String8 pressureCalibrationString;
1142 if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
1143 if (pressureCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001144 out.pressureCalibration = Calibration::PressureCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001145 } else if (pressureCalibrationString == "physical") {
Michael Wright227c5542020-07-02 18:30:52 +01001146 out.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001147 } else if (pressureCalibrationString == "amplitude") {
Michael Wright227c5542020-07-02 18:30:52 +01001148 out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001149 } else if (pressureCalibrationString != "default") {
1150 ALOGW("Invalid value for touch.pressure.calibration: '%s'",
1151 pressureCalibrationString.string());
1152 }
1153 }
1154
1155 out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale);
1156
1157 // Orientation
Michael Wright227c5542020-07-02 18:30:52 +01001158 out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001159 String8 orientationCalibrationString;
1160 if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
1161 if (orientationCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001162 out.orientationCalibration = Calibration::OrientationCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001163 } else if (orientationCalibrationString == "interpolated") {
Michael Wright227c5542020-07-02 18:30:52 +01001164 out.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001165 } else if (orientationCalibrationString == "vector") {
Michael Wright227c5542020-07-02 18:30:52 +01001166 out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001167 } else if (orientationCalibrationString != "default") {
1168 ALOGW("Invalid value for touch.orientation.calibration: '%s'",
1169 orientationCalibrationString.string());
1170 }
1171 }
1172
1173 // Distance
Michael Wright227c5542020-07-02 18:30:52 +01001174 out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001175 String8 distanceCalibrationString;
1176 if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
1177 if (distanceCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001178 out.distanceCalibration = Calibration::DistanceCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001179 } else if (distanceCalibrationString == "scaled") {
Michael Wright227c5542020-07-02 18:30:52 +01001180 out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001181 } else if (distanceCalibrationString != "default") {
1182 ALOGW("Invalid value for touch.distance.calibration: '%s'",
1183 distanceCalibrationString.string());
1184 }
1185 }
1186
1187 out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale);
1188
Michael Wright227c5542020-07-02 18:30:52 +01001189 out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001190 String8 coverageCalibrationString;
1191 if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
1192 if (coverageCalibrationString == "none") {
Michael Wright227c5542020-07-02 18:30:52 +01001193 out.coverageCalibration = Calibration::CoverageCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001194 } else if (coverageCalibrationString == "box") {
Michael Wright227c5542020-07-02 18:30:52 +01001195 out.coverageCalibration = Calibration::CoverageCalibration::BOX;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001196 } else if (coverageCalibrationString != "default") {
1197 ALOGW("Invalid value for touch.coverage.calibration: '%s'",
1198 coverageCalibrationString.string());
1199 }
1200 }
1201}
1202
1203void TouchInputMapper::resolveCalibration() {
1204 // Size
1205 if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001206 if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DEFAULT) {
1207 mCalibration.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001208 }
1209 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001210 mCalibration.sizeCalibration = Calibration::SizeCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001211 }
1212
1213 // Pressure
1214 if (mRawPointerAxes.pressure.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001215 if (mCalibration.pressureCalibration == Calibration::PressureCalibration::DEFAULT) {
1216 mCalibration.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001217 }
1218 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001219 mCalibration.pressureCalibration = Calibration::PressureCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001220 }
1221
1222 // Orientation
1223 if (mRawPointerAxes.orientation.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001224 if (mCalibration.orientationCalibration == Calibration::OrientationCalibration::DEFAULT) {
1225 mCalibration.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001226 }
1227 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001228 mCalibration.orientationCalibration = Calibration::OrientationCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001229 }
1230
1231 // Distance
1232 if (mRawPointerAxes.distance.valid) {
Michael Wright227c5542020-07-02 18:30:52 +01001233 if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::DEFAULT) {
1234 mCalibration.distanceCalibration = Calibration::DistanceCalibration::SCALED;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001235 }
1236 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001237 mCalibration.distanceCalibration = Calibration::DistanceCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001238 }
1239
1240 // Coverage
Michael Wright227c5542020-07-02 18:30:52 +01001241 if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::DEFAULT) {
1242 mCalibration.coverageCalibration = Calibration::CoverageCalibration::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001243 }
1244}
1245
1246void TouchInputMapper::dumpCalibration(std::string& dump) {
1247 dump += INDENT3 "Calibration:\n";
1248
1249 // Size
1250 switch (mCalibration.sizeCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001251 case Calibration::SizeCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001252 dump += INDENT4 "touch.size.calibration: none\n";
1253 break;
Michael Wright227c5542020-07-02 18:30:52 +01001254 case Calibration::SizeCalibration::GEOMETRIC:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001255 dump += INDENT4 "touch.size.calibration: geometric\n";
1256 break;
Michael Wright227c5542020-07-02 18:30:52 +01001257 case Calibration::SizeCalibration::DIAMETER:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001258 dump += INDENT4 "touch.size.calibration: diameter\n";
1259 break;
Michael Wright227c5542020-07-02 18:30:52 +01001260 case Calibration::SizeCalibration::BOX:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001261 dump += INDENT4 "touch.size.calibration: box\n";
1262 break;
Michael Wright227c5542020-07-02 18:30:52 +01001263 case Calibration::SizeCalibration::AREA:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001264 dump += INDENT4 "touch.size.calibration: area\n";
1265 break;
1266 default:
1267 ALOG_ASSERT(false);
1268 }
1269
1270 if (mCalibration.haveSizeScale) {
1271 dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale);
1272 }
1273
1274 if (mCalibration.haveSizeBias) {
1275 dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias);
1276 }
1277
1278 if (mCalibration.haveSizeIsSummed) {
1279 dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n",
1280 toString(mCalibration.sizeIsSummed));
1281 }
1282
1283 // Pressure
1284 switch (mCalibration.pressureCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001285 case Calibration::PressureCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001286 dump += INDENT4 "touch.pressure.calibration: none\n";
1287 break;
Michael Wright227c5542020-07-02 18:30:52 +01001288 case Calibration::PressureCalibration::PHYSICAL:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001289 dump += INDENT4 "touch.pressure.calibration: physical\n";
1290 break;
Michael Wright227c5542020-07-02 18:30:52 +01001291 case Calibration::PressureCalibration::AMPLITUDE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001292 dump += INDENT4 "touch.pressure.calibration: amplitude\n";
1293 break;
1294 default:
1295 ALOG_ASSERT(false);
1296 }
1297
1298 if (mCalibration.havePressureScale) {
1299 dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale);
1300 }
1301
1302 // Orientation
1303 switch (mCalibration.orientationCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001304 case Calibration::OrientationCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001305 dump += INDENT4 "touch.orientation.calibration: none\n";
1306 break;
Michael Wright227c5542020-07-02 18:30:52 +01001307 case Calibration::OrientationCalibration::INTERPOLATED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001308 dump += INDENT4 "touch.orientation.calibration: interpolated\n";
1309 break;
Michael Wright227c5542020-07-02 18:30:52 +01001310 case Calibration::OrientationCalibration::VECTOR:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001311 dump += INDENT4 "touch.orientation.calibration: vector\n";
1312 break;
1313 default:
1314 ALOG_ASSERT(false);
1315 }
1316
1317 // Distance
1318 switch (mCalibration.distanceCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001319 case Calibration::DistanceCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001320 dump += INDENT4 "touch.distance.calibration: none\n";
1321 break;
Michael Wright227c5542020-07-02 18:30:52 +01001322 case Calibration::DistanceCalibration::SCALED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001323 dump += INDENT4 "touch.distance.calibration: scaled\n";
1324 break;
1325 default:
1326 ALOG_ASSERT(false);
1327 }
1328
1329 if (mCalibration.haveDistanceScale) {
1330 dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale);
1331 }
1332
1333 switch (mCalibration.coverageCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01001334 case Calibration::CoverageCalibration::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001335 dump += INDENT4 "touch.coverage.calibration: none\n";
1336 break;
Michael Wright227c5542020-07-02 18:30:52 +01001337 case Calibration::CoverageCalibration::BOX:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001338 dump += INDENT4 "touch.coverage.calibration: box\n";
1339 break;
1340 default:
1341 ALOG_ASSERT(false);
1342 }
1343}
1344
1345void TouchInputMapper::dumpAffineTransformation(std::string& dump) {
1346 dump += INDENT3 "Affine Transformation:\n";
1347
1348 dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
1349 dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
1350 dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
1351 dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
1352 dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
1353 dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
1354}
1355
1356void TouchInputMapper::updateAffineTransformation() {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001357 mAffineTransform = getPolicy()->getTouchAffineTransformation(getDeviceContext().getDescriptor(),
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001358 mSurfaceOrientation);
1359}
1360
1361void TouchInputMapper::reset(nsecs_t when) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001362 mCursorButtonAccumulator.reset(getDeviceContext());
1363 mCursorScrollAccumulator.reset(getDeviceContext());
1364 mTouchButtonAccumulator.reset(getDeviceContext());
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001365
1366 mPointerVelocityControl.reset();
1367 mWheelXVelocityControl.reset();
1368 mWheelYVelocityControl.reset();
1369
1370 mRawStatesPending.clear();
1371 mCurrentRawState.clear();
1372 mCurrentCookedState.clear();
1373 mLastRawState.clear();
1374 mLastCookedState.clear();
Michael Wright227c5542020-07-02 18:30:52 +01001375 mPointerUsage = PointerUsage::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001376 mSentHoverEnter = false;
1377 mHavePointerIds = false;
1378 mCurrentMotionAborted = false;
1379 mDownTime = 0;
1380
1381 mCurrentVirtualKey.down = false;
1382
1383 mPointerGesture.reset();
1384 mPointerSimple.reset();
1385 resetExternalStylus();
1386
1387 if (mPointerController != nullptr) {
Michael Wrightca5bede2020-07-02 00:00:29 +01001388 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001389 mPointerController->clearSpots();
1390 }
1391
1392 InputMapper::reset(when);
1393}
1394
1395void TouchInputMapper::resetExternalStylus() {
1396 mExternalStylusState.clear();
1397 mExternalStylusId = -1;
1398 mExternalStylusFusionTimeout = LLONG_MAX;
1399 mExternalStylusDataPending = false;
1400}
1401
1402void TouchInputMapper::clearStylusDataPendingFlags() {
1403 mExternalStylusDataPending = false;
1404 mExternalStylusFusionTimeout = LLONG_MAX;
1405}
1406
1407void TouchInputMapper::process(const RawEvent* rawEvent) {
1408 mCursorButtonAccumulator.process(rawEvent);
1409 mCursorScrollAccumulator.process(rawEvent);
1410 mTouchButtonAccumulator.process(rawEvent);
1411
1412 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
1413 sync(rawEvent->when);
1414 }
1415}
1416
1417void TouchInputMapper::sync(nsecs_t when) {
1418 const RawState* last =
1419 mRawStatesPending.empty() ? &mCurrentRawState : &mRawStatesPending.back();
1420
1421 // Push a new state.
1422 mRawStatesPending.emplace_back();
1423
1424 RawState* next = &mRawStatesPending.back();
1425 next->clear();
1426 next->when = when;
1427
1428 // Sync button state.
1429 next->buttonState =
1430 mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState();
1431
1432 // Sync scroll
1433 next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel();
1434 next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel();
1435 mCursorScrollAccumulator.finishSync();
1436
1437 // Sync touch
1438 syncTouch(when, next);
1439
1440 // Assign pointer ids.
1441 if (!mHavePointerIds) {
1442 assignPointerIds(last, next);
1443 }
1444
1445#if DEBUG_RAW_EVENTS
1446 ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, "
1447 "hovering ids 0x%08x -> 0x%08x",
1448 last->rawPointerData.pointerCount, next->rawPointerData.pointerCount,
1449 last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value,
1450 last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value);
1451#endif
1452
1453 processRawTouches(false /*timeout*/);
1454}
1455
1456void TouchInputMapper::processRawTouches(bool timeout) {
Michael Wright227c5542020-07-02 18:30:52 +01001457 if (mDeviceMode == DeviceMode::DISABLED) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001458 // Drop all input if the device is disabled.
1459 mCurrentRawState.clear();
1460 mRawStatesPending.clear();
1461 return;
1462 }
1463
1464 // Drain any pending touch states. The invariant here is that the mCurrentRawState is always
1465 // valid and must go through the full cook and dispatch cycle. This ensures that anything
1466 // touching the current state will only observe the events that have been dispatched to the
1467 // rest of the pipeline.
1468 const size_t N = mRawStatesPending.size();
1469 size_t count;
1470 for (count = 0; count < N; count++) {
1471 const RawState& next = mRawStatesPending[count];
1472
1473 // A failure to assign the stylus id means that we're waiting on stylus data
1474 // and so should defer the rest of the pipeline.
1475 if (assignExternalStylusId(next, timeout)) {
1476 break;
1477 }
1478
1479 // All ready to go.
1480 clearStylusDataPendingFlags();
1481 mCurrentRawState.copyFrom(next);
1482 if (mCurrentRawState.when < mLastRawState.when) {
1483 mCurrentRawState.when = mLastRawState.when;
1484 }
1485 cookAndDispatch(mCurrentRawState.when);
1486 }
1487 if (count != 0) {
1488 mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
1489 }
1490
1491 if (mExternalStylusDataPending) {
1492 if (timeout) {
1493 nsecs_t when = mExternalStylusFusionTimeout - STYLUS_DATA_LATENCY;
1494 clearStylusDataPendingFlags();
1495 mCurrentRawState.copyFrom(mLastRawState);
1496#if DEBUG_STYLUS_FUSION
1497 ALOGD("Timeout expired, synthesizing event with new stylus data");
1498#endif
1499 cookAndDispatch(when);
1500 } else if (mExternalStylusFusionTimeout == LLONG_MAX) {
1501 mExternalStylusFusionTimeout = mExternalStylusState.when + TOUCH_DATA_TIMEOUT;
1502 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
1503 }
1504 }
1505}
1506
1507void TouchInputMapper::cookAndDispatch(nsecs_t when) {
1508 // Always start with a clean state.
1509 mCurrentCookedState.clear();
1510
1511 // Apply stylus buttons to current raw state.
1512 applyExternalStylusButtonState(when);
1513
1514 // Handle policy on initial down or hover events.
1515 bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&
1516 mCurrentRawState.rawPointerData.pointerCount != 0;
1517
1518 uint32_t policyFlags = 0;
1519 bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
1520 if (initialDown || buttonsPressed) {
1521 // If this is a touch screen, hide the pointer on an initial down.
Michael Wright227c5542020-07-02 18:30:52 +01001522 if (mDeviceMode == DeviceMode::DIRECT) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001523 getContext()->fadePointer();
1524 }
1525
1526 if (mParameters.wake) {
1527 policyFlags |= POLICY_FLAG_WAKE;
1528 }
1529 }
1530
1531 // Consume raw off-screen touches before cooking pointer data.
1532 // If touches are consumed, subsequent code will not receive any pointer data.
1533 if (consumeRawTouches(when, policyFlags)) {
1534 mCurrentRawState.rawPointerData.clear();
1535 }
1536
1537 // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure
1538 // with cooked pointer data that has the same ids and indices as the raw data.
1539 // The following code can use either the raw or cooked data, as needed.
1540 cookPointerData();
1541
1542 // Apply stylus pressure to current cooked state.
1543 applyExternalStylusTouchState(when);
1544
1545 // Synthesize key down from raw buttons if needed.
1546 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
1547 mViewport.displayId, policyFlags, mLastCookedState.buttonState,
1548 mCurrentCookedState.buttonState);
1549
1550 // Dispatch the touches either directly or by translation through a pointer on screen.
Michael Wright227c5542020-07-02 18:30:52 +01001551 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001552 for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) {
1553 uint32_t id = idBits.clearFirstMarkedBit();
1554 const RawPointerData::Pointer& pointer =
1555 mCurrentRawState.rawPointerData.pointerForId(id);
1556 if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
1557 pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
1558 mCurrentCookedState.stylusIdBits.markBit(id);
1559 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER ||
1560 pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
1561 mCurrentCookedState.fingerIdBits.markBit(id);
1562 } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
1563 mCurrentCookedState.mouseIdBits.markBit(id);
1564 }
1565 }
1566 for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); !idBits.isEmpty();) {
1567 uint32_t id = idBits.clearFirstMarkedBit();
1568 const RawPointerData::Pointer& pointer =
1569 mCurrentRawState.rawPointerData.pointerForId(id);
1570 if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS ||
1571 pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
1572 mCurrentCookedState.stylusIdBits.markBit(id);
1573 }
1574 }
1575
1576 // Stylus takes precedence over all tools, then mouse, then finger.
1577 PointerUsage pointerUsage = mPointerUsage;
1578 if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
1579 mCurrentCookedState.mouseIdBits.clear();
1580 mCurrentCookedState.fingerIdBits.clear();
Michael Wright227c5542020-07-02 18:30:52 +01001581 pointerUsage = PointerUsage::STYLUS;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001582 } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
1583 mCurrentCookedState.fingerIdBits.clear();
Michael Wright227c5542020-07-02 18:30:52 +01001584 pointerUsage = PointerUsage::MOUSE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001585 } else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
1586 isPointerDown(mCurrentRawState.buttonState)) {
Michael Wright227c5542020-07-02 18:30:52 +01001587 pointerUsage = PointerUsage::GESTURES;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001588 }
1589
1590 dispatchPointerUsage(when, policyFlags, pointerUsage);
1591 } else {
Michael Wright227c5542020-07-02 18:30:52 +01001592 if (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001593 mPointerController != nullptr) {
Michael Wrightca5bede2020-07-02 00:00:29 +01001594 mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
1595 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001596
1597 mPointerController->setButtonState(mCurrentRawState.buttonState);
1598 mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
1599 mCurrentCookedState.cookedPointerData.idToIndex,
1600 mCurrentCookedState.cookedPointerData.touchingIdBits,
1601 mViewport.displayId);
1602 }
1603
1604 if (!mCurrentMotionAborted) {
1605 dispatchButtonRelease(when, policyFlags);
1606 dispatchHoverExit(when, policyFlags);
1607 dispatchTouches(when, policyFlags);
1608 dispatchHoverEnterAndMove(when, policyFlags);
1609 dispatchButtonPress(when, policyFlags);
1610 }
1611
1612 if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
1613 mCurrentMotionAborted = false;
1614 }
1615 }
1616
1617 // Synthesize key up from raw buttons if needed.
1618 synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
1619 mViewport.displayId, policyFlags, mLastCookedState.buttonState,
1620 mCurrentCookedState.buttonState);
1621
1622 // Clear some transient state.
1623 mCurrentRawState.rawVScroll = 0;
1624 mCurrentRawState.rawHScroll = 0;
1625
1626 // Copy current touch to last touch in preparation for the next cycle.
1627 mLastRawState.copyFrom(mCurrentRawState);
1628 mLastCookedState.copyFrom(mCurrentCookedState);
1629}
1630
1631void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
Michael Wright227c5542020-07-02 18:30:52 +01001632 if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001633 mCurrentRawState.buttonState |= mExternalStylusState.buttons;
1634 }
1635}
1636
1637void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) {
1638 CookedPointerData& currentPointerData = mCurrentCookedState.cookedPointerData;
1639 const CookedPointerData& lastPointerData = mLastCookedState.cookedPointerData;
1640
1641 if (mExternalStylusId != -1 && currentPointerData.isTouching(mExternalStylusId)) {
1642 float pressure = mExternalStylusState.pressure;
1643 if (pressure == 0.0f && lastPointerData.isTouching(mExternalStylusId)) {
1644 const PointerCoords& coords = lastPointerData.pointerCoordsForId(mExternalStylusId);
1645 pressure = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
1646 }
1647 PointerCoords& coords = currentPointerData.editPointerCoordsWithId(mExternalStylusId);
1648 coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
1649
1650 PointerProperties& properties =
1651 currentPointerData.editPointerPropertiesWithId(mExternalStylusId);
1652 if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) {
1653 properties.toolType = mExternalStylusState.toolType;
1654 }
1655 }
1656}
1657
1658bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
Michael Wright227c5542020-07-02 18:30:52 +01001659 if (mDeviceMode != DeviceMode::DIRECT || !hasExternalStylus()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001660 return false;
1661 }
1662
1663 const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 &&
1664 state.rawPointerData.pointerCount != 0;
1665 if (initialDown) {
1666 if (mExternalStylusState.pressure != 0.0f) {
1667#if DEBUG_STYLUS_FUSION
1668 ALOGD("Have both stylus and touch data, beginning fusion");
1669#endif
1670 mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit();
1671 } else if (timeout) {
1672#if DEBUG_STYLUS_FUSION
1673 ALOGD("Timeout expired, assuming touch is not a stylus.");
1674#endif
1675 resetExternalStylus();
1676 } else {
1677 if (mExternalStylusFusionTimeout == LLONG_MAX) {
1678 mExternalStylusFusionTimeout = state.when + EXTERNAL_STYLUS_DATA_TIMEOUT;
1679 }
1680#if DEBUG_STYLUS_FUSION
1681 ALOGD("No stylus data but stylus is connected, requesting timeout "
1682 "(%" PRId64 "ms)",
1683 mExternalStylusFusionTimeout);
1684#endif
1685 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
1686 return true;
1687 }
1688 }
1689
1690 // Check if the stylus pointer has gone up.
1691 if (mExternalStylusId != -1 && !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) {
1692#if DEBUG_STYLUS_FUSION
1693 ALOGD("Stylus pointer is going up");
1694#endif
1695 mExternalStylusId = -1;
1696 }
1697
1698 return false;
1699}
1700
1701void TouchInputMapper::timeoutExpired(nsecs_t when) {
Michael Wright227c5542020-07-02 18:30:52 +01001702 if (mDeviceMode == DeviceMode::POINTER) {
1703 if (mPointerUsage == PointerUsage::GESTURES) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001704 dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
1705 }
Michael Wright227c5542020-07-02 18:30:52 +01001706 } else if (mDeviceMode == DeviceMode::DIRECT) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001707 if (mExternalStylusFusionTimeout < when) {
1708 processRawTouches(true /*timeout*/);
1709 } else if (mExternalStylusFusionTimeout != LLONG_MAX) {
1710 getContext()->requestTimeoutAtTime(mExternalStylusFusionTimeout);
1711 }
1712 }
1713}
1714
1715void TouchInputMapper::updateExternalStylusState(const StylusState& state) {
1716 mExternalStylusState.copyFrom(state);
1717 if (mExternalStylusId != -1 || mExternalStylusFusionTimeout != LLONG_MAX) {
1718 // We're either in the middle of a fused stream of data or we're waiting on data before
1719 // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus
1720 // data.
1721 mExternalStylusDataPending = true;
1722 processRawTouches(false /*timeout*/);
1723 }
1724}
1725
1726bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) {
1727 // Check for release of a virtual key.
1728 if (mCurrentVirtualKey.down) {
1729 if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
1730 // Pointer went up while virtual key was down.
1731 mCurrentVirtualKey.down = false;
1732 if (!mCurrentVirtualKey.ignored) {
1733#if DEBUG_VIRTUAL_KEYS
1734 ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
1735 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
1736#endif
1737 dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP,
1738 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
1739 }
1740 return true;
1741 }
1742
1743 if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
1744 uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
1745 const RawPointerData::Pointer& pointer =
1746 mCurrentRawState.rawPointerData.pointerForId(id);
1747 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
1748 if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
1749 // Pointer is still within the space of the virtual key.
1750 return true;
1751 }
1752 }
1753
1754 // Pointer left virtual key area or another pointer also went down.
1755 // Send key cancellation but do not consume the touch yet.
1756 // This is useful when the user swipes through from the virtual key area
1757 // into the main display surface.
1758 mCurrentVirtualKey.down = false;
1759 if (!mCurrentVirtualKey.ignored) {
1760#if DEBUG_VIRTUAL_KEYS
1761 ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode,
1762 mCurrentVirtualKey.scanCode);
1763#endif
1764 dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP,
1765 AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY |
1766 AKEY_EVENT_FLAG_CANCELED);
1767 }
1768 }
1769
1770 if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() &&
1771 !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
1772 // Pointer just went down. Check for virtual key press or off-screen touches.
1773 uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit();
1774 const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id);
1775 if (!isPointInsideSurface(pointer.x, pointer.y)) {
1776 // If exactly one pointer went down, check for virtual key hit.
1777 // Otherwise we will drop the entire stroke.
1778 if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) {
1779 const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y);
1780 if (virtualKey) {
1781 mCurrentVirtualKey.down = true;
1782 mCurrentVirtualKey.downTime = when;
1783 mCurrentVirtualKey.keyCode = virtualKey->keyCode;
1784 mCurrentVirtualKey.scanCode = virtualKey->scanCode;
1785 mCurrentVirtualKey.ignored =
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001786 getContext()->shouldDropVirtualKey(when, virtualKey->keyCode,
1787 virtualKey->scanCode);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001788
1789 if (!mCurrentVirtualKey.ignored) {
1790#if DEBUG_VIRTUAL_KEYS
1791 ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
1792 mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
1793#endif
1794 dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_DOWN,
1795 AKEY_EVENT_FLAG_FROM_SYSTEM |
1796 AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
1797 }
1798 }
1799 }
1800 return true;
1801 }
1802 }
1803
1804 // Disable all virtual key touches that happen within a short time interval of the
1805 // most recent touch within the screen area. The idea is to filter out stray
1806 // virtual key presses when interacting with the touch screen.
1807 //
1808 // Problems we're trying to solve:
1809 //
1810 // 1. While scrolling a list or dragging the window shade, the user swipes down into a
1811 // virtual key area that is implemented by a separate touch panel and accidentally
1812 // triggers a virtual key.
1813 //
1814 // 2. While typing in the on screen keyboard, the user taps slightly outside the screen
1815 // area and accidentally triggers a virtual key. This often happens when virtual keys
1816 // are layed out below the screen near to where the on screen keyboard's space bar
1817 // is displayed.
1818 if (mConfig.virtualKeyQuietTime > 0 &&
1819 !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001820 getContext()->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001821 }
1822 return false;
1823}
1824
1825void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
1826 int32_t keyEventAction, int32_t keyEventFlags) {
1827 int32_t keyCode = mCurrentVirtualKey.keyCode;
1828 int32_t scanCode = mCurrentVirtualKey.scanCode;
1829 nsecs_t downTime = mCurrentVirtualKey.downTime;
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08001830 int32_t metaState = getContext()->getGlobalMetaState();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001831 policyFlags |= POLICY_FLAG_VIRTUAL;
1832
Garfield Tanc51d1ba2020-01-28 13:24:04 -08001833 NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
1834 mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode,
1835 scanCode, metaState, downTime);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001836 getListener()->notifyKey(&args);
1837}
1838
1839void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
1840 BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
1841 if (!currentIdBits.isEmpty()) {
1842 int32_t metaState = getContext()->getGlobalMetaState();
1843 int32_t buttonState = mCurrentCookedState.buttonState;
1844 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState,
1845 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
1846 mCurrentCookedState.cookedPointerData.pointerProperties,
1847 mCurrentCookedState.cookedPointerData.pointerCoords,
1848 mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
1849 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1850 mCurrentMotionAborted = true;
1851 }
1852}
1853
1854void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
1855 BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
1856 BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits;
1857 int32_t metaState = getContext()->getGlobalMetaState();
1858 int32_t buttonState = mCurrentCookedState.buttonState;
1859
1860 if (currentIdBits == lastIdBits) {
1861 if (!currentIdBits.isEmpty()) {
1862 // No pointer id changes so this is a move event.
1863 // The listener takes care of batching moves so we don't have to deal with that here.
1864 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
1865 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
1866 mCurrentCookedState.cookedPointerData.pointerProperties,
1867 mCurrentCookedState.cookedPointerData.pointerCoords,
1868 mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
1869 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1870 }
1871 } else {
1872 // There may be pointers going up and pointers going down and pointers moving
1873 // all at the same time.
1874 BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value);
1875 BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value);
1876 BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value);
1877 BitSet32 dispatchedIdBits(lastIdBits.value);
1878
1879 // Update last coordinates of pointers that have moved so that we observe the new
1880 // pointer positions at the same time as other pointers that have just gone up.
1881 bool moveNeeded =
1882 updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties,
1883 mCurrentCookedState.cookedPointerData.pointerCoords,
1884 mCurrentCookedState.cookedPointerData.idToIndex,
1885 mLastCookedState.cookedPointerData.pointerProperties,
1886 mLastCookedState.cookedPointerData.pointerCoords,
1887 mLastCookedState.cookedPointerData.idToIndex, moveIdBits);
1888 if (buttonState != mLastCookedState.buttonState) {
1889 moveNeeded = true;
1890 }
1891
1892 // Dispatch pointer up events.
1893 while (!upIdBits.isEmpty()) {
1894 uint32_t upId = upIdBits.clearFirstMarkedBit();
1895
1896 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
1897 metaState, buttonState, 0,
1898 mLastCookedState.cookedPointerData.pointerProperties,
1899 mLastCookedState.cookedPointerData.pointerCoords,
1900 mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
1901 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1902 dispatchedIdBits.clearBit(upId);
1903 }
1904
1905 // Dispatch move events if any of the remaining pointers moved from their old locations.
1906 // Although applications receive new locations as part of individual pointer up
1907 // events, they do not generally handle them except when presented in a move event.
1908 if (moveNeeded && !moveIdBits.isEmpty()) {
1909 ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
1910 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
1911 buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties,
1912 mCurrentCookedState.cookedPointerData.pointerCoords,
1913 mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1,
1914 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1915 }
1916
1917 // Dispatch pointer down events using the new pointer locations.
1918 while (!downIdBits.isEmpty()) {
1919 uint32_t downId = downIdBits.clearFirstMarkedBit();
1920 dispatchedIdBits.markBit(downId);
1921
1922 if (dispatchedIdBits.count() == 1) {
1923 // First pointer is going down. Set down time.
1924 mDownTime = when;
1925 }
1926
1927 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0,
1928 metaState, buttonState, 0,
1929 mCurrentCookedState.cookedPointerData.pointerProperties,
1930 mCurrentCookedState.cookedPointerData.pointerCoords,
1931 mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits,
1932 downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1933 }
1934 }
1935}
1936
1937void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) {
1938 if (mSentHoverEnter &&
1939 (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() ||
1940 !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
1941 int32_t metaState = getContext()->getGlobalMetaState();
1942 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
1943 mLastCookedState.buttonState, 0,
1944 mLastCookedState.cookedPointerData.pointerProperties,
1945 mLastCookedState.cookedPointerData.pointerCoords,
1946 mLastCookedState.cookedPointerData.idToIndex,
1947 mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision,
1948 mOrientedYPrecision, mDownTime);
1949 mSentHoverEnter = false;
1950 }
1951}
1952
1953void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) {
1954 if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() &&
1955 !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) {
1956 int32_t metaState = getContext()->getGlobalMetaState();
1957 if (!mSentHoverEnter) {
1958 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
1959 metaState, mCurrentRawState.buttonState, 0,
1960 mCurrentCookedState.cookedPointerData.pointerProperties,
1961 mCurrentCookedState.cookedPointerData.pointerCoords,
1962 mCurrentCookedState.cookedPointerData.idToIndex,
1963 mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
1964 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1965 mSentHoverEnter = true;
1966 }
1967
1968 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
1969 mCurrentRawState.buttonState, 0,
1970 mCurrentCookedState.cookedPointerData.pointerProperties,
1971 mCurrentCookedState.cookedPointerData.pointerCoords,
1972 mCurrentCookedState.cookedPointerData.idToIndex,
1973 mCurrentCookedState.cookedPointerData.hoveringIdBits, -1,
1974 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1975 }
1976}
1977
1978void TouchInputMapper::dispatchButtonRelease(nsecs_t when, uint32_t policyFlags) {
1979 BitSet32 releasedButtons(mLastCookedState.buttonState & ~mCurrentCookedState.buttonState);
1980 const BitSet32& idBits = findActiveIdBits(mLastCookedState.cookedPointerData);
1981 const int32_t metaState = getContext()->getGlobalMetaState();
1982 int32_t buttonState = mLastCookedState.buttonState;
1983 while (!releasedButtons.isEmpty()) {
1984 int32_t actionButton = BitSet32::valueForBit(releasedButtons.clearFirstMarkedBit());
1985 buttonState &= ~actionButton;
1986 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
1987 actionButton, 0, metaState, buttonState, 0,
1988 mCurrentCookedState.cookedPointerData.pointerProperties,
1989 mCurrentCookedState.cookedPointerData.pointerCoords,
1990 mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
1991 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
1992 }
1993}
1994
1995void TouchInputMapper::dispatchButtonPress(nsecs_t when, uint32_t policyFlags) {
1996 BitSet32 pressedButtons(mCurrentCookedState.buttonState & ~mLastCookedState.buttonState);
1997 const BitSet32& idBits = findActiveIdBits(mCurrentCookedState.cookedPointerData);
1998 const int32_t metaState = getContext()->getGlobalMetaState();
1999 int32_t buttonState = mLastCookedState.buttonState;
2000 while (!pressedButtons.isEmpty()) {
2001 int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
2002 buttonState |= actionButton;
2003 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
2004 0, metaState, buttonState, 0,
2005 mCurrentCookedState.cookedPointerData.pointerProperties,
2006 mCurrentCookedState.cookedPointerData.pointerCoords,
2007 mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
2008 mOrientedXPrecision, mOrientedYPrecision, mDownTime);
2009 }
2010}
2011
2012const BitSet32& TouchInputMapper::findActiveIdBits(const CookedPointerData& cookedPointerData) {
2013 if (!cookedPointerData.touchingIdBits.isEmpty()) {
2014 return cookedPointerData.touchingIdBits;
2015 }
2016 return cookedPointerData.hoveringIdBits;
2017}
2018
2019void TouchInputMapper::cookPointerData() {
2020 uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
2021
2022 mCurrentCookedState.cookedPointerData.clear();
2023 mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
2024 mCurrentCookedState.cookedPointerData.hoveringIdBits =
2025 mCurrentRawState.rawPointerData.hoveringIdBits;
2026 mCurrentCookedState.cookedPointerData.touchingIdBits =
2027 mCurrentRawState.rawPointerData.touchingIdBits;
2028
2029 if (mCurrentCookedState.cookedPointerData.pointerCount == 0) {
2030 mCurrentCookedState.buttonState = 0;
2031 } else {
2032 mCurrentCookedState.buttonState = mCurrentRawState.buttonState;
2033 }
2034
2035 // Walk through the the active pointers and map device coordinates onto
2036 // surface coordinates and adjust for display orientation.
2037 for (uint32_t i = 0; i < currentPointerCount; i++) {
2038 const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i];
2039
2040 // Size
2041 float touchMajor, touchMinor, toolMajor, toolMinor, size;
2042 switch (mCalibration.sizeCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002043 case Calibration::SizeCalibration::GEOMETRIC:
2044 case Calibration::SizeCalibration::DIAMETER:
2045 case Calibration::SizeCalibration::BOX:
2046 case Calibration::SizeCalibration::AREA:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002047 if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
2048 touchMajor = in.touchMajor;
2049 touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
2050 toolMajor = in.toolMajor;
2051 toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
2052 size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor)
2053 : in.touchMajor;
2054 } else if (mRawPointerAxes.touchMajor.valid) {
2055 toolMajor = touchMajor = in.touchMajor;
2056 toolMinor = touchMinor =
2057 mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
2058 size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor)
2059 : in.touchMajor;
2060 } else if (mRawPointerAxes.toolMajor.valid) {
2061 touchMajor = toolMajor = in.toolMajor;
2062 touchMinor = toolMinor =
2063 mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor;
2064 size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor)
2065 : in.toolMajor;
2066 } else {
2067 ALOG_ASSERT(false,
2068 "No touch or tool axes. "
2069 "Size calibration should have been resolved to NONE.");
2070 touchMajor = 0;
2071 touchMinor = 0;
2072 toolMajor = 0;
2073 toolMinor = 0;
2074 size = 0;
2075 }
2076
2077 if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) {
2078 uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count();
2079 if (touchingCount > 1) {
2080 touchMajor /= touchingCount;
2081 touchMinor /= touchingCount;
2082 toolMajor /= touchingCount;
2083 toolMinor /= touchingCount;
2084 size /= touchingCount;
2085 }
2086 }
2087
Michael Wright227c5542020-07-02 18:30:52 +01002088 if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002089 touchMajor *= mGeometricScale;
2090 touchMinor *= mGeometricScale;
2091 toolMajor *= mGeometricScale;
2092 toolMinor *= mGeometricScale;
Michael Wright227c5542020-07-02 18:30:52 +01002093 } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::AREA) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002094 touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
2095 touchMinor = touchMajor;
2096 toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
2097 toolMinor = toolMajor;
Michael Wright227c5542020-07-02 18:30:52 +01002098 } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DIAMETER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002099 touchMinor = touchMajor;
2100 toolMinor = toolMajor;
2101 }
2102
2103 mCalibration.applySizeScaleAndBias(&touchMajor);
2104 mCalibration.applySizeScaleAndBias(&touchMinor);
2105 mCalibration.applySizeScaleAndBias(&toolMajor);
2106 mCalibration.applySizeScaleAndBias(&toolMinor);
2107 size *= mSizeScale;
2108 break;
2109 default:
2110 touchMajor = 0;
2111 touchMinor = 0;
2112 toolMajor = 0;
2113 toolMinor = 0;
2114 size = 0;
2115 break;
2116 }
2117
2118 // Pressure
2119 float pressure;
2120 switch (mCalibration.pressureCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002121 case Calibration::PressureCalibration::PHYSICAL:
2122 case Calibration::PressureCalibration::AMPLITUDE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002123 pressure = in.pressure * mPressureScale;
2124 break;
2125 default:
2126 pressure = in.isHovering ? 0 : 1;
2127 break;
2128 }
2129
2130 // Tilt and Orientation
2131 float tilt;
2132 float orientation;
2133 if (mHaveTilt) {
2134 float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale;
2135 float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale;
2136 orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle));
2137 tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle));
2138 } else {
2139 tilt = 0;
2140
2141 switch (mCalibration.orientationCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002142 case Calibration::OrientationCalibration::INTERPOLATED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002143 orientation = in.orientation * mOrientationScale;
2144 break;
Michael Wright227c5542020-07-02 18:30:52 +01002145 case Calibration::OrientationCalibration::VECTOR: {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002146 int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
2147 int32_t c2 = signExtendNybble(in.orientation & 0x0f);
2148 if (c1 != 0 || c2 != 0) {
2149 orientation = atan2f(c1, c2) * 0.5f;
2150 float confidence = hypotf(c1, c2);
2151 float scale = 1.0f + confidence / 16.0f;
2152 touchMajor *= scale;
2153 touchMinor /= scale;
2154 toolMajor *= scale;
2155 toolMinor /= scale;
2156 } else {
2157 orientation = 0;
2158 }
2159 break;
2160 }
2161 default:
2162 orientation = 0;
2163 }
2164 }
2165
2166 // Distance
2167 float distance;
2168 switch (mCalibration.distanceCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002169 case Calibration::DistanceCalibration::SCALED:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002170 distance = in.distance * mDistanceScale;
2171 break;
2172 default:
2173 distance = 0;
2174 }
2175
2176 // Coverage
2177 int32_t rawLeft, rawTop, rawRight, rawBottom;
2178 switch (mCalibration.coverageCalibration) {
Michael Wright227c5542020-07-02 18:30:52 +01002179 case Calibration::CoverageCalibration::BOX:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002180 rawLeft = (in.toolMinor & 0xffff0000) >> 16;
2181 rawRight = in.toolMinor & 0x0000ffff;
2182 rawBottom = in.toolMajor & 0x0000ffff;
2183 rawTop = (in.toolMajor & 0xffff0000) >> 16;
2184 break;
2185 default:
2186 rawLeft = rawTop = rawRight = rawBottom = 0;
2187 break;
2188 }
2189
2190 // Adjust X,Y coords for device calibration
2191 // TODO: Adjust coverage coords?
2192 float xTransformed = in.x, yTransformed = in.y;
2193 mAffineTransform.applyTo(xTransformed, yTransformed);
Arthur Hung05de5772019-09-26 18:31:26 +08002194 rotateAndScale(xTransformed, yTransformed);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002195
2196 // Adjust X, Y, and coverage coords for surface orientation.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002197 float left, top, right, bottom;
2198
2199 switch (mSurfaceOrientation) {
2200 case DISPLAY_ORIENTATION_90:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002201 left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
2202 right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
2203 bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
2204 top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate;
2205 orientation -= M_PI_2;
2206 if (mOrientedRanges.haveOrientation &&
2207 orientation < mOrientedRanges.orientation.min) {
2208 orientation +=
2209 (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
2210 }
2211 break;
2212 case DISPLAY_ORIENTATION_180:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002213 left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
2214 right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
2215 bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
2216 top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate;
2217 orientation -= M_PI;
2218 if (mOrientedRanges.haveOrientation &&
2219 orientation < mOrientedRanges.orientation.min) {
2220 orientation +=
2221 (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
2222 }
2223 break;
2224 case DISPLAY_ORIENTATION_270:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002225 left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
2226 right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
2227 bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
2228 top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
2229 orientation += M_PI_2;
2230 if (mOrientedRanges.haveOrientation &&
2231 orientation > mOrientedRanges.orientation.max) {
2232 orientation -=
2233 (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min);
2234 }
2235 break;
2236 default:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002237 left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
2238 right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
2239 bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
2240 top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
2241 break;
2242 }
2243
2244 // Write output coords.
2245 PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i];
2246 out.clear();
Arthur Hung4197f6b2020-03-16 15:39:59 +08002247 out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed);
2248 out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002249 out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
2250 out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size);
2251 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor);
2252 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor);
2253 out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
2254 out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
2255 out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
Michael Wright227c5542020-07-02 18:30:52 +01002256 if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002257 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
2258 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
2259 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
2260 out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom);
2261 } else {
2262 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
2263 out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
2264 }
2265
2266 // Write output properties.
2267 PointerProperties& properties = mCurrentCookedState.cookedPointerData.pointerProperties[i];
2268 uint32_t id = in.id;
2269 properties.clear();
2270 properties.id = id;
2271 properties.toolType = in.toolType;
2272
2273 // Write id index.
2274 mCurrentCookedState.cookedPointerData.idToIndex[id] = i;
2275 }
2276}
2277
2278void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags,
2279 PointerUsage pointerUsage) {
2280 if (pointerUsage != mPointerUsage) {
2281 abortPointerUsage(when, policyFlags);
2282 mPointerUsage = pointerUsage;
2283 }
2284
2285 switch (mPointerUsage) {
Michael Wright227c5542020-07-02 18:30:52 +01002286 case PointerUsage::GESTURES:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002287 dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
2288 break;
Michael Wright227c5542020-07-02 18:30:52 +01002289 case PointerUsage::STYLUS:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002290 dispatchPointerStylus(when, policyFlags);
2291 break;
Michael Wright227c5542020-07-02 18:30:52 +01002292 case PointerUsage::MOUSE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002293 dispatchPointerMouse(when, policyFlags);
2294 break;
Michael Wright227c5542020-07-02 18:30:52 +01002295 case PointerUsage::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002296 break;
2297 }
2298}
2299
2300void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) {
2301 switch (mPointerUsage) {
Michael Wright227c5542020-07-02 18:30:52 +01002302 case PointerUsage::GESTURES:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002303 abortPointerGestures(when, policyFlags);
2304 break;
Michael Wright227c5542020-07-02 18:30:52 +01002305 case PointerUsage::STYLUS:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002306 abortPointerStylus(when, policyFlags);
2307 break;
Michael Wright227c5542020-07-02 18:30:52 +01002308 case PointerUsage::MOUSE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002309 abortPointerMouse(when, policyFlags);
2310 break;
Michael Wright227c5542020-07-02 18:30:52 +01002311 case PointerUsage::NONE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002312 break;
2313 }
2314
Michael Wright227c5542020-07-02 18:30:52 +01002315 mPointerUsage = PointerUsage::NONE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002316}
2317
2318void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) {
2319 // Update current gesture coordinates.
2320 bool cancelPreviousGesture, finishPreviousGesture;
2321 bool sendEvents =
2322 preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout);
2323 if (!sendEvents) {
2324 return;
2325 }
2326 if (finishPreviousGesture) {
2327 cancelPreviousGesture = false;
2328 }
2329
2330 // Update the pointer presentation and spots.
Michael Wright227c5542020-07-02 18:30:52 +01002331 if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
Michael Wrightca5bede2020-07-02 00:00:29 +01002332 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002333 if (finishPreviousGesture || cancelPreviousGesture) {
2334 mPointerController->clearSpots();
2335 }
2336
Michael Wright227c5542020-07-02 18:30:52 +01002337 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002338 mPointerController->setSpots(mPointerGesture.currentGestureCoords,
2339 mPointerGesture.currentGestureIdToIndex,
2340 mPointerGesture.currentGestureIdBits,
2341 mPointerController->getDisplayId());
2342 }
2343 } else {
Michael Wrightca5bede2020-07-02 00:00:29 +01002344 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002345 }
2346
2347 // Show or hide the pointer if needed.
2348 switch (mPointerGesture.currentGestureMode) {
Michael Wright227c5542020-07-02 18:30:52 +01002349 case PointerGesture::Mode::NEUTRAL:
2350 case PointerGesture::Mode::QUIET:
2351 if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH &&
2352 mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002353 // Remind the user of where the pointer is after finishing a gesture with spots.
Michael Wrightca5bede2020-07-02 00:00:29 +01002354 mPointerController->unfade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002355 }
2356 break;
Michael Wright227c5542020-07-02 18:30:52 +01002357 case PointerGesture::Mode::TAP:
2358 case PointerGesture::Mode::TAP_DRAG:
2359 case PointerGesture::Mode::BUTTON_CLICK_OR_DRAG:
2360 case PointerGesture::Mode::HOVER:
2361 case PointerGesture::Mode::PRESS:
2362 case PointerGesture::Mode::SWIPE:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002363 // Unfade the pointer when the current gesture manipulates the
2364 // area directly under the pointer.
Michael Wrightca5bede2020-07-02 00:00:29 +01002365 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002366 break;
Michael Wright227c5542020-07-02 18:30:52 +01002367 case PointerGesture::Mode::FREEFORM:
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002368 // Fade the pointer when the current gesture manipulates a different
2369 // area and there are spots to guide the user experience.
Michael Wright227c5542020-07-02 18:30:52 +01002370 if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
Michael Wrightca5bede2020-07-02 00:00:29 +01002371 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002372 } else {
Michael Wrightca5bede2020-07-02 00:00:29 +01002373 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002374 }
2375 break;
2376 }
2377
2378 // Send events!
2379 int32_t metaState = getContext()->getGlobalMetaState();
2380 int32_t buttonState = mCurrentCookedState.buttonState;
2381
2382 // Update last coordinates of pointers that have moved so that we observe the new
2383 // pointer positions at the same time as other pointers that have just gone up.
Michael Wright227c5542020-07-02 18:30:52 +01002384 bool down = mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP ||
2385 mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG ||
2386 mPointerGesture.currentGestureMode == PointerGesture::Mode::BUTTON_CLICK_OR_DRAG ||
2387 mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
2388 mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE ||
2389 mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002390 bool moveNeeded = false;
2391 if (down && !cancelPreviousGesture && !finishPreviousGesture &&
2392 !mPointerGesture.lastGestureIdBits.isEmpty() &&
2393 !mPointerGesture.currentGestureIdBits.isEmpty()) {
2394 BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value &
2395 mPointerGesture.lastGestureIdBits.value);
2396 moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties,
2397 mPointerGesture.currentGestureCoords,
2398 mPointerGesture.currentGestureIdToIndex,
2399 mPointerGesture.lastGestureProperties,
2400 mPointerGesture.lastGestureCoords,
2401 mPointerGesture.lastGestureIdToIndex, movedGestureIdBits);
2402 if (buttonState != mLastCookedState.buttonState) {
2403 moveNeeded = true;
2404 }
2405 }
2406
2407 // Send motion events for all pointers that went up or were canceled.
2408 BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits);
2409 if (!dispatchedGestureIdBits.isEmpty()) {
2410 if (cancelPreviousGesture) {
2411 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState,
2412 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2413 mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
2414 mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
2415 mPointerGesture.downTime);
2416
2417 dispatchedGestureIdBits.clear();
2418 } else {
2419 BitSet32 upGestureIdBits;
2420 if (finishPreviousGesture) {
2421 upGestureIdBits = dispatchedGestureIdBits;
2422 } else {
2423 upGestureIdBits.value =
2424 dispatchedGestureIdBits.value & ~mPointerGesture.currentGestureIdBits.value;
2425 }
2426 while (!upGestureIdBits.isEmpty()) {
2427 uint32_t id = upGestureIdBits.clearFirstMarkedBit();
2428
2429 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
2430 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2431 mPointerGesture.lastGestureProperties,
2432 mPointerGesture.lastGestureCoords,
2433 mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0,
2434 0, mPointerGesture.downTime);
2435
2436 dispatchedGestureIdBits.clearBit(id);
2437 }
2438 }
2439 }
2440
2441 // Send motion events for all pointers that moved.
2442 if (moveNeeded) {
2443 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
2444 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2445 mPointerGesture.currentGestureProperties,
2446 mPointerGesture.currentGestureCoords,
2447 mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
2448 mPointerGesture.downTime);
2449 }
2450
2451 // Send motion events for all pointers that went down.
2452 if (down) {
2453 BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value &
2454 ~dispatchedGestureIdBits.value);
2455 while (!downGestureIdBits.isEmpty()) {
2456 uint32_t id = downGestureIdBits.clearFirstMarkedBit();
2457 dispatchedGestureIdBits.markBit(id);
2458
2459 if (dispatchedGestureIdBits.count() == 1) {
2460 mPointerGesture.downTime = when;
2461 }
2462
2463 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0,
2464 metaState, buttonState, 0, mPointerGesture.currentGestureProperties,
2465 mPointerGesture.currentGestureCoords,
2466 mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0,
2467 0, mPointerGesture.downTime);
2468 }
2469 }
2470
2471 // Send motion events for hover.
Michael Wright227c5542020-07-02 18:30:52 +01002472 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002473 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
2474 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2475 mPointerGesture.currentGestureProperties,
2476 mPointerGesture.currentGestureCoords,
2477 mPointerGesture.currentGestureIdToIndex,
2478 mPointerGesture.currentGestureIdBits, -1, 0, 0, mPointerGesture.downTime);
2479 } else if (dispatchedGestureIdBits.isEmpty() && !mPointerGesture.lastGestureIdBits.isEmpty()) {
2480 // Synthesize a hover move event after all pointers go up to indicate that
2481 // the pointer is hovering again even if the user is not currently touching
2482 // the touch pad. This ensures that a view will receive a fresh hover enter
2483 // event after a tap.
2484 float x, y;
2485 mPointerController->getPosition(&x, &y);
2486
2487 PointerProperties pointerProperties;
2488 pointerProperties.clear();
2489 pointerProperties.id = 0;
2490 pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
2491
2492 PointerCoords pointerCoords;
2493 pointerCoords.clear();
2494 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
2495 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
2496
2497 const int32_t displayId = mPointerController->getDisplayId();
Garfield Tanc51d1ba2020-01-28 13:24:04 -08002498 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
2499 policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
2500 buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
2501 1, &pointerProperties, &pointerCoords, 0, 0, x, y,
2502 mPointerGesture.downTime, /* videoFrames */ {});
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002503 getListener()->notifyMotion(&args);
2504 }
2505
2506 // Update state.
2507 mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode;
2508 if (!down) {
2509 mPointerGesture.lastGestureIdBits.clear();
2510 } else {
2511 mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits;
2512 for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty();) {
2513 uint32_t id = idBits.clearFirstMarkedBit();
2514 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
2515 mPointerGesture.lastGestureProperties[index].copyFrom(
2516 mPointerGesture.currentGestureProperties[index]);
2517 mPointerGesture.lastGestureCoords[index].copyFrom(
2518 mPointerGesture.currentGestureCoords[index]);
2519 mPointerGesture.lastGestureIdToIndex[id] = index;
2520 }
2521 }
2522}
2523
2524void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) {
2525 // Cancel previously dispatches pointers.
2526 if (!mPointerGesture.lastGestureIdBits.isEmpty()) {
2527 int32_t metaState = getContext()->getGlobalMetaState();
2528 int32_t buttonState = mCurrentRawState.buttonState;
2529 dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState,
2530 buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
2531 mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
2532 mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1,
2533 0, 0, mPointerGesture.downTime);
2534 }
2535
2536 // Reset the current pointer gesture.
2537 mPointerGesture.reset();
2538 mPointerVelocityControl.reset();
2539
2540 // Remove any current spots.
2541 if (mPointerController != nullptr) {
Michael Wrightca5bede2020-07-02 00:00:29 +01002542 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002543 mPointerController->clearSpots();
2544 }
2545}
2546
2547bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture,
2548 bool* outFinishPreviousGesture, bool isTimeout) {
2549 *outCancelPreviousGesture = false;
2550 *outFinishPreviousGesture = false;
2551
2552 // Handle TAP timeout.
2553 if (isTimeout) {
2554#if DEBUG_GESTURES
2555 ALOGD("Gestures: Processing timeout");
2556#endif
2557
Michael Wright227c5542020-07-02 18:30:52 +01002558 if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002559 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
2560 // The tap/drag timeout has not yet expired.
2561 getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime +
2562 mConfig.pointerGestureTapDragInterval);
2563 } else {
2564 // The tap is finished.
2565#if DEBUG_GESTURES
2566 ALOGD("Gestures: TAP finished");
2567#endif
2568 *outFinishPreviousGesture = true;
2569
2570 mPointerGesture.activeGestureId = -1;
Michael Wright227c5542020-07-02 18:30:52 +01002571 mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002572 mPointerGesture.currentGestureIdBits.clear();
2573
2574 mPointerVelocityControl.reset();
2575 return true;
2576 }
2577 }
2578
2579 // We did not handle this timeout.
2580 return false;
2581 }
2582
2583 const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count();
2584 const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count();
2585
2586 // Update the velocity tracker.
2587 {
2588 VelocityTracker::Position positions[MAX_POINTERS];
2589 uint32_t count = 0;
2590 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
2591 uint32_t id = idBits.clearFirstMarkedBit();
2592 const RawPointerData::Pointer& pointer =
2593 mCurrentRawState.rawPointerData.pointerForId(id);
2594 positions[count].x = pointer.x * mPointerXMovementScale;
2595 positions[count].y = pointer.y * mPointerYMovementScale;
2596 }
2597 mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
2598 positions);
2599 }
2600
2601 // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
2602 // to NEUTRAL, then we should not generate tap event.
Michael Wright227c5542020-07-02 18:30:52 +01002603 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER &&
2604 mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP &&
2605 mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP_DRAG) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002606 mPointerGesture.resetTap();
2607 }
2608
2609 // Pick a new active touch id if needed.
2610 // Choose an arbitrary pointer that just went down, if there is one.
2611 // Otherwise choose an arbitrary remaining pointer.
2612 // This guarantees we always have an active touch id when there is at least one pointer.
2613 // We keep the same active touch id for as long as possible.
2614 int32_t lastActiveTouchId = mPointerGesture.activeTouchId;
2615 int32_t activeTouchId = lastActiveTouchId;
2616 if (activeTouchId < 0) {
2617 if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
2618 activeTouchId = mPointerGesture.activeTouchId =
2619 mCurrentCookedState.fingerIdBits.firstMarkedBit();
2620 mPointerGesture.firstTouchTime = when;
2621 }
2622 } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) {
2623 if (!mCurrentCookedState.fingerIdBits.isEmpty()) {
2624 activeTouchId = mPointerGesture.activeTouchId =
2625 mCurrentCookedState.fingerIdBits.firstMarkedBit();
2626 } else {
2627 activeTouchId = mPointerGesture.activeTouchId = -1;
2628 }
2629 }
2630
2631 // Determine whether we are in quiet time.
2632 bool isQuietTime = false;
2633 if (activeTouchId < 0) {
2634 mPointerGesture.resetQuietTime();
2635 } else {
2636 isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval;
2637 if (!isQuietTime) {
Michael Wright227c5542020-07-02 18:30:52 +01002638 if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::PRESS ||
2639 mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE ||
2640 mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002641 currentFingerCount < 2) {
2642 // Enter quiet time when exiting swipe or freeform state.
2643 // This is to prevent accidentally entering the hover state and flinging the
2644 // pointer when finishing a swipe and there is still one pointer left onscreen.
2645 isQuietTime = true;
Michael Wright227c5542020-07-02 18:30:52 +01002646 } else if (mPointerGesture.lastGestureMode ==
2647 PointerGesture::Mode::BUTTON_CLICK_OR_DRAG &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002648 currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) {
2649 // Enter quiet time when releasing the button and there are still two or more
2650 // fingers down. This may indicate that one finger was used to press the button
2651 // but it has not gone up yet.
2652 isQuietTime = true;
2653 }
2654 if (isQuietTime) {
2655 mPointerGesture.quietTime = when;
2656 }
2657 }
2658 }
2659
2660 // Switch states based on button and pointer state.
2661 if (isQuietTime) {
2662 // Case 1: Quiet time. (QUIET)
2663#if DEBUG_GESTURES
2664 ALOGD("Gestures: QUIET for next %0.3fms",
2665 (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f);
2666#endif
Michael Wright227c5542020-07-02 18:30:52 +01002667 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::QUIET) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002668 *outFinishPreviousGesture = true;
2669 }
2670
2671 mPointerGesture.activeGestureId = -1;
Michael Wright227c5542020-07-02 18:30:52 +01002672 mPointerGesture.currentGestureMode = PointerGesture::Mode::QUIET;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002673 mPointerGesture.currentGestureIdBits.clear();
2674
2675 mPointerVelocityControl.reset();
2676 } else if (isPointerDown(mCurrentRawState.buttonState)) {
2677 // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG)
2678 // The pointer follows the active touch point.
2679 // Emit DOWN, MOVE, UP events at the pointer location.
2680 //
2681 // Only the active touch matters; other fingers are ignored. This policy helps
2682 // to handle the case where the user places a second finger on the touch pad
2683 // to apply the necessary force to depress an integrated button below the surface.
2684 // We don't want the second finger to be delivered to applications.
2685 //
2686 // For this to work well, we need to make sure to track the pointer that is really
2687 // active. If the user first puts one finger down to click then adds another
2688 // finger to drag then the active pointer should switch to the finger that is
2689 // being dragged.
2690#if DEBUG_GESTURES
2691 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, "
2692 "currentFingerCount=%d",
2693 activeTouchId, currentFingerCount);
2694#endif
2695 // Reset state when just starting.
Michael Wright227c5542020-07-02 18:30:52 +01002696 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::BUTTON_CLICK_OR_DRAG) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002697 *outFinishPreviousGesture = true;
2698 mPointerGesture.activeGestureId = 0;
2699 }
2700
2701 // Switch pointers if needed.
2702 // Find the fastest pointer and follow it.
2703 if (activeTouchId >= 0 && currentFingerCount > 1) {
2704 int32_t bestId = -1;
2705 float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
2706 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
2707 uint32_t id = idBits.clearFirstMarkedBit();
2708 float vx, vy;
2709 if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
2710 float speed = hypotf(vx, vy);
2711 if (speed > bestSpeed) {
2712 bestId = id;
2713 bestSpeed = speed;
2714 }
2715 }
2716 }
2717 if (bestId >= 0 && bestId != activeTouchId) {
2718 mPointerGesture.activeTouchId = activeTouchId = bestId;
2719#if DEBUG_GESTURES
2720 ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, "
2721 "bestId=%d, bestSpeed=%0.3f",
2722 bestId, bestSpeed);
2723#endif
2724 }
2725 }
2726
2727 float deltaX = 0, deltaY = 0;
2728 if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
2729 const RawPointerData::Pointer& currentPointer =
2730 mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
2731 const RawPointerData::Pointer& lastPointer =
2732 mLastRawState.rawPointerData.pointerForId(activeTouchId);
2733 deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
2734 deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
2735
2736 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
2737 mPointerVelocityControl.move(when, &deltaX, &deltaY);
2738
2739 // Move the pointer using a relative motion.
2740 // When using spots, the click will occur at the position of the anchor
2741 // spot and all other spots will move there.
2742 mPointerController->move(deltaX, deltaY);
2743 } else {
2744 mPointerVelocityControl.reset();
2745 }
2746
2747 float x, y;
2748 mPointerController->getPosition(&x, &y);
2749
Michael Wright227c5542020-07-02 18:30:52 +01002750 mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002751 mPointerGesture.currentGestureIdBits.clear();
2752 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
2753 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
2754 mPointerGesture.currentGestureProperties[0].clear();
2755 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
2756 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
2757 mPointerGesture.currentGestureCoords[0].clear();
2758 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
2759 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
2760 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
2761 } else if (currentFingerCount == 0) {
2762 // Case 3. No fingers down and button is not pressed. (NEUTRAL)
Michael Wright227c5542020-07-02 18:30:52 +01002763 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::NEUTRAL) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002764 *outFinishPreviousGesture = true;
2765 }
2766
2767 // Watch for taps coming out of HOVER or TAP_DRAG mode.
2768 // Checking for taps after TAP_DRAG allows us to detect double-taps.
2769 bool tapped = false;
Michael Wright227c5542020-07-02 18:30:52 +01002770 if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::HOVER ||
2771 mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002772 lastFingerCount == 1) {
2773 if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
2774 float x, y;
2775 mPointerController->getPosition(&x, &y);
2776 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
2777 fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
2778#if DEBUG_GESTURES
2779 ALOGD("Gestures: TAP");
2780#endif
2781
2782 mPointerGesture.tapUpTime = when;
2783 getContext()->requestTimeoutAtTime(when +
2784 mConfig.pointerGestureTapDragInterval);
2785
2786 mPointerGesture.activeGestureId = 0;
Michael Wright227c5542020-07-02 18:30:52 +01002787 mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002788 mPointerGesture.currentGestureIdBits.clear();
2789 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
2790 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
2791 mPointerGesture.currentGestureProperties[0].clear();
2792 mPointerGesture.currentGestureProperties[0].id =
2793 mPointerGesture.activeGestureId;
2794 mPointerGesture.currentGestureProperties[0].toolType =
2795 AMOTION_EVENT_TOOL_TYPE_FINGER;
2796 mPointerGesture.currentGestureCoords[0].clear();
2797 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
2798 mPointerGesture.tapX);
2799 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
2800 mPointerGesture.tapY);
2801 mPointerGesture.currentGestureCoords[0]
2802 .setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
2803
2804 tapped = true;
2805 } else {
2806#if DEBUG_GESTURES
2807 ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX,
2808 y - mPointerGesture.tapY);
2809#endif
2810 }
2811 } else {
2812#if DEBUG_GESTURES
2813 if (mPointerGesture.tapDownTime != LLONG_MIN) {
2814 ALOGD("Gestures: Not a TAP, %0.3fms since down",
2815 (when - mPointerGesture.tapDownTime) * 0.000001f);
2816 } else {
2817 ALOGD("Gestures: Not a TAP, incompatible mode transitions");
2818 }
2819#endif
2820 }
2821 }
2822
2823 mPointerVelocityControl.reset();
2824
2825 if (!tapped) {
2826#if DEBUG_GESTURES
2827 ALOGD("Gestures: NEUTRAL");
2828#endif
2829 mPointerGesture.activeGestureId = -1;
Michael Wright227c5542020-07-02 18:30:52 +01002830 mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002831 mPointerGesture.currentGestureIdBits.clear();
2832 }
2833 } else if (currentFingerCount == 1) {
2834 // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG)
2835 // The pointer follows the active touch point.
2836 // When in HOVER, emit HOVER_MOVE events at the pointer location.
2837 // When in TAP_DRAG, emit MOVE events at the pointer location.
2838 ALOG_ASSERT(activeTouchId >= 0);
2839
Michael Wright227c5542020-07-02 18:30:52 +01002840 mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER;
2841 if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002842 if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
2843 float x, y;
2844 mPointerController->getPosition(&x, &y);
2845 if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
2846 fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
Michael Wright227c5542020-07-02 18:30:52 +01002847 mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002848 } else {
2849#if DEBUG_GESTURES
2850 ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
2851 x - mPointerGesture.tapX, y - mPointerGesture.tapY);
2852#endif
2853 }
2854 } else {
2855#if DEBUG_GESTURES
2856 ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up",
2857 (when - mPointerGesture.tapUpTime) * 0.000001f);
2858#endif
2859 }
Michael Wright227c5542020-07-02 18:30:52 +01002860 } else if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) {
2861 mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002862 }
2863
2864 float deltaX = 0, deltaY = 0;
2865 if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) {
2866 const RawPointerData::Pointer& currentPointer =
2867 mCurrentRawState.rawPointerData.pointerForId(activeTouchId);
2868 const RawPointerData::Pointer& lastPointer =
2869 mLastRawState.rawPointerData.pointerForId(activeTouchId);
2870 deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale;
2871 deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale;
2872
2873 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
2874 mPointerVelocityControl.move(when, &deltaX, &deltaY);
2875
2876 // Move the pointer using a relative motion.
2877 // When using spots, the hover or drag will occur at the position of the anchor spot.
2878 mPointerController->move(deltaX, deltaY);
2879 } else {
2880 mPointerVelocityControl.reset();
2881 }
2882
2883 bool down;
Michael Wright227c5542020-07-02 18:30:52 +01002884 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002885#if DEBUG_GESTURES
2886 ALOGD("Gestures: TAP_DRAG");
2887#endif
2888 down = true;
2889 } else {
2890#if DEBUG_GESTURES
2891 ALOGD("Gestures: HOVER");
2892#endif
Michael Wright227c5542020-07-02 18:30:52 +01002893 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002894 *outFinishPreviousGesture = true;
2895 }
2896 mPointerGesture.activeGestureId = 0;
2897 down = false;
2898 }
2899
2900 float x, y;
2901 mPointerController->getPosition(&x, &y);
2902
2903 mPointerGesture.currentGestureIdBits.clear();
2904 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
2905 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
2906 mPointerGesture.currentGestureProperties[0].clear();
2907 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
2908 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
2909 mPointerGesture.currentGestureCoords[0].clear();
2910 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
2911 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
2912 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
2913 down ? 1.0f : 0.0f);
2914
2915 if (lastFingerCount == 0 && currentFingerCount != 0) {
2916 mPointerGesture.resetTap();
2917 mPointerGesture.tapDownTime = when;
2918 mPointerGesture.tapX = x;
2919 mPointerGesture.tapY = y;
2920 }
2921 } else {
2922 // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
2923 // We need to provide feedback for each finger that goes down so we cannot wait
2924 // for the fingers to move before deciding what to do.
2925 //
2926 // The ambiguous case is deciding what to do when there are two fingers down but they
2927 // have not moved enough to determine whether they are part of a drag or part of a
2928 // freeform gesture, or just a press or long-press at the pointer location.
2929 //
2930 // When there are two fingers we start with the PRESS hypothesis and we generate a
2931 // down at the pointer location.
2932 //
2933 // When the two fingers move enough or when additional fingers are added, we make
2934 // a decision to transition into SWIPE or FREEFORM mode accordingly.
2935 ALOG_ASSERT(activeTouchId >= 0);
2936
2937 bool settled = when >=
2938 mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval;
Michael Wright227c5542020-07-02 18:30:52 +01002939 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::PRESS &&
2940 mPointerGesture.lastGestureMode != PointerGesture::Mode::SWIPE &&
2941 mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002942 *outFinishPreviousGesture = true;
2943 } else if (!settled && currentFingerCount > lastFingerCount) {
2944 // Additional pointers have gone down but not yet settled.
2945 // Reset the gesture.
2946#if DEBUG_GESTURES
2947 ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, "
2948 "settle time remaining %0.3fms",
2949 (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval -
2950 when) * 0.000001f);
2951#endif
2952 *outCancelPreviousGesture = true;
2953 } else {
2954 // Continue previous gesture.
2955 mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode;
2956 }
2957
2958 if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
Michael Wright227c5542020-07-02 18:30:52 +01002959 mPointerGesture.currentGestureMode = PointerGesture::Mode::PRESS;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07002960 mPointerGesture.activeGestureId = 0;
2961 mPointerGesture.referenceIdBits.clear();
2962 mPointerVelocityControl.reset();
2963
2964 // Use the centroid and pointer location as the reference points for the gesture.
2965#if DEBUG_GESTURES
2966 ALOGD("Gestures: Using centroid as reference for MULTITOUCH, "
2967 "settle time remaining %0.3fms",
2968 (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval -
2969 when) * 0.000001f);
2970#endif
2971 mCurrentRawState.rawPointerData
2972 .getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX,
2973 &mPointerGesture.referenceTouchY);
2974 mPointerController->getPosition(&mPointerGesture.referenceGestureX,
2975 &mPointerGesture.referenceGestureY);
2976 }
2977
2978 // Clear the reference deltas for fingers not yet included in the reference calculation.
2979 for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value &
2980 ~mPointerGesture.referenceIdBits.value);
2981 !idBits.isEmpty();) {
2982 uint32_t id = idBits.clearFirstMarkedBit();
2983 mPointerGesture.referenceDeltas[id].dx = 0;
2984 mPointerGesture.referenceDeltas[id].dy = 0;
2985 }
2986 mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits;
2987
2988 // Add delta for all fingers and calculate a common movement delta.
2989 float commonDeltaX = 0, commonDeltaY = 0;
2990 BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value &
2991 mCurrentCookedState.fingerIdBits.value);
2992 for (BitSet32 idBits(commonIdBits); !idBits.isEmpty();) {
2993 bool first = (idBits == commonIdBits);
2994 uint32_t id = idBits.clearFirstMarkedBit();
2995 const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id);
2996 const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id);
2997 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
2998 delta.dx += cpd.x - lpd.x;
2999 delta.dy += cpd.y - lpd.y;
3000
3001 if (first) {
3002 commonDeltaX = delta.dx;
3003 commonDeltaY = delta.dy;
3004 } else {
3005 commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx);
3006 commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy);
3007 }
3008 }
3009
3010 // Consider transitions from PRESS to SWIPE or MULTITOUCH.
Michael Wright227c5542020-07-02 18:30:52 +01003011 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003012 float dist[MAX_POINTER_ID + 1];
3013 int32_t distOverThreshold = 0;
3014 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
3015 uint32_t id = idBits.clearFirstMarkedBit();
3016 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
3017 dist[id] = hypotf(delta.dx * mPointerXZoomScale, delta.dy * mPointerYZoomScale);
3018 if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) {
3019 distOverThreshold += 1;
3020 }
3021 }
3022
3023 // Only transition when at least two pointers have moved further than
3024 // the minimum distance threshold.
3025 if (distOverThreshold >= 2) {
3026 if (currentFingerCount > 2) {
3027 // There are more than two pointers, switch to FREEFORM.
3028#if DEBUG_GESTURES
3029 ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2",
3030 currentFingerCount);
3031#endif
3032 *outCancelPreviousGesture = true;
Michael Wright227c5542020-07-02 18:30:52 +01003033 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003034 } else {
3035 // There are exactly two pointers.
3036 BitSet32 idBits(mCurrentCookedState.fingerIdBits);
3037 uint32_t id1 = idBits.clearFirstMarkedBit();
3038 uint32_t id2 = idBits.firstMarkedBit();
3039 const RawPointerData::Pointer& p1 =
3040 mCurrentRawState.rawPointerData.pointerForId(id1);
3041 const RawPointerData::Pointer& p2 =
3042 mCurrentRawState.rawPointerData.pointerForId(id2);
3043 float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y);
3044 if (mutualDistance > mPointerGestureMaxSwipeWidth) {
3045 // There are two pointers but they are too far apart for a SWIPE,
3046 // switch to FREEFORM.
3047#if DEBUG_GESTURES
3048 ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f",
3049 mutualDistance, mPointerGestureMaxSwipeWidth);
3050#endif
3051 *outCancelPreviousGesture = true;
Michael Wright227c5542020-07-02 18:30:52 +01003052 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003053 } else {
3054 // There are two pointers. Wait for both pointers to start moving
3055 // before deciding whether this is a SWIPE or FREEFORM gesture.
3056 float dist1 = dist[id1];
3057 float dist2 = dist[id2];
3058 if (dist1 >= mConfig.pointerGestureMultitouchMinDistance &&
3059 dist2 >= mConfig.pointerGestureMultitouchMinDistance) {
3060 // Calculate the dot product of the displacement vectors.
3061 // When the vectors are oriented in approximately the same direction,
3062 // the angle betweeen them is near zero and the cosine of the angle
3063 // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) *
3064 // mag(v2).
3065 PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1];
3066 PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2];
3067 float dx1 = delta1.dx * mPointerXZoomScale;
3068 float dy1 = delta1.dy * mPointerYZoomScale;
3069 float dx2 = delta2.dx * mPointerXZoomScale;
3070 float dy2 = delta2.dy * mPointerYZoomScale;
3071 float dot = dx1 * dx2 + dy1 * dy2;
3072 float cosine = dot / (dist1 * dist2); // denominator always > 0
3073 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) {
3074 // Pointers are moving in the same direction. Switch to SWIPE.
3075#if DEBUG_GESTURES
3076 ALOGD("Gestures: PRESS transitioned to SWIPE, "
3077 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
3078 "cosine %0.3f >= %0.3f",
3079 dist1, mConfig.pointerGestureMultitouchMinDistance, dist2,
3080 mConfig.pointerGestureMultitouchMinDistance, cosine,
3081 mConfig.pointerGestureSwipeTransitionAngleCosine);
3082#endif
Michael Wright227c5542020-07-02 18:30:52 +01003083 mPointerGesture.currentGestureMode = PointerGesture::Mode::SWIPE;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003084 } else {
3085 // Pointers are moving in different directions. Switch to FREEFORM.
3086#if DEBUG_GESTURES
3087 ALOGD("Gestures: PRESS transitioned to FREEFORM, "
3088 "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, "
3089 "cosine %0.3f < %0.3f",
3090 dist1, mConfig.pointerGestureMultitouchMinDistance, dist2,
3091 mConfig.pointerGestureMultitouchMinDistance, cosine,
3092 mConfig.pointerGestureSwipeTransitionAngleCosine);
3093#endif
3094 *outCancelPreviousGesture = true;
Michael Wright227c5542020-07-02 18:30:52 +01003095 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003096 }
3097 }
3098 }
3099 }
3100 }
Michael Wright227c5542020-07-02 18:30:52 +01003101 } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003102 // Switch from SWIPE to FREEFORM if additional pointers go down.
3103 // Cancel previous gesture.
3104 if (currentFingerCount > 2) {
3105#if DEBUG_GESTURES
3106 ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2",
3107 currentFingerCount);
3108#endif
3109 *outCancelPreviousGesture = true;
Michael Wright227c5542020-07-02 18:30:52 +01003110 mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003111 }
3112 }
3113
3114 // Move the reference points based on the overall group motion of the fingers
3115 // except in PRESS mode while waiting for a transition to occur.
Michael Wright227c5542020-07-02 18:30:52 +01003116 if (mPointerGesture.currentGestureMode != PointerGesture::Mode::PRESS &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003117 (commonDeltaX || commonDeltaY)) {
3118 for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
3119 uint32_t id = idBits.clearFirstMarkedBit();
3120 PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id];
3121 delta.dx = 0;
3122 delta.dy = 0;
3123 }
3124
3125 mPointerGesture.referenceTouchX += commonDeltaX;
3126 mPointerGesture.referenceTouchY += commonDeltaY;
3127
3128 commonDeltaX *= mPointerXMovementScale;
3129 commonDeltaY *= mPointerYMovementScale;
3130
3131 rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY);
3132 mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
3133
3134 mPointerGesture.referenceGestureX += commonDeltaX;
3135 mPointerGesture.referenceGestureY += commonDeltaY;
3136 }
3137
3138 // Report gestures.
Michael Wright227c5542020-07-02 18:30:52 +01003139 if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
3140 mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003141 // PRESS or SWIPE mode.
3142#if DEBUG_GESTURES
3143 ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
3144 "activeGestureId=%d, currentTouchPointerCount=%d",
3145 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
3146#endif
3147 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
3148
3149 mPointerGesture.currentGestureIdBits.clear();
3150 mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
3151 mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
3152 mPointerGesture.currentGestureProperties[0].clear();
3153 mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
3154 mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
3155 mPointerGesture.currentGestureCoords[0].clear();
3156 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
3157 mPointerGesture.referenceGestureX);
3158 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
3159 mPointerGesture.referenceGestureY);
3160 mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
Michael Wright227c5542020-07-02 18:30:52 +01003161 } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003162 // FREEFORM mode.
3163#if DEBUG_GESTURES
3164 ALOGD("Gestures: FREEFORM activeTouchId=%d,"
3165 "activeGestureId=%d, currentTouchPointerCount=%d",
3166 activeTouchId, mPointerGesture.activeGestureId, currentFingerCount);
3167#endif
3168 ALOG_ASSERT(mPointerGesture.activeGestureId >= 0);
3169
3170 mPointerGesture.currentGestureIdBits.clear();
3171
3172 BitSet32 mappedTouchIdBits;
3173 BitSet32 usedGestureIdBits;
Michael Wright227c5542020-07-02 18:30:52 +01003174 if (mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003175 // Initially, assign the active gesture id to the active touch point
3176 // if there is one. No other touch id bits are mapped yet.
3177 if (!*outCancelPreviousGesture) {
3178 mappedTouchIdBits.markBit(activeTouchId);
3179 usedGestureIdBits.markBit(mPointerGesture.activeGestureId);
3180 mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] =
3181 mPointerGesture.activeGestureId;
3182 } else {
3183 mPointerGesture.activeGestureId = -1;
3184 }
3185 } else {
3186 // Otherwise, assume we mapped all touches from the previous frame.
3187 // Reuse all mappings that are still applicable.
3188 mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value &
3189 mCurrentCookedState.fingerIdBits.value;
3190 usedGestureIdBits = mPointerGesture.lastGestureIdBits;
3191
3192 // Check whether we need to choose a new active gesture id because the
3193 // current went went up.
3194 for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value &
3195 ~mCurrentCookedState.fingerIdBits.value);
3196 !upTouchIdBits.isEmpty();) {
3197 uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit();
3198 uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId];
3199 if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) {
3200 mPointerGesture.activeGestureId = -1;
3201 break;
3202 }
3203 }
3204 }
3205
3206#if DEBUG_GESTURES
3207 ALOGD("Gestures: FREEFORM follow up "
3208 "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, "
3209 "activeGestureId=%d",
3210 mappedTouchIdBits.value, usedGestureIdBits.value,
3211 mPointerGesture.activeGestureId);
3212#endif
3213
3214 BitSet32 idBits(mCurrentCookedState.fingerIdBits);
3215 for (uint32_t i = 0; i < currentFingerCount; i++) {
3216 uint32_t touchId = idBits.clearFirstMarkedBit();
3217 uint32_t gestureId;
3218 if (!mappedTouchIdBits.hasBit(touchId)) {
3219 gestureId = usedGestureIdBits.markFirstUnmarkedBit();
3220 mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId;
3221#if DEBUG_GESTURES
3222 ALOGD("Gestures: FREEFORM "
3223 "new mapping for touch id %d -> gesture id %d",
3224 touchId, gestureId);
3225#endif
3226 } else {
3227 gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId];
3228#if DEBUG_GESTURES
3229 ALOGD("Gestures: FREEFORM "
3230 "existing mapping for touch id %d -> gesture id %d",
3231 touchId, gestureId);
3232#endif
3233 }
3234 mPointerGesture.currentGestureIdBits.markBit(gestureId);
3235 mPointerGesture.currentGestureIdToIndex[gestureId] = i;
3236
3237 const RawPointerData::Pointer& pointer =
3238 mCurrentRawState.rawPointerData.pointerForId(touchId);
3239 float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale;
3240 float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale;
3241 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
3242
3243 mPointerGesture.currentGestureProperties[i].clear();
3244 mPointerGesture.currentGestureProperties[i].id = gestureId;
3245 mPointerGesture.currentGestureProperties[i].toolType =
3246 AMOTION_EVENT_TOOL_TYPE_FINGER;
3247 mPointerGesture.currentGestureCoords[i].clear();
3248 mPointerGesture.currentGestureCoords[i]
3249 .setAxisValue(AMOTION_EVENT_AXIS_X,
3250 mPointerGesture.referenceGestureX + deltaX);
3251 mPointerGesture.currentGestureCoords[i]
3252 .setAxisValue(AMOTION_EVENT_AXIS_Y,
3253 mPointerGesture.referenceGestureY + deltaY);
3254 mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
3255 1.0f);
3256 }
3257
3258 if (mPointerGesture.activeGestureId < 0) {
3259 mPointerGesture.activeGestureId =
3260 mPointerGesture.currentGestureIdBits.firstMarkedBit();
3261#if DEBUG_GESTURES
3262 ALOGD("Gestures: FREEFORM new "
3263 "activeGestureId=%d",
3264 mPointerGesture.activeGestureId);
3265#endif
3266 }
3267 }
3268 }
3269
3270 mPointerController->setButtonState(mCurrentRawState.buttonState);
3271
3272#if DEBUG_GESTURES
3273 ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, "
3274 "currentGestureMode=%d, currentGestureIdBits=0x%08x, "
3275 "lastGestureMode=%d, lastGestureIdBits=0x%08x",
3276 toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture),
3277 mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value,
3278 mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value);
3279 for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty();) {
3280 uint32_t id = idBits.clearFirstMarkedBit();
3281 uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
3282 const PointerProperties& properties = mPointerGesture.currentGestureProperties[index];
3283 const PointerCoords& coords = mPointerGesture.currentGestureCoords[index];
3284 ALOGD(" currentGesture[%d]: index=%d, toolType=%d, "
3285 "x=%0.3f, y=%0.3f, pressure=%0.3f",
3286 id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
3287 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
3288 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
3289 }
3290 for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty();) {
3291 uint32_t id = idBits.clearFirstMarkedBit();
3292 uint32_t index = mPointerGesture.lastGestureIdToIndex[id];
3293 const PointerProperties& properties = mPointerGesture.lastGestureProperties[index];
3294 const PointerCoords& coords = mPointerGesture.lastGestureCoords[index];
3295 ALOGD(" lastGesture[%d]: index=%d, toolType=%d, "
3296 "x=%0.3f, y=%0.3f, pressure=%0.3f",
3297 id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X),
3298 coords.getAxisValue(AMOTION_EVENT_AXIS_Y),
3299 coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
3300 }
3301#endif
3302 return true;
3303}
3304
3305void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) {
3306 mPointerSimple.currentCoords.clear();
3307 mPointerSimple.currentProperties.clear();
3308
3309 bool down, hovering;
3310 if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
3311 uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit();
3312 uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id];
3313 float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX();
3314 float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY();
3315 mPointerController->setPosition(x, y);
3316
3317 hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id);
3318 down = !hovering;
3319
3320 mPointerController->getPosition(&x, &y);
3321 mPointerSimple.currentCoords.copyFrom(
3322 mCurrentCookedState.cookedPointerData.pointerCoords[index]);
3323 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
3324 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
3325 mPointerSimple.currentProperties.id = 0;
3326 mPointerSimple.currentProperties.toolType =
3327 mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType;
3328 } else {
3329 down = false;
3330 hovering = false;
3331 }
3332
3333 dispatchPointerSimple(when, policyFlags, down, hovering);
3334}
3335
3336void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) {
3337 abortPointerSimple(when, policyFlags);
3338}
3339
3340void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) {
3341 mPointerSimple.currentCoords.clear();
3342 mPointerSimple.currentProperties.clear();
3343
3344 bool down, hovering;
3345 if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
3346 uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit();
3347 uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
3348 float deltaX = 0, deltaY = 0;
3349 if (mLastCookedState.mouseIdBits.hasBit(id)) {
3350 uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id];
3351 deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x -
3352 mLastRawState.rawPointerData.pointers[lastIndex].x) *
3353 mPointerXMovementScale;
3354 deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y -
3355 mLastRawState.rawPointerData.pointers[lastIndex].y) *
3356 mPointerYMovementScale;
3357
3358 rotateDelta(mSurfaceOrientation, &deltaX, &deltaY);
3359 mPointerVelocityControl.move(when, &deltaX, &deltaY);
3360
3361 mPointerController->move(deltaX, deltaY);
3362 } else {
3363 mPointerVelocityControl.reset();
3364 }
3365
3366 down = isPointerDown(mCurrentRawState.buttonState);
3367 hovering = !down;
3368
3369 float x, y;
3370 mPointerController->getPosition(&x, &y);
3371 mPointerSimple.currentCoords.copyFrom(
3372 mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]);
3373 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
3374 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
3375 mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
3376 hovering ? 0.0f : 1.0f);
3377 mPointerSimple.currentProperties.id = 0;
3378 mPointerSimple.currentProperties.toolType =
3379 mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType;
3380 } else {
3381 mPointerVelocityControl.reset();
3382
3383 down = false;
3384 hovering = false;
3385 }
3386
3387 dispatchPointerSimple(when, policyFlags, down, hovering);
3388}
3389
3390void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) {
3391 abortPointerSimple(when, policyFlags);
3392
3393 mPointerVelocityControl.reset();
3394}
3395
3396void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down,
3397 bool hovering) {
3398 int32_t metaState = getContext()->getGlobalMetaState();
3399 int32_t displayId = mViewport.displayId;
3400
3401 if (down || hovering) {
Michael Wrightca5bede2020-07-02 00:00:29 +01003402 mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003403 mPointerController->clearSpots();
3404 mPointerController->setButtonState(mCurrentRawState.buttonState);
Michael Wrightca5bede2020-07-02 00:00:29 +01003405 mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003406 } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
Michael Wrightca5bede2020-07-02 00:00:29 +01003407 mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003408 }
3409 displayId = mPointerController->getDisplayId();
3410
3411 float xCursorPosition;
3412 float yCursorPosition;
3413 mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
3414
3415 if (mPointerSimple.down && !down) {
3416 mPointerSimple.down = false;
3417
3418 // Send up.
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003419 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
3420 policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003421 mLastRawState.buttonState, MotionClassification::NONE,
3422 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
3423 &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
3424 xCursorPosition, yCursorPosition, mPointerSimple.downTime,
3425 /* videoFrames */ {});
3426 getListener()->notifyMotion(&args);
3427 }
3428
3429 if (mPointerSimple.hovering && !hovering) {
3430 mPointerSimple.hovering = false;
3431
3432 // Send hover exit.
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003433 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
3434 policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
3435 mLastRawState.buttonState, MotionClassification::NONE,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003436 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
3437 &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
3438 xCursorPosition, yCursorPosition, mPointerSimple.downTime,
3439 /* videoFrames */ {});
3440 getListener()->notifyMotion(&args);
3441 }
3442
3443 if (down) {
3444 if (!mPointerSimple.down) {
3445 mPointerSimple.down = true;
3446 mPointerSimple.downTime = when;
3447
3448 // Send down.
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003449 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003450 displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
3451 metaState, mCurrentRawState.buttonState,
3452 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3453 &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
3454 mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
3455 yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
3456 getListener()->notifyMotion(&args);
3457 }
3458
3459 // Send move.
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003460 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
3461 policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003462 mCurrentRawState.buttonState, MotionClassification::NONE,
3463 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
3464 &mPointerSimple.currentCoords, mOrientedXPrecision,
3465 mOrientedYPrecision, xCursorPosition, yCursorPosition,
3466 mPointerSimple.downTime, /* videoFrames */ {});
3467 getListener()->notifyMotion(&args);
3468 }
3469
3470 if (hovering) {
3471 if (!mPointerSimple.hovering) {
3472 mPointerSimple.hovering = true;
3473
3474 // Send hover enter.
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003475 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003476 displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
3477 metaState, mCurrentRawState.buttonState,
3478 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
3479 &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
3480 mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
3481 yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
3482 getListener()->notifyMotion(&args);
3483 }
3484
3485 // Send hover move.
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003486 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
3487 policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
3488 mCurrentRawState.buttonState, MotionClassification::NONE,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003489 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
3490 &mPointerSimple.currentCoords, mOrientedXPrecision,
3491 mOrientedYPrecision, xCursorPosition, yCursorPosition,
3492 mPointerSimple.downTime, /* videoFrames */ {});
3493 getListener()->notifyMotion(&args);
3494 }
3495
3496 if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
3497 float vscroll = mCurrentRawState.rawVScroll;
3498 float hscroll = mCurrentRawState.rawHScroll;
3499 mWheelYVelocityControl.move(when, nullptr, &vscroll);
3500 mWheelXVelocityControl.move(when, &hscroll, nullptr);
3501
3502 // Send scroll.
3503 PointerCoords pointerCoords;
3504 pointerCoords.copyFrom(mPointerSimple.currentCoords);
3505 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
3506 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
3507
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003508 NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
3509 policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003510 mCurrentRawState.buttonState, MotionClassification::NONE,
3511 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
3512 &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
3513 xCursorPosition, yCursorPosition, mPointerSimple.downTime,
3514 /* videoFrames */ {});
3515 getListener()->notifyMotion(&args);
3516 }
3517
3518 // Save state.
3519 if (down || hovering) {
3520 mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords);
3521 mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties);
3522 } else {
3523 mPointerSimple.reset();
3524 }
3525}
3526
3527void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) {
3528 mPointerSimple.currentCoords.clear();
3529 mPointerSimple.currentProperties.clear();
3530
3531 dispatchPointerSimple(when, policyFlags, false, false);
3532}
3533
3534void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
3535 int32_t action, int32_t actionButton, int32_t flags,
3536 int32_t metaState, int32_t buttonState, int32_t edgeFlags,
3537 const PointerProperties* properties,
3538 const PointerCoords* coords, const uint32_t* idToIndex,
3539 BitSet32 idBits, int32_t changedId, float xPrecision,
3540 float yPrecision, nsecs_t downTime) {
3541 PointerCoords pointerCoords[MAX_POINTERS];
3542 PointerProperties pointerProperties[MAX_POINTERS];
3543 uint32_t pointerCount = 0;
3544 while (!idBits.isEmpty()) {
3545 uint32_t id = idBits.clearFirstMarkedBit();
3546 uint32_t index = idToIndex[id];
3547 pointerProperties[pointerCount].copyFrom(properties[index]);
3548 pointerCoords[pointerCount].copyFrom(coords[index]);
3549
3550 if (changedId >= 0 && id == uint32_t(changedId)) {
3551 action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
3552 }
3553
3554 pointerCount += 1;
3555 }
3556
3557 ALOG_ASSERT(pointerCount != 0);
3558
3559 if (changedId >= 0 && pointerCount == 1) {
3560 // Replace initial down and final up action.
3561 // We can compare the action without masking off the changed pointer index
3562 // because we know the index is 0.
3563 if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
3564 action = AMOTION_EVENT_ACTION_DOWN;
3565 } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
3566 action = AMOTION_EVENT_ACTION_UP;
3567 } else {
3568 // Can't happen.
3569 ALOG_ASSERT(false);
3570 }
3571 }
3572 float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
3573 float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
Michael Wright227c5542020-07-02 18:30:52 +01003574 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003575 mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
3576 }
3577 const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
3578 const int32_t deviceId = getDeviceId();
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -08003579 std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003580 std::for_each(frames.begin(), frames.end(),
3581 [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
Garfield Tanc51d1ba2020-01-28 13:24:04 -08003582 NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
3583 action, actionButton, flags, metaState, buttonState,
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003584 MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
3585 pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
3586 downTime, std::move(frames));
3587 getListener()->notifyMotion(&args);
3588}
3589
3590bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
3591 const PointerCoords* inCoords,
3592 const uint32_t* inIdToIndex,
3593 PointerProperties* outProperties,
3594 PointerCoords* outCoords, const uint32_t* outIdToIndex,
3595 BitSet32 idBits) const {
3596 bool changed = false;
3597 while (!idBits.isEmpty()) {
3598 uint32_t id = idBits.clearFirstMarkedBit();
3599 uint32_t inIndex = inIdToIndex[id];
3600 uint32_t outIndex = outIdToIndex[id];
3601
3602 const PointerProperties& curInProperties = inProperties[inIndex];
3603 const PointerCoords& curInCoords = inCoords[inIndex];
3604 PointerProperties& curOutProperties = outProperties[outIndex];
3605 PointerCoords& curOutCoords = outCoords[outIndex];
3606
3607 if (curInProperties != curOutProperties) {
3608 curOutProperties.copyFrom(curInProperties);
3609 changed = true;
3610 }
3611
3612 if (curInCoords != curOutCoords) {
3613 curOutCoords.copyFrom(curInCoords);
3614 changed = true;
3615 }
3616 }
3617 return changed;
3618}
3619
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003620void TouchInputMapper::cancelTouch(nsecs_t when) {
3621 abortPointerUsage(when, 0 /*policyFlags*/);
3622 abortTouches(when, 0 /* policyFlags*/);
3623}
3624
Arthur Hung4197f6b2020-03-16 15:39:59 +08003625// Transform raw coordinate to surface coordinate
Arthur Hung05de5772019-09-26 18:31:26 +08003626void TouchInputMapper::rotateAndScale(float& x, float& y) {
Arthur Hung4197f6b2020-03-16 15:39:59 +08003627 // Scale to surface coordinate.
3628 const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
3629 const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
3630
3631 // Rotate to surface coordinate.
3632 // 0 - no swap and reverse.
3633 // 90 - swap x/y and reverse y.
3634 // 180 - reverse x, y.
3635 // 270 - swap x/y and reverse x.
Arthur Hung05de5772019-09-26 18:31:26 +08003636 switch (mSurfaceOrientation) {
Arthur Hung4197f6b2020-03-16 15:39:59 +08003637 case DISPLAY_ORIENTATION_0:
3638 x = xScaled + mXTranslate;
3639 y = yScaled + mYTranslate;
3640 break;
Arthur Hung05de5772019-09-26 18:31:26 +08003641 case DISPLAY_ORIENTATION_90:
Arthur Hung4197f6b2020-03-16 15:39:59 +08003642 y = mSurfaceRight - xScaled;
3643 x = yScaled + mYTranslate;
Arthur Hung05de5772019-09-26 18:31:26 +08003644 break;
3645 case DISPLAY_ORIENTATION_180:
Arthur Hung4197f6b2020-03-16 15:39:59 +08003646 x = mSurfaceRight - xScaled;
3647 y = mSurfaceBottom - yScaled;
Arthur Hung05de5772019-09-26 18:31:26 +08003648 break;
3649 case DISPLAY_ORIENTATION_270:
Arthur Hung4197f6b2020-03-16 15:39:59 +08003650 y = xScaled + mXTranslate;
3651 x = mSurfaceBottom - yScaled;
Arthur Hung05de5772019-09-26 18:31:26 +08003652 break;
3653 default:
Arthur Hung4197f6b2020-03-16 15:39:59 +08003654 assert(false);
Arthur Hung05de5772019-09-26 18:31:26 +08003655 }
3656}
3657
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003658bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
Arthur Hung4197f6b2020-03-16 15:39:59 +08003659 const float xScaled = (x - mRawPointerAxes.x.minValue) * mXScale;
3660 const float yScaled = (y - mRawPointerAxes.y.minValue) * mYScale;
3661
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003662 return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
Arthur Hung4197f6b2020-03-16 15:39:59 +08003663 xScaled >= mSurfaceLeft && xScaled <= mSurfaceRight &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003664 y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
Arthur Hung4197f6b2020-03-16 15:39:59 +08003665 yScaled >= mSurfaceTop && yScaled <= mSurfaceBottom;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003666}
3667
3668const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
3669 for (const VirtualKey& virtualKey : mVirtualKeys) {
3670#if DEBUG_VIRTUAL_KEYS
3671 ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
3672 "left=%d, top=%d, right=%d, bottom=%d",
3673 x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, virtualKey.hitTop,
3674 virtualKey.hitRight, virtualKey.hitBottom);
3675#endif
3676
3677 if (virtualKey.isHit(x, y)) {
3678 return &virtualKey;
3679 }
3680 }
3681
3682 return nullptr;
3683}
3684
3685void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
3686 uint32_t currentPointerCount = current->rawPointerData.pointerCount;
3687 uint32_t lastPointerCount = last->rawPointerData.pointerCount;
3688
3689 current->rawPointerData.clearIdBits();
3690
3691 if (currentPointerCount == 0) {
3692 // No pointers to assign.
3693 return;
3694 }
3695
3696 if (lastPointerCount == 0) {
3697 // All pointers are new.
3698 for (uint32_t i = 0; i < currentPointerCount; i++) {
3699 uint32_t id = i;
3700 current->rawPointerData.pointers[i].id = id;
3701 current->rawPointerData.idToIndex[id] = i;
3702 current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i));
3703 }
3704 return;
3705 }
3706
3707 if (currentPointerCount == 1 && lastPointerCount == 1 &&
3708 current->rawPointerData.pointers[0].toolType == last->rawPointerData.pointers[0].toolType) {
3709 // Only one pointer and no change in count so it must have the same id as before.
3710 uint32_t id = last->rawPointerData.pointers[0].id;
3711 current->rawPointerData.pointers[0].id = id;
3712 current->rawPointerData.idToIndex[id] = 0;
3713 current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0));
3714 return;
3715 }
3716
3717 // General case.
3718 // We build a heap of squared euclidean distances between current and last pointers
3719 // associated with the current and last pointer indices. Then, we find the best
3720 // match (by distance) for each current pointer.
3721 // The pointers must have the same tool type but it is possible for them to
3722 // transition from hovering to touching or vice-versa while retaining the same id.
3723 PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
3724
3725 uint32_t heapSize = 0;
3726 for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
3727 currentPointerIndex++) {
3728 for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
3729 lastPointerIndex++) {
3730 const RawPointerData::Pointer& currentPointer =
3731 current->rawPointerData.pointers[currentPointerIndex];
3732 const RawPointerData::Pointer& lastPointer =
3733 last->rawPointerData.pointers[lastPointerIndex];
3734 if (currentPointer.toolType == lastPointer.toolType) {
3735 int64_t deltaX = currentPointer.x - lastPointer.x;
3736 int64_t deltaY = currentPointer.y - lastPointer.y;
3737
3738 uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
3739
3740 // Insert new element into the heap (sift up).
3741 heap[heapSize].currentPointerIndex = currentPointerIndex;
3742 heap[heapSize].lastPointerIndex = lastPointerIndex;
3743 heap[heapSize].distance = distance;
3744 heapSize += 1;
3745 }
3746 }
3747 }
3748
3749 // Heapify
3750 for (uint32_t startIndex = heapSize / 2; startIndex != 0;) {
3751 startIndex -= 1;
3752 for (uint32_t parentIndex = startIndex;;) {
3753 uint32_t childIndex = parentIndex * 2 + 1;
3754 if (childIndex >= heapSize) {
3755 break;
3756 }
3757
3758 if (childIndex + 1 < heapSize &&
3759 heap[childIndex + 1].distance < heap[childIndex].distance) {
3760 childIndex += 1;
3761 }
3762
3763 if (heap[parentIndex].distance <= heap[childIndex].distance) {
3764 break;
3765 }
3766
3767 swap(heap[parentIndex], heap[childIndex]);
3768 parentIndex = childIndex;
3769 }
3770 }
3771
3772#if DEBUG_POINTER_ASSIGNMENT
3773 ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize);
3774 for (size_t i = 0; i < heapSize; i++) {
3775 ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i,
3776 heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance);
3777 }
3778#endif
3779
3780 // Pull matches out by increasing order of distance.
3781 // To avoid reassigning pointers that have already been matched, the loop keeps track
3782 // of which last and current pointers have been matched using the matchedXXXBits variables.
3783 // It also tracks the used pointer id bits.
3784 BitSet32 matchedLastBits(0);
3785 BitSet32 matchedCurrentBits(0);
3786 BitSet32 usedIdBits(0);
3787 bool first = true;
3788 for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) {
3789 while (heapSize > 0) {
3790 if (first) {
3791 // The first time through the loop, we just consume the root element of
3792 // the heap (the one with smallest distance).
3793 first = false;
3794 } else {
3795 // Previous iterations consumed the root element of the heap.
3796 // Pop root element off of the heap (sift down).
3797 heap[0] = heap[heapSize];
3798 for (uint32_t parentIndex = 0;;) {
3799 uint32_t childIndex = parentIndex * 2 + 1;
3800 if (childIndex >= heapSize) {
3801 break;
3802 }
3803
3804 if (childIndex + 1 < heapSize &&
3805 heap[childIndex + 1].distance < heap[childIndex].distance) {
3806 childIndex += 1;
3807 }
3808
3809 if (heap[parentIndex].distance <= heap[childIndex].distance) {
3810 break;
3811 }
3812
3813 swap(heap[parentIndex], heap[childIndex]);
3814 parentIndex = childIndex;
3815 }
3816
3817#if DEBUG_POINTER_ASSIGNMENT
3818 ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
3819 for (size_t i = 0; i < heapSize; i++) {
3820 ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i,
3821 heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance);
3822 }
3823#endif
3824 }
3825
3826 heapSize -= 1;
3827
3828 uint32_t currentPointerIndex = heap[0].currentPointerIndex;
3829 if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
3830
3831 uint32_t lastPointerIndex = heap[0].lastPointerIndex;
3832 if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
3833
3834 matchedCurrentBits.markBit(currentPointerIndex);
3835 matchedLastBits.markBit(lastPointerIndex);
3836
3837 uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id;
3838 current->rawPointerData.pointers[currentPointerIndex].id = id;
3839 current->rawPointerData.idToIndex[id] = currentPointerIndex;
3840 current->rawPointerData.markIdBit(id,
3841 current->rawPointerData.isHovering(
3842 currentPointerIndex));
3843 usedIdBits.markBit(id);
3844
3845#if DEBUG_POINTER_ASSIGNMENT
3846 ALOGD("assignPointerIds - matched: cur=%" PRIu32 ", last=%" PRIu32 ", id=%" PRIu32
3847 ", distance=%" PRIu64,
3848 lastPointerIndex, currentPointerIndex, id, heap[0].distance);
3849#endif
3850 break;
3851 }
3852 }
3853
3854 // Assign fresh ids to pointers that were not matched in the process.
3855 for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) {
3856 uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit();
3857 uint32_t id = usedIdBits.markFirstUnmarkedBit();
3858
3859 current->rawPointerData.pointers[currentPointerIndex].id = id;
3860 current->rawPointerData.idToIndex[id] = currentPointerIndex;
3861 current->rawPointerData.markIdBit(id,
3862 current->rawPointerData.isHovering(currentPointerIndex));
3863
3864#if DEBUG_POINTER_ASSIGNMENT
3865 ALOGD("assignPointerIds - assigned: cur=%" PRIu32 ", id=%" PRIu32, currentPointerIndex, id);
3866#endif
3867 }
3868}
3869
3870int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
3871 if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
3872 return AKEY_STATE_VIRTUAL;
3873 }
3874
3875 for (const VirtualKey& virtualKey : mVirtualKeys) {
3876 if (virtualKey.keyCode == keyCode) {
3877 return AKEY_STATE_UP;
3878 }
3879 }
3880
3881 return AKEY_STATE_UNKNOWN;
3882}
3883
3884int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
3885 if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
3886 return AKEY_STATE_VIRTUAL;
3887 }
3888
3889 for (const VirtualKey& virtualKey : mVirtualKeys) {
3890 if (virtualKey.scanCode == scanCode) {
3891 return AKEY_STATE_UP;
3892 }
3893 }
3894
3895 return AKEY_STATE_UNKNOWN;
3896}
3897
3898bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
3899 const int32_t* keyCodes, uint8_t* outFlags) {
3900 for (const VirtualKey& virtualKey : mVirtualKeys) {
3901 for (size_t i = 0; i < numCodes; i++) {
3902 if (virtualKey.keyCode == keyCodes[i]) {
3903 outFlags[i] = 1;
3904 }
3905 }
3906 }
3907
3908 return true;
3909}
3910
3911std::optional<int32_t> TouchInputMapper::getAssociatedDisplayId() {
3912 if (mParameters.hasAssociatedDisplay) {
Michael Wright227c5542020-07-02 18:30:52 +01003913 if (mDeviceMode == DeviceMode::POINTER) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07003914 return std::make_optional(mPointerController->getDisplayId());
3915 } else {
3916 return std::make_optional(mViewport.displayId);
3917 }
3918 }
3919 return std::nullopt;
3920}
3921
3922} // namespace android