1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "UnwantedInteractionBlocker"
18*38e8c45fSAndroid Build Coastguard Worker #include "UnwantedInteractionBlocker.h"
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <com_android_input_flags.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <ftl/enum.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <input/PrintTools.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <linux/input-event-codes.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <linux/input.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <server_configurable_flags/get_flags.h>
28*38e8c45fSAndroid Build Coastguard Worker
29*38e8c45fSAndroid Build Coastguard Worker #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h"
30*38e8c45fSAndroid Build Coastguard Worker #include "ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h"
31*38e8c45fSAndroid Build Coastguard Worker
32*38e8c45fSAndroid Build Coastguard Worker namespace input_flags = com::android::input::flags;
33*38e8c45fSAndroid Build Coastguard Worker
34*38e8c45fSAndroid Build Coastguard Worker using android::base::StringPrintf;
35*38e8c45fSAndroid Build Coastguard Worker
36*38e8c45fSAndroid Build Coastguard Worker /**
37*38e8c45fSAndroid Build Coastguard Worker * This type is declared here to ensure consistency between the instantiated type (used in the
38*38e8c45fSAndroid Build Coastguard Worker * constructor via std::make_unique) and the cast-to type (used in PalmRejector::dump() with
39*38e8c45fSAndroid Build Coastguard Worker * static_cast). Due to the lack of rtti support, dynamic_cast is not available, so this can't be
40*38e8c45fSAndroid Build Coastguard Worker * checked at runtime to avoid undefined behaviour.
41*38e8c45fSAndroid Build Coastguard Worker */
42*38e8c45fSAndroid Build Coastguard Worker using PalmFilterImplementation = ::ui::NeuralStylusPalmDetectionFilter;
43*38e8c45fSAndroid Build Coastguard Worker
44*38e8c45fSAndroid Build Coastguard Worker namespace android {
45*38e8c45fSAndroid Build Coastguard Worker
46*38e8c45fSAndroid Build Coastguard Worker /**
47*38e8c45fSAndroid Build Coastguard Worker * Log detailed debug messages about each inbound motion event notification to the blocker.
48*38e8c45fSAndroid Build Coastguard Worker * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerInboundMotion DEBUG"
49*38e8c45fSAndroid Build Coastguard Worker * (requires restart)
50*38e8c45fSAndroid Build Coastguard Worker */
51*38e8c45fSAndroid Build Coastguard Worker const bool DEBUG_INBOUND_MOTION =
52*38e8c45fSAndroid Build Coastguard Worker __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundMotion", ANDROID_LOG_INFO);
53*38e8c45fSAndroid Build Coastguard Worker
54*38e8c45fSAndroid Build Coastguard Worker /**
55*38e8c45fSAndroid Build Coastguard Worker * Log detailed debug messages about each outbound motion event processed by the blocker.
56*38e8c45fSAndroid Build Coastguard Worker * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerOutboundMotion DEBUG"
57*38e8c45fSAndroid Build Coastguard Worker * (requires restart)
58*38e8c45fSAndroid Build Coastguard Worker */
59*38e8c45fSAndroid Build Coastguard Worker const bool DEBUG_OUTBOUND_MOTION =
60*38e8c45fSAndroid Build Coastguard Worker __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundMotion", ANDROID_LOG_INFO);
61*38e8c45fSAndroid Build Coastguard Worker
62*38e8c45fSAndroid Build Coastguard Worker /**
63*38e8c45fSAndroid Build Coastguard Worker * Log the data sent to the model and received back from the model.
64*38e8c45fSAndroid Build Coastguard Worker * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerModel DEBUG"
65*38e8c45fSAndroid Build Coastguard Worker * (requires restart)
66*38e8c45fSAndroid Build Coastguard Worker */
67*38e8c45fSAndroid Build Coastguard Worker const bool DEBUG_MODEL =
68*38e8c45fSAndroid Build Coastguard Worker __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Model", ANDROID_LOG_INFO);
69*38e8c45fSAndroid Build Coastguard Worker
70*38e8c45fSAndroid Build Coastguard Worker /**
71*38e8c45fSAndroid Build Coastguard Worker * When multi-device input is enabled, we shouldn't use PreferStylusOverTouchBlocker at all.
72*38e8c45fSAndroid Build Coastguard Worker * However, multi-device input has the following default behaviour: hovering stylus rejects touch.
73*38e8c45fSAndroid Build Coastguard Worker * Therefore, if we want to disable that behaviour (and go back to a place where stylus down
74*38e8c45fSAndroid Build Coastguard Worker * blocks touch, but hovering stylus doesn't interact with touch), we should just disable the entire
75*38e8c45fSAndroid Build Coastguard Worker * multi-device input feature.
76*38e8c45fSAndroid Build Coastguard Worker */
77*38e8c45fSAndroid Build Coastguard Worker const bool ENABLE_MULTI_DEVICE_INPUT = input_flags::enable_multi_device_input() &&
78*38e8c45fSAndroid Build Coastguard Worker !input_flags::disable_reject_touch_on_stylus_hover();
79*38e8c45fSAndroid Build Coastguard Worker
80*38e8c45fSAndroid Build Coastguard Worker // Category (=namespace) name for the input settings that are applied at boot time
81*38e8c45fSAndroid Build Coastguard Worker static const char* INPUT_NATIVE_BOOT = "input_native_boot";
82*38e8c45fSAndroid Build Coastguard Worker /**
83*38e8c45fSAndroid Build Coastguard Worker * Feature flag name. This flag determines whether palm rejection is enabled. To enable, specify
84*38e8c45fSAndroid Build Coastguard Worker * 'true' (not case sensitive) or '1'. To disable, specify any other value.
85*38e8c45fSAndroid Build Coastguard Worker */
86*38e8c45fSAndroid Build Coastguard Worker static const char* PALM_REJECTION_ENABLED = "palm_rejection_enabled";
87*38e8c45fSAndroid Build Coastguard Worker
toLower(std::string s)88*38e8c45fSAndroid Build Coastguard Worker static std::string toLower(std::string s) {
89*38e8c45fSAndroid Build Coastguard Worker std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
90*38e8c45fSAndroid Build Coastguard Worker return s;
91*38e8c45fSAndroid Build Coastguard Worker }
92*38e8c45fSAndroid Build Coastguard Worker
isFromTouchscreen(int32_t source)93*38e8c45fSAndroid Build Coastguard Worker static bool isFromTouchscreen(int32_t source) {
94*38e8c45fSAndroid Build Coastguard Worker return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN);
95*38e8c45fSAndroid Build Coastguard Worker }
96*38e8c45fSAndroid Build Coastguard Worker
toChromeTimestamp(nsecs_t eventTime)97*38e8c45fSAndroid Build Coastguard Worker static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
98*38e8c45fSAndroid Build Coastguard Worker return ::base::TimeTicks::UnixEpoch() + ::base::TimeDelta::FromNanosecondsD(eventTime);
99*38e8c45fSAndroid Build Coastguard Worker }
100*38e8c45fSAndroid Build Coastguard Worker
101*38e8c45fSAndroid Build Coastguard Worker /**
102*38e8c45fSAndroid Build Coastguard Worker * Return true if palm rejection is enabled via the server configurable flags. Return false
103*38e8c45fSAndroid Build Coastguard Worker * otherwise.
104*38e8c45fSAndroid Build Coastguard Worker */
isPalmRejectionEnabled()105*38e8c45fSAndroid Build Coastguard Worker static bool isPalmRejectionEnabled() {
106*38e8c45fSAndroid Build Coastguard Worker std::string value = toLower(
107*38e8c45fSAndroid Build Coastguard Worker server_configurable_flags::GetServerConfigurableFlag(INPUT_NATIVE_BOOT,
108*38e8c45fSAndroid Build Coastguard Worker PALM_REJECTION_ENABLED, "0"));
109*38e8c45fSAndroid Build Coastguard Worker if (value == "1") {
110*38e8c45fSAndroid Build Coastguard Worker return true;
111*38e8c45fSAndroid Build Coastguard Worker }
112*38e8c45fSAndroid Build Coastguard Worker return false;
113*38e8c45fSAndroid Build Coastguard Worker }
114*38e8c45fSAndroid Build Coastguard Worker
getLinuxToolCode(ToolType toolType)115*38e8c45fSAndroid Build Coastguard Worker static int getLinuxToolCode(ToolType toolType) {
116*38e8c45fSAndroid Build Coastguard Worker switch (toolType) {
117*38e8c45fSAndroid Build Coastguard Worker case ToolType::STYLUS:
118*38e8c45fSAndroid Build Coastguard Worker return BTN_TOOL_PEN;
119*38e8c45fSAndroid Build Coastguard Worker case ToolType::ERASER:
120*38e8c45fSAndroid Build Coastguard Worker return BTN_TOOL_RUBBER;
121*38e8c45fSAndroid Build Coastguard Worker case ToolType::FINGER:
122*38e8c45fSAndroid Build Coastguard Worker return BTN_TOOL_FINGER;
123*38e8c45fSAndroid Build Coastguard Worker case ToolType::UNKNOWN:
124*38e8c45fSAndroid Build Coastguard Worker case ToolType::MOUSE:
125*38e8c45fSAndroid Build Coastguard Worker case ToolType::PALM:
126*38e8c45fSAndroid Build Coastguard Worker break;
127*38e8c45fSAndroid Build Coastguard Worker }
128*38e8c45fSAndroid Build Coastguard Worker ALOGW("Got tool type %s, converting to BTN_TOOL_FINGER", ftl::enum_string(toolType).c_str());
129*38e8c45fSAndroid Build Coastguard Worker return BTN_TOOL_FINGER;
130*38e8c45fSAndroid Build Coastguard Worker }
131*38e8c45fSAndroid Build Coastguard Worker
getActionUpForPointerId(const NotifyMotionArgs & args,int32_t pointerId)132*38e8c45fSAndroid Build Coastguard Worker static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) {
133*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < args.getPointerCount(); i++) {
134*38e8c45fSAndroid Build Coastguard Worker if (pointerId == args.pointerProperties[i].id) {
135*38e8c45fSAndroid Build Coastguard Worker return AMOTION_EVENT_ACTION_POINTER_UP |
136*38e8c45fSAndroid Build Coastguard Worker (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
137*38e8c45fSAndroid Build Coastguard Worker }
138*38e8c45fSAndroid Build Coastguard Worker }
139*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("Can't find pointerId %" PRId32 " in %s", pointerId, args.dump().c_str());
140*38e8c45fSAndroid Build Coastguard Worker }
141*38e8c45fSAndroid Build Coastguard Worker
142*38e8c45fSAndroid Build Coastguard Worker /**
143*38e8c45fSAndroid Build Coastguard Worker * Find the action for individual pointer at the given pointer index.
144*38e8c45fSAndroid Build Coastguard Worker * This is always equal to MotionEvent::getActionMasked, except for
145*38e8c45fSAndroid Build Coastguard Worker * POINTER_UP or POINTER_DOWN events. For example, in a POINTER_UP event, the action for
146*38e8c45fSAndroid Build Coastguard Worker * the active pointer is ACTION_POINTER_UP, while the action for the other pointers is ACTION_MOVE.
147*38e8c45fSAndroid Build Coastguard Worker */
resolveActionForPointer(uint8_t pointerIndex,int32_t action)148*38e8c45fSAndroid Build Coastguard Worker static int32_t resolveActionForPointer(uint8_t pointerIndex, int32_t action) {
149*38e8c45fSAndroid Build Coastguard Worker const int32_t actionMasked = MotionEvent::getActionMasked(action);
150*38e8c45fSAndroid Build Coastguard Worker if (actionMasked != AMOTION_EVENT_ACTION_POINTER_DOWN &&
151*38e8c45fSAndroid Build Coastguard Worker actionMasked != AMOTION_EVENT_ACTION_POINTER_UP) {
152*38e8c45fSAndroid Build Coastguard Worker return actionMasked;
153*38e8c45fSAndroid Build Coastguard Worker }
154*38e8c45fSAndroid Build Coastguard Worker // This is a POINTER_DOWN or POINTER_UP event
155*38e8c45fSAndroid Build Coastguard Worker const uint8_t actionIndex = MotionEvent::getActionIndex(action);
156*38e8c45fSAndroid Build Coastguard Worker if (pointerIndex == actionIndex) {
157*38e8c45fSAndroid Build Coastguard Worker return actionMasked;
158*38e8c45fSAndroid Build Coastguard Worker }
159*38e8c45fSAndroid Build Coastguard Worker // When POINTER_DOWN or POINTER_UP happens, it's actually a MOVE for all of the other
160*38e8c45fSAndroid Build Coastguard Worker // pointers
161*38e8c45fSAndroid Build Coastguard Worker return AMOTION_EVENT_ACTION_MOVE;
162*38e8c45fSAndroid Build Coastguard Worker }
163*38e8c45fSAndroid Build Coastguard Worker
removePointerIds(const NotifyMotionArgs & args,const std::set<int32_t> & pointerIds)164*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
165*38e8c45fSAndroid Build Coastguard Worker const std::set<int32_t>& pointerIds) {
166*38e8c45fSAndroid Build Coastguard Worker const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
167*38e8c45fSAndroid Build Coastguard Worker const int32_t actionMasked = MotionEvent::getActionMasked(args.action);
168*38e8c45fSAndroid Build Coastguard Worker const bool isPointerUpOrDownAction = actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN ||
169*38e8c45fSAndroid Build Coastguard Worker actionMasked == AMOTION_EVENT_ACTION_POINTER_UP;
170*38e8c45fSAndroid Build Coastguard Worker
171*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs newArgs{args};
172*38e8c45fSAndroid Build Coastguard Worker newArgs.pointerProperties.clear();
173*38e8c45fSAndroid Build Coastguard Worker newArgs.pointerCoords.clear();
174*38e8c45fSAndroid Build Coastguard Worker int32_t newActionIndex = 0;
175*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < args.getPointerCount(); i++) {
176*38e8c45fSAndroid Build Coastguard Worker const int32_t pointerId = args.pointerProperties[i].id;
177*38e8c45fSAndroid Build Coastguard Worker if (pointerIds.find(pointerId) != pointerIds.end()) {
178*38e8c45fSAndroid Build Coastguard Worker // skip this pointer
179*38e8c45fSAndroid Build Coastguard Worker if (isPointerUpOrDownAction && i == actionIndex) {
180*38e8c45fSAndroid Build Coastguard Worker // The active pointer is being removed, so the action is no longer valid.
181*38e8c45fSAndroid Build Coastguard Worker // Set the action to 'UNKNOWN' here. The caller is responsible for updating this
182*38e8c45fSAndroid Build Coastguard Worker // action later to a proper value.
183*38e8c45fSAndroid Build Coastguard Worker newArgs.action = ACTION_UNKNOWN;
184*38e8c45fSAndroid Build Coastguard Worker }
185*38e8c45fSAndroid Build Coastguard Worker continue;
186*38e8c45fSAndroid Build Coastguard Worker }
187*38e8c45fSAndroid Build Coastguard Worker newArgs.pointerProperties.push_back(args.pointerProperties[i]);
188*38e8c45fSAndroid Build Coastguard Worker newArgs.pointerCoords.push_back(args.pointerCoords[i]);
189*38e8c45fSAndroid Build Coastguard Worker if (i == actionIndex) {
190*38e8c45fSAndroid Build Coastguard Worker newActionIndex = newArgs.getPointerCount() - 1;
191*38e8c45fSAndroid Build Coastguard Worker }
192*38e8c45fSAndroid Build Coastguard Worker }
193*38e8c45fSAndroid Build Coastguard Worker // Update POINTER_DOWN or POINTER_UP actions
194*38e8c45fSAndroid Build Coastguard Worker if (isPointerUpOrDownAction && newArgs.action != ACTION_UNKNOWN) {
195*38e8c45fSAndroid Build Coastguard Worker newArgs.action =
196*38e8c45fSAndroid Build Coastguard Worker actionMasked | (newActionIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
197*38e8c45fSAndroid Build Coastguard Worker // Convert POINTER_DOWN and POINTER_UP to DOWN and UP if there's only 1 pointer remaining
198*38e8c45fSAndroid Build Coastguard Worker if (newArgs.getPointerCount() == 1) {
199*38e8c45fSAndroid Build Coastguard Worker if (actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN) {
200*38e8c45fSAndroid Build Coastguard Worker newArgs.action = AMOTION_EVENT_ACTION_DOWN;
201*38e8c45fSAndroid Build Coastguard Worker } else if (actionMasked == AMOTION_EVENT_ACTION_POINTER_UP) {
202*38e8c45fSAndroid Build Coastguard Worker newArgs.action = AMOTION_EVENT_ACTION_UP;
203*38e8c45fSAndroid Build Coastguard Worker }
204*38e8c45fSAndroid Build Coastguard Worker }
205*38e8c45fSAndroid Build Coastguard Worker }
206*38e8c45fSAndroid Build Coastguard Worker return newArgs;
207*38e8c45fSAndroid Build Coastguard Worker }
208*38e8c45fSAndroid Build Coastguard Worker
209*38e8c45fSAndroid Build Coastguard Worker /**
210*38e8c45fSAndroid Build Coastguard Worker * Remove stylus pointers from the provided NotifyMotionArgs.
211*38e8c45fSAndroid Build Coastguard Worker *
212*38e8c45fSAndroid Build Coastguard Worker * Return NotifyMotionArgs where the stylus pointers have been removed.
213*38e8c45fSAndroid Build Coastguard Worker * If this results in removal of the active pointer, then return nullopt.
214*38e8c45fSAndroid Build Coastguard Worker */
removeStylusPointerIds(const NotifyMotionArgs & args)215*38e8c45fSAndroid Build Coastguard Worker static std::optional<NotifyMotionArgs> removeStylusPointerIds(const NotifyMotionArgs& args) {
216*38e8c45fSAndroid Build Coastguard Worker std::set<int32_t> stylusPointerIds;
217*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < args.getPointerCount(); i++) {
218*38e8c45fSAndroid Build Coastguard Worker if (isStylusToolType(args.pointerProperties[i].toolType)) {
219*38e8c45fSAndroid Build Coastguard Worker stylusPointerIds.insert(args.pointerProperties[i].id);
220*38e8c45fSAndroid Build Coastguard Worker }
221*38e8c45fSAndroid Build Coastguard Worker }
222*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs withoutStylusPointers = removePointerIds(args, stylusPointerIds);
223*38e8c45fSAndroid Build Coastguard Worker if (withoutStylusPointers.getPointerCount() == 0 ||
224*38e8c45fSAndroid Build Coastguard Worker withoutStylusPointers.action == ACTION_UNKNOWN) {
225*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
226*38e8c45fSAndroid Build Coastguard Worker }
227*38e8c45fSAndroid Build Coastguard Worker return withoutStylusPointers;
228*38e8c45fSAndroid Build Coastguard Worker }
229*38e8c45fSAndroid Build Coastguard Worker
createPalmFilterDeviceInfo(const InputDeviceInfo & deviceInfo)230*38e8c45fSAndroid Build Coastguard Worker std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(
231*38e8c45fSAndroid Build Coastguard Worker const InputDeviceInfo& deviceInfo) {
232*38e8c45fSAndroid Build Coastguard Worker if (!isFromTouchscreen(deviceInfo.getSources())) {
233*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
234*38e8c45fSAndroid Build Coastguard Worker }
235*38e8c45fSAndroid Build Coastguard Worker AndroidPalmFilterDeviceInfo out;
236*38e8c45fSAndroid Build Coastguard Worker const InputDeviceInfo::MotionRange* axisX =
237*38e8c45fSAndroid Build Coastguard Worker deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN);
238*38e8c45fSAndroid Build Coastguard Worker if (axisX != nullptr) {
239*38e8c45fSAndroid Build Coastguard Worker out.max_x = axisX->max;
240*38e8c45fSAndroid Build Coastguard Worker out.x_res = axisX->resolution;
241*38e8c45fSAndroid Build Coastguard Worker } else {
242*38e8c45fSAndroid Build Coastguard Worker ALOGW("Palm rejection is disabled for %s because AXIS_X is not supported",
243*38e8c45fSAndroid Build Coastguard Worker deviceInfo.getDisplayName().c_str());
244*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
245*38e8c45fSAndroid Build Coastguard Worker }
246*38e8c45fSAndroid Build Coastguard Worker const InputDeviceInfo::MotionRange* axisY =
247*38e8c45fSAndroid Build Coastguard Worker deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN);
248*38e8c45fSAndroid Build Coastguard Worker if (axisY != nullptr) {
249*38e8c45fSAndroid Build Coastguard Worker out.max_y = axisY->max;
250*38e8c45fSAndroid Build Coastguard Worker out.y_res = axisY->resolution;
251*38e8c45fSAndroid Build Coastguard Worker } else {
252*38e8c45fSAndroid Build Coastguard Worker ALOGW("Palm rejection is disabled for %s because AXIS_Y is not supported",
253*38e8c45fSAndroid Build Coastguard Worker deviceInfo.getDisplayName().c_str());
254*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
255*38e8c45fSAndroid Build Coastguard Worker }
256*38e8c45fSAndroid Build Coastguard Worker const InputDeviceInfo::MotionRange* axisMajor =
257*38e8c45fSAndroid Build Coastguard Worker deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, AINPUT_SOURCE_TOUCHSCREEN);
258*38e8c45fSAndroid Build Coastguard Worker if (axisMajor != nullptr) {
259*38e8c45fSAndroid Build Coastguard Worker out.major_radius_res = axisMajor->resolution;
260*38e8c45fSAndroid Build Coastguard Worker out.touch_major_res = axisMajor->resolution;
261*38e8c45fSAndroid Build Coastguard Worker } else {
262*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
263*38e8c45fSAndroid Build Coastguard Worker }
264*38e8c45fSAndroid Build Coastguard Worker const InputDeviceInfo::MotionRange* axisMinor =
265*38e8c45fSAndroid Build Coastguard Worker deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR, AINPUT_SOURCE_TOUCHSCREEN);
266*38e8c45fSAndroid Build Coastguard Worker if (axisMinor != nullptr) {
267*38e8c45fSAndroid Build Coastguard Worker out.minor_radius_res = axisMinor->resolution;
268*38e8c45fSAndroid Build Coastguard Worker out.touch_minor_res = axisMinor->resolution;
269*38e8c45fSAndroid Build Coastguard Worker out.minor_radius_supported = true;
270*38e8c45fSAndroid Build Coastguard Worker } else {
271*38e8c45fSAndroid Build Coastguard Worker out.minor_radius_supported = false;
272*38e8c45fSAndroid Build Coastguard Worker }
273*38e8c45fSAndroid Build Coastguard Worker
274*38e8c45fSAndroid Build Coastguard Worker return out;
275*38e8c45fSAndroid Build Coastguard Worker }
276*38e8c45fSAndroid Build Coastguard Worker
277*38e8c45fSAndroid Build Coastguard Worker /**
278*38e8c45fSAndroid Build Coastguard Worker * Synthesize CANCEL events for any new pointers that should be canceled, while removing pointers
279*38e8c45fSAndroid Build Coastguard Worker * that have already been canceled.
280*38e8c45fSAndroid Build Coastguard Worker * The flow of the function is as follows:
281*38e8c45fSAndroid Build Coastguard Worker * 1. Remove all already canceled pointers
282*38e8c45fSAndroid Build Coastguard Worker * 2. Cancel all newly suppressed pointers
283*38e8c45fSAndroid Build Coastguard Worker * 3. Decide what to do with the current event : keep it, or drop it
284*38e8c45fSAndroid Build Coastguard Worker * The pointers can never be "unsuppressed": once a pointer is canceled, it will never become valid.
285*38e8c45fSAndroid Build Coastguard Worker */
cancelSuppressedPointers(const NotifyMotionArgs & args,const std::set<int32_t> & oldSuppressedPointerIds,const std::set<int32_t> & newSuppressedPointerIds)286*38e8c45fSAndroid Build Coastguard Worker std::vector<NotifyMotionArgs> cancelSuppressedPointers(
287*38e8c45fSAndroid Build Coastguard Worker const NotifyMotionArgs& args, const std::set<int32_t>& oldSuppressedPointerIds,
288*38e8c45fSAndroid Build Coastguard Worker const std::set<int32_t>& newSuppressedPointerIds) {
289*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(args.getPointerCount() == 0, "0 pointers in %s", args.dump().c_str());
290*38e8c45fSAndroid Build Coastguard Worker
291*38e8c45fSAndroid Build Coastguard Worker // First, let's remove the old suppressed pointers. They've already been canceled previously.
292*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs oldArgs = removePointerIds(args, oldSuppressedPointerIds);
293*38e8c45fSAndroid Build Coastguard Worker
294*38e8c45fSAndroid Build Coastguard Worker // Cancel any newly suppressed pointers.
295*38e8c45fSAndroid Build Coastguard Worker std::vector<NotifyMotionArgs> out;
296*38e8c45fSAndroid Build Coastguard Worker const int32_t activePointerId =
297*38e8c45fSAndroid Build Coastguard Worker args.pointerProperties[MotionEvent::getActionIndex(args.action)].id;
298*38e8c45fSAndroid Build Coastguard Worker const int32_t actionMasked = MotionEvent::getActionMasked(args.action);
299*38e8c45fSAndroid Build Coastguard Worker // We will iteratively remove pointers from 'removedArgs'.
300*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs removedArgs{oldArgs};
301*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < oldArgs.getPointerCount(); i++) {
302*38e8c45fSAndroid Build Coastguard Worker const int32_t pointerId = oldArgs.pointerProperties[i].id;
303*38e8c45fSAndroid Build Coastguard Worker if (newSuppressedPointerIds.find(pointerId) == newSuppressedPointerIds.end()) {
304*38e8c45fSAndroid Build Coastguard Worker // This is a pointer that should not be canceled. Move on.
305*38e8c45fSAndroid Build Coastguard Worker continue;
306*38e8c45fSAndroid Build Coastguard Worker }
307*38e8c45fSAndroid Build Coastguard Worker if (pointerId == activePointerId && actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN) {
308*38e8c45fSAndroid Build Coastguard Worker // Remove this pointer, but don't cancel it. We'll just not send the POINTER_DOWN event
309*38e8c45fSAndroid Build Coastguard Worker removedArgs = removePointerIds(removedArgs, {pointerId});
310*38e8c45fSAndroid Build Coastguard Worker continue;
311*38e8c45fSAndroid Build Coastguard Worker }
312*38e8c45fSAndroid Build Coastguard Worker
313*38e8c45fSAndroid Build Coastguard Worker if (removedArgs.getPointerCount() == 1) {
314*38e8c45fSAndroid Build Coastguard Worker // We are about to remove the last pointer, which means there will be no more gesture
315*38e8c45fSAndroid Build Coastguard Worker // remaining. This is identical to canceling all pointers, so just send a single CANCEL
316*38e8c45fSAndroid Build Coastguard Worker // event, without any of the preceding POINTER_UP with FLAG_CANCELED events.
317*38e8c45fSAndroid Build Coastguard Worker oldArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
318*38e8c45fSAndroid Build Coastguard Worker oldArgs.action = AMOTION_EVENT_ACTION_CANCEL;
319*38e8c45fSAndroid Build Coastguard Worker return {oldArgs};
320*38e8c45fSAndroid Build Coastguard Worker }
321*38e8c45fSAndroid Build Coastguard Worker // Cancel the current pointer
322*38e8c45fSAndroid Build Coastguard Worker out.push_back(removedArgs);
323*38e8c45fSAndroid Build Coastguard Worker out.back().flags |= AMOTION_EVENT_FLAG_CANCELED;
324*38e8c45fSAndroid Build Coastguard Worker out.back().action = getActionUpForPointerId(out.back(), pointerId);
325*38e8c45fSAndroid Build Coastguard Worker
326*38e8c45fSAndroid Build Coastguard Worker // Remove the newly canceled pointer from the args
327*38e8c45fSAndroid Build Coastguard Worker removedArgs = removePointerIds(removedArgs, {pointerId});
328*38e8c45fSAndroid Build Coastguard Worker }
329*38e8c45fSAndroid Build Coastguard Worker
330*38e8c45fSAndroid Build Coastguard Worker // Now 'removedArgs' contains only pointers that are valid.
331*38e8c45fSAndroid Build Coastguard Worker if (removedArgs.getPointerCount() <= 0 || removedArgs.action == ACTION_UNKNOWN) {
332*38e8c45fSAndroid Build Coastguard Worker return out;
333*38e8c45fSAndroid Build Coastguard Worker }
334*38e8c45fSAndroid Build Coastguard Worker out.push_back(removedArgs);
335*38e8c45fSAndroid Build Coastguard Worker return out;
336*38e8c45fSAndroid Build Coastguard Worker }
337*38e8c45fSAndroid Build Coastguard Worker
UnwantedInteractionBlocker(InputListenerInterface & listener)338*38e8c45fSAndroid Build Coastguard Worker UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener)
339*38e8c45fSAndroid Build Coastguard Worker : UnwantedInteractionBlocker(listener, isPalmRejectionEnabled()){};
340*38e8c45fSAndroid Build Coastguard Worker
UnwantedInteractionBlocker(InputListenerInterface & listener,bool enablePalmRejection)341*38e8c45fSAndroid Build Coastguard Worker UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener,
342*38e8c45fSAndroid Build Coastguard Worker bool enablePalmRejection)
343*38e8c45fSAndroid Build Coastguard Worker : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {}
344*38e8c45fSAndroid Build Coastguard Worker
notifyKey(const NotifyKeyArgs & args)345*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs& args) {
346*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyKey(args);
347*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
348*38e8c45fSAndroid Build Coastguard Worker }
349*38e8c45fSAndroid Build Coastguard Worker
notifyMotion(const NotifyMotionArgs & args)350*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs& args) {
351*38e8c45fSAndroid Build Coastguard Worker ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args.dump().c_str());
352*38e8c45fSAndroid Build Coastguard Worker { // acquire lock
353*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
354*38e8c45fSAndroid Build Coastguard Worker if (ENABLE_MULTI_DEVICE_INPUT) {
355*38e8c45fSAndroid Build Coastguard Worker notifyMotionLocked(args);
356*38e8c45fSAndroid Build Coastguard Worker } else {
357*38e8c45fSAndroid Build Coastguard Worker const std::vector<NotifyMotionArgs> processedArgs =
358*38e8c45fSAndroid Build Coastguard Worker mPreferStylusOverTouchBlocker.processMotion(args);
359*38e8c45fSAndroid Build Coastguard Worker for (const NotifyMotionArgs& loopArgs : processedArgs) {
360*38e8c45fSAndroid Build Coastguard Worker notifyMotionLocked(loopArgs);
361*38e8c45fSAndroid Build Coastguard Worker }
362*38e8c45fSAndroid Build Coastguard Worker }
363*38e8c45fSAndroid Build Coastguard Worker } // release lock
364*38e8c45fSAndroid Build Coastguard Worker
365*38e8c45fSAndroid Build Coastguard Worker // Call out to the next stage without holding the lock
366*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
367*38e8c45fSAndroid Build Coastguard Worker }
368*38e8c45fSAndroid Build Coastguard Worker
enqueueOutboundMotionLocked(const NotifyMotionArgs & args)369*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::enqueueOutboundMotionLocked(const NotifyMotionArgs& args) {
370*38e8c45fSAndroid Build Coastguard Worker ALOGD_IF(DEBUG_OUTBOUND_MOTION, "%s: %s", __func__, args.dump().c_str());
371*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyMotion(args);
372*38e8c45fSAndroid Build Coastguard Worker }
373*38e8c45fSAndroid Build Coastguard Worker
notifyMotionLocked(const NotifyMotionArgs & args)374*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs& args) {
375*38e8c45fSAndroid Build Coastguard Worker auto it = mPalmRejectors.find(args.deviceId);
376*38e8c45fSAndroid Build Coastguard Worker const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args.source);
377*38e8c45fSAndroid Build Coastguard Worker if (!sendToPalmRejector) {
378*38e8c45fSAndroid Build Coastguard Worker enqueueOutboundMotionLocked(args);
379*38e8c45fSAndroid Build Coastguard Worker return;
380*38e8c45fSAndroid Build Coastguard Worker }
381*38e8c45fSAndroid Build Coastguard Worker
382*38e8c45fSAndroid Build Coastguard Worker std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(args);
383*38e8c45fSAndroid Build Coastguard Worker for (const NotifyMotionArgs& loopArgs : processedArgs) {
384*38e8c45fSAndroid Build Coastguard Worker enqueueOutboundMotionLocked(loopArgs);
385*38e8c45fSAndroid Build Coastguard Worker }
386*38e8c45fSAndroid Build Coastguard Worker }
387*38e8c45fSAndroid Build Coastguard Worker
notifySwitch(const NotifySwitchArgs & args)388*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs& args) {
389*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifySwitch(args);
390*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
391*38e8c45fSAndroid Build Coastguard Worker }
392*38e8c45fSAndroid Build Coastguard Worker
notifySensor(const NotifySensorArgs & args)393*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs& args) {
394*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifySensor(args);
395*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
396*38e8c45fSAndroid Build Coastguard Worker }
397*38e8c45fSAndroid Build Coastguard Worker
notifyVibratorState(const NotifyVibratorStateArgs & args)398*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs& args) {
399*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyVibratorState(args);
400*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
401*38e8c45fSAndroid Build Coastguard Worker }
notifyDeviceReset(const NotifyDeviceResetArgs & args)402*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
403*38e8c45fSAndroid Build Coastguard Worker { // acquire lock
404*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
405*38e8c45fSAndroid Build Coastguard Worker auto it = mPalmRejectors.find(args.deviceId);
406*38e8c45fSAndroid Build Coastguard Worker if (it != mPalmRejectors.end()) {
407*38e8c45fSAndroid Build Coastguard Worker AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
408*38e8c45fSAndroid Build Coastguard Worker // Re-create the object instead of resetting it
409*38e8c45fSAndroid Build Coastguard Worker mPalmRejectors.erase(it);
410*38e8c45fSAndroid Build Coastguard Worker mPalmRejectors.emplace(args.deviceId, info);
411*38e8c45fSAndroid Build Coastguard Worker }
412*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyDeviceReset(args);
413*38e8c45fSAndroid Build Coastguard Worker mPreferStylusOverTouchBlocker.notifyDeviceReset(args);
414*38e8c45fSAndroid Build Coastguard Worker } // release lock
415*38e8c45fSAndroid Build Coastguard Worker // Send events to the next stage without holding the lock
416*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
417*38e8c45fSAndroid Build Coastguard Worker }
418*38e8c45fSAndroid Build Coastguard Worker
notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs & args)419*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
420*38e8c45fSAndroid Build Coastguard Worker const NotifyPointerCaptureChangedArgs& args) {
421*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyPointerCaptureChanged(args);
422*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
423*38e8c45fSAndroid Build Coastguard Worker }
424*38e8c45fSAndroid Build Coastguard Worker
notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs & args)425*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::notifyInputDevicesChanged(
426*38e8c45fSAndroid Build Coastguard Worker const NotifyInputDevicesChangedArgs& args) {
427*38e8c45fSAndroid Build Coastguard Worker onInputDevicesChanged(args.inputDeviceInfos);
428*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notify(args);
429*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
430*38e8c45fSAndroid Build Coastguard Worker }
431*38e8c45fSAndroid Build Coastguard Worker
onInputDevicesChanged(const std::vector<InputDeviceInfo> & inputDevices)432*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::onInputDevicesChanged(
433*38e8c45fSAndroid Build Coastguard Worker const std::vector<InputDeviceInfo>& inputDevices) {
434*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
435*38e8c45fSAndroid Build Coastguard Worker if (!mEnablePalmRejection) {
436*38e8c45fSAndroid Build Coastguard Worker // Palm rejection is disabled. Don't create any palm rejector objects.
437*38e8c45fSAndroid Build Coastguard Worker return;
438*38e8c45fSAndroid Build Coastguard Worker }
439*38e8c45fSAndroid Build Coastguard Worker
440*38e8c45fSAndroid Build Coastguard Worker // Let's see which of the existing devices didn't change, so that we can keep them
441*38e8c45fSAndroid Build Coastguard Worker // and prevent event stream disruption
442*38e8c45fSAndroid Build Coastguard Worker std::set<int32_t /*deviceId*/> devicesToKeep;
443*38e8c45fSAndroid Build Coastguard Worker for (const InputDeviceInfo& device : inputDevices) {
444*38e8c45fSAndroid Build Coastguard Worker std::optional<AndroidPalmFilterDeviceInfo> info = createPalmFilterDeviceInfo(device);
445*38e8c45fSAndroid Build Coastguard Worker if (!info) {
446*38e8c45fSAndroid Build Coastguard Worker continue;
447*38e8c45fSAndroid Build Coastguard Worker }
448*38e8c45fSAndroid Build Coastguard Worker
449*38e8c45fSAndroid Build Coastguard Worker auto [it, emplaced] = mPalmRejectors.try_emplace(device.getId(), *info);
450*38e8c45fSAndroid Build Coastguard Worker if (!emplaced && *info != it->second.getPalmFilterDeviceInfo()) {
451*38e8c45fSAndroid Build Coastguard Worker // Re-create the PalmRejector because the device info has changed.
452*38e8c45fSAndroid Build Coastguard Worker mPalmRejectors.erase(it);
453*38e8c45fSAndroid Build Coastguard Worker mPalmRejectors.emplace(device.getId(), *info);
454*38e8c45fSAndroid Build Coastguard Worker }
455*38e8c45fSAndroid Build Coastguard Worker devicesToKeep.insert(device.getId());
456*38e8c45fSAndroid Build Coastguard Worker }
457*38e8c45fSAndroid Build Coastguard Worker // Delete all devices that we don't need to keep
458*38e8c45fSAndroid Build Coastguard Worker std::erase_if(mPalmRejectors, [&devicesToKeep](const auto& item) {
459*38e8c45fSAndroid Build Coastguard Worker auto const& [deviceId, _] = item;
460*38e8c45fSAndroid Build Coastguard Worker return devicesToKeep.find(deviceId) == devicesToKeep.end();
461*38e8c45fSAndroid Build Coastguard Worker });
462*38e8c45fSAndroid Build Coastguard Worker mPreferStylusOverTouchBlocker.notifyInputDevicesChanged(inputDevices);
463*38e8c45fSAndroid Build Coastguard Worker }
464*38e8c45fSAndroid Build Coastguard Worker
dump(std::string & dump)465*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::dump(std::string& dump) {
466*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
467*38e8c45fSAndroid Build Coastguard Worker dump += "UnwantedInteractionBlocker:\n";
468*38e8c45fSAndroid Build Coastguard Worker dump += " mPreferStylusOverTouchBlocker:\n";
469*38e8c45fSAndroid Build Coastguard Worker dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), " ");
470*38e8c45fSAndroid Build Coastguard Worker dump += StringPrintf(" mEnablePalmRejection: %s\n",
471*38e8c45fSAndroid Build Coastguard Worker std::to_string(mEnablePalmRejection).c_str());
472*38e8c45fSAndroid Build Coastguard Worker dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n",
473*38e8c45fSAndroid Build Coastguard Worker std::to_string(isPalmRejectionEnabled()).c_str());
474*38e8c45fSAndroid Build Coastguard Worker dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n";
475*38e8c45fSAndroid Build Coastguard Worker for (const auto& [deviceId, palmRejector] : mPalmRejectors) {
476*38e8c45fSAndroid Build Coastguard Worker dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId);
477*38e8c45fSAndroid Build Coastguard Worker dump += addLinePrefix(palmRejector.dump(), " ");
478*38e8c45fSAndroid Build Coastguard Worker }
479*38e8c45fSAndroid Build Coastguard Worker }
480*38e8c45fSAndroid Build Coastguard Worker
monitor()481*38e8c45fSAndroid Build Coastguard Worker void UnwantedInteractionBlocker::monitor() {
482*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
483*38e8c45fSAndroid Build Coastguard Worker }
484*38e8c45fSAndroid Build Coastguard Worker
~UnwantedInteractionBlocker()485*38e8c45fSAndroid Build Coastguard Worker UnwantedInteractionBlocker::~UnwantedInteractionBlocker() {}
486*38e8c45fSAndroid Build Coastguard Worker
update(const NotifyMotionArgs & args)487*38e8c45fSAndroid Build Coastguard Worker void SlotState::update(const NotifyMotionArgs& args) {
488*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < args.getPointerCount(); i++) {
489*38e8c45fSAndroid Build Coastguard Worker const int32_t pointerId = args.pointerProperties[i].id;
490*38e8c45fSAndroid Build Coastguard Worker const int32_t resolvedAction = resolveActionForPointer(i, args.action);
491*38e8c45fSAndroid Build Coastguard Worker processPointerId(pointerId, resolvedAction);
492*38e8c45fSAndroid Build Coastguard Worker }
493*38e8c45fSAndroid Build Coastguard Worker }
494*38e8c45fSAndroid Build Coastguard Worker
findUnusedSlot() const495*38e8c45fSAndroid Build Coastguard Worker size_t SlotState::findUnusedSlot() const {
496*38e8c45fSAndroid Build Coastguard Worker size_t unusedSlot = 0;
497*38e8c45fSAndroid Build Coastguard Worker // Since the collection is ordered, we can rely on the in-order traversal
498*38e8c45fSAndroid Build Coastguard Worker for (const auto& [slot, trackingId] : mPointerIdsBySlot) {
499*38e8c45fSAndroid Build Coastguard Worker if (unusedSlot != slot) {
500*38e8c45fSAndroid Build Coastguard Worker break;
501*38e8c45fSAndroid Build Coastguard Worker }
502*38e8c45fSAndroid Build Coastguard Worker unusedSlot++;
503*38e8c45fSAndroid Build Coastguard Worker }
504*38e8c45fSAndroid Build Coastguard Worker return unusedSlot;
505*38e8c45fSAndroid Build Coastguard Worker }
506*38e8c45fSAndroid Build Coastguard Worker
processPointerId(int pointerId,int32_t actionMasked)507*38e8c45fSAndroid Build Coastguard Worker void SlotState::processPointerId(int pointerId, int32_t actionMasked) {
508*38e8c45fSAndroid Build Coastguard Worker switch (MotionEvent::getActionMasked(actionMasked)) {
509*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_DOWN:
510*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_POINTER_DOWN:
511*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_HOVER_ENTER: {
512*38e8c45fSAndroid Build Coastguard Worker // New pointer going down
513*38e8c45fSAndroid Build Coastguard Worker size_t newSlot = findUnusedSlot();
514*38e8c45fSAndroid Build Coastguard Worker mPointerIdsBySlot[newSlot] = pointerId;
515*38e8c45fSAndroid Build Coastguard Worker mSlotsByPointerId[pointerId] = newSlot;
516*38e8c45fSAndroid Build Coastguard Worker return;
517*38e8c45fSAndroid Build Coastguard Worker }
518*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_MOVE:
519*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_HOVER_MOVE: {
520*38e8c45fSAndroid Build Coastguard Worker return;
521*38e8c45fSAndroid Build Coastguard Worker }
522*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_CANCEL:
523*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_POINTER_UP:
524*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_UP:
525*38e8c45fSAndroid Build Coastguard Worker case AMOTION_EVENT_ACTION_HOVER_EXIT: {
526*38e8c45fSAndroid Build Coastguard Worker auto it = mSlotsByPointerId.find(pointerId);
527*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(it == mSlotsByPointerId.end());
528*38e8c45fSAndroid Build Coastguard Worker size_t slot = it->second;
529*38e8c45fSAndroid Build Coastguard Worker // Erase this pointer from both collections
530*38e8c45fSAndroid Build Coastguard Worker mPointerIdsBySlot.erase(slot);
531*38e8c45fSAndroid Build Coastguard Worker mSlotsByPointerId.erase(pointerId);
532*38e8c45fSAndroid Build Coastguard Worker return;
533*38e8c45fSAndroid Build Coastguard Worker }
534*38e8c45fSAndroid Build Coastguard Worker }
535*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("Unhandled action : %s", MotionEvent::actionToString(actionMasked).c_str());
536*38e8c45fSAndroid Build Coastguard Worker return;
537*38e8c45fSAndroid Build Coastguard Worker }
538*38e8c45fSAndroid Build Coastguard Worker
getSlotForPointerId(int32_t pointerId) const539*38e8c45fSAndroid Build Coastguard Worker std::optional<size_t> SlotState::getSlotForPointerId(int32_t pointerId) const {
540*38e8c45fSAndroid Build Coastguard Worker auto it = mSlotsByPointerId.find(pointerId);
541*38e8c45fSAndroid Build Coastguard Worker if (it == mSlotsByPointerId.end()) {
542*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
543*38e8c45fSAndroid Build Coastguard Worker }
544*38e8c45fSAndroid Build Coastguard Worker return it->second;
545*38e8c45fSAndroid Build Coastguard Worker }
546*38e8c45fSAndroid Build Coastguard Worker
dump() const547*38e8c45fSAndroid Build Coastguard Worker std::string SlotState::dump() const {
548*38e8c45fSAndroid Build Coastguard Worker std::string out = "mSlotsByPointerId:\n";
549*38e8c45fSAndroid Build Coastguard Worker out += addLinePrefix(dumpMap(mSlotsByPointerId), " ") + "\n";
550*38e8c45fSAndroid Build Coastguard Worker out += "mPointerIdsBySlot:\n";
551*38e8c45fSAndroid Build Coastguard Worker out += addLinePrefix(dumpMap(mPointerIdsBySlot), " ") + "\n";
552*38e8c45fSAndroid Build Coastguard Worker return out;
553*38e8c45fSAndroid Build Coastguard Worker }
554*38e8c45fSAndroid Build Coastguard Worker
555*38e8c45fSAndroid Build Coastguard Worker class AndroidPalmRejectionModel : public ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel {
556*38e8c45fSAndroid Build Coastguard Worker public:
AndroidPalmRejectionModel()557*38e8c45fSAndroid Build Coastguard Worker AndroidPalmRejectionModel()
558*38e8c45fSAndroid Build Coastguard Worker : ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel(/*default version*/ "",
559*38e8c45fSAndroid Build Coastguard Worker std::vector<float>()) {
560*38e8c45fSAndroid Build Coastguard Worker config_.resample_period = ::ui::kResamplePeriod;
561*38e8c45fSAndroid Build Coastguard Worker }
562*38e8c45fSAndroid Build Coastguard Worker };
563*38e8c45fSAndroid Build Coastguard Worker
PalmRejector(const AndroidPalmFilterDeviceInfo & info,std::unique_ptr<::ui::PalmDetectionFilter> filter)564*38e8c45fSAndroid Build Coastguard Worker PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info,
565*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<::ui::PalmDetectionFilter> filter)
566*38e8c45fSAndroid Build Coastguard Worker : mSharedPalmState(std::make_unique<::ui::SharedPalmDetectionFilterState>()),
567*38e8c45fSAndroid Build Coastguard Worker mDeviceInfo(info),
568*38e8c45fSAndroid Build Coastguard Worker mPalmDetectionFilter(std::move(filter)) {
569*38e8c45fSAndroid Build Coastguard Worker if (mPalmDetectionFilter != nullptr) {
570*38e8c45fSAndroid Build Coastguard Worker // This path is used for testing. Non-testing invocations should let this constructor
571*38e8c45fSAndroid Build Coastguard Worker // create a real PalmDetectionFilter
572*38e8c45fSAndroid Build Coastguard Worker return;
573*38e8c45fSAndroid Build Coastguard Worker }
574*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<::ui::NeuralStylusPalmDetectionFilterModel> model =
575*38e8c45fSAndroid Build Coastguard Worker std::make_unique<AndroidPalmRejectionModel>();
576*38e8c45fSAndroid Build Coastguard Worker mPalmDetectionFilter = std::make_unique<PalmFilterImplementation>(mDeviceInfo, std::move(model),
577*38e8c45fSAndroid Build Coastguard Worker mSharedPalmState.get());
578*38e8c45fSAndroid Build Coastguard Worker }
579*38e8c45fSAndroid Build Coastguard Worker
getTouches(const NotifyMotionArgs & args,const AndroidPalmFilterDeviceInfo & deviceInfo,const SlotState & oldSlotState,const SlotState & newSlotState)580*38e8c45fSAndroid Build Coastguard Worker std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args,
581*38e8c45fSAndroid Build Coastguard Worker const AndroidPalmFilterDeviceInfo& deviceInfo,
582*38e8c45fSAndroid Build Coastguard Worker const SlotState& oldSlotState,
583*38e8c45fSAndroid Build Coastguard Worker const SlotState& newSlotState) {
584*38e8c45fSAndroid Build Coastguard Worker std::vector<::ui::InProgressTouchEvdev> touches;
585*38e8c45fSAndroid Build Coastguard Worker
586*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < args.getPointerCount(); i++) {
587*38e8c45fSAndroid Build Coastguard Worker const int32_t pointerId = args.pointerProperties[i].id;
588*38e8c45fSAndroid Build Coastguard Worker touches.emplace_back(::ui::InProgressTouchEvdev());
589*38e8c45fSAndroid Build Coastguard Worker touches.back().major = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
590*38e8c45fSAndroid Build Coastguard Worker touches.back().minor = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
591*38e8c45fSAndroid Build Coastguard Worker // The field 'tool_type' is not used for palm rejection
592*38e8c45fSAndroid Build Coastguard Worker
593*38e8c45fSAndroid Build Coastguard Worker // Whether there is new information for the touch.
594*38e8c45fSAndroid Build Coastguard Worker touches.back().altered = true;
595*38e8c45fSAndroid Build Coastguard Worker
596*38e8c45fSAndroid Build Coastguard Worker // Whether the touch was cancelled. Touch events should be ignored till a
597*38e8c45fSAndroid Build Coastguard Worker // new touch is initiated.
598*38e8c45fSAndroid Build Coastguard Worker touches.back().was_cancelled = false;
599*38e8c45fSAndroid Build Coastguard Worker
600*38e8c45fSAndroid Build Coastguard Worker // Whether the touch is going to be canceled.
601*38e8c45fSAndroid Build Coastguard Worker touches.back().cancelled = false;
602*38e8c45fSAndroid Build Coastguard Worker
603*38e8c45fSAndroid Build Coastguard Worker // Whether the touch is delayed at first appearance. Will not be reported yet.
604*38e8c45fSAndroid Build Coastguard Worker touches.back().delayed = false;
605*38e8c45fSAndroid Build Coastguard Worker
606*38e8c45fSAndroid Build Coastguard Worker // Whether the touch was delayed before.
607*38e8c45fSAndroid Build Coastguard Worker touches.back().was_delayed = false;
608*38e8c45fSAndroid Build Coastguard Worker
609*38e8c45fSAndroid Build Coastguard Worker // Whether the touch is held until end or no longer held.
610*38e8c45fSAndroid Build Coastguard Worker touches.back().held = false;
611*38e8c45fSAndroid Build Coastguard Worker
612*38e8c45fSAndroid Build Coastguard Worker // Whether this touch was held before being sent.
613*38e8c45fSAndroid Build Coastguard Worker touches.back().was_held = false;
614*38e8c45fSAndroid Build Coastguard Worker
615*38e8c45fSAndroid Build Coastguard Worker const int32_t resolvedAction = resolveActionForPointer(i, args.action);
616*38e8c45fSAndroid Build Coastguard Worker const bool isDown = resolvedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ||
617*38e8c45fSAndroid Build Coastguard Worker resolvedAction == AMOTION_EVENT_ACTION_DOWN;
618*38e8c45fSAndroid Build Coastguard Worker touches.back().was_touching = !isDown;
619*38e8c45fSAndroid Build Coastguard Worker
620*38e8c45fSAndroid Build Coastguard Worker const bool isUpOrCancel = resolvedAction == AMOTION_EVENT_ACTION_CANCEL ||
621*38e8c45fSAndroid Build Coastguard Worker resolvedAction == AMOTION_EVENT_ACTION_UP ||
622*38e8c45fSAndroid Build Coastguard Worker resolvedAction == AMOTION_EVENT_ACTION_POINTER_UP;
623*38e8c45fSAndroid Build Coastguard Worker
624*38e8c45fSAndroid Build Coastguard Worker touches.back().x = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X);
625*38e8c45fSAndroid Build Coastguard Worker touches.back().y = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y);
626*38e8c45fSAndroid Build Coastguard Worker
627*38e8c45fSAndroid Build Coastguard Worker std::optional<size_t> slot = newSlotState.getSlotForPointerId(pointerId);
628*38e8c45fSAndroid Build Coastguard Worker if (!slot) {
629*38e8c45fSAndroid Build Coastguard Worker slot = oldSlotState.getSlotForPointerId(pointerId);
630*38e8c45fSAndroid Build Coastguard Worker }
631*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer %d", pointerId);
632*38e8c45fSAndroid Build Coastguard Worker touches.back().slot = *slot;
633*38e8c45fSAndroid Build Coastguard Worker touches.back().tracking_id = (!isUpOrCancel) ? pointerId : -1;
634*38e8c45fSAndroid Build Coastguard Worker touches.back().touching = !isUpOrCancel;
635*38e8c45fSAndroid Build Coastguard Worker
636*38e8c45fSAndroid Build Coastguard Worker // The fields 'radius_x' and 'radius_x' are not used for palm rejection
637*38e8c45fSAndroid Build Coastguard Worker touches.back().pressure = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
638*38e8c45fSAndroid Build Coastguard Worker touches.back().tool_code = getLinuxToolCode(args.pointerProperties[i].toolType);
639*38e8c45fSAndroid Build Coastguard Worker // The field 'orientation' is not used for palm rejection
640*38e8c45fSAndroid Build Coastguard Worker // The fields 'tilt_x' and 'tilt_y' are not used for palm rejection
641*38e8c45fSAndroid Build Coastguard Worker // The field 'reported_tool_type' is not used for palm rejection
642*38e8c45fSAndroid Build Coastguard Worker touches.back().stylus_button = false;
643*38e8c45fSAndroid Build Coastguard Worker }
644*38e8c45fSAndroid Build Coastguard Worker return touches;
645*38e8c45fSAndroid Build Coastguard Worker }
646*38e8c45fSAndroid Build Coastguard Worker
detectPalmPointers(const NotifyMotionArgs & args)647*38e8c45fSAndroid Build Coastguard Worker std::set<int32_t> PalmRejector::detectPalmPointers(const NotifyMotionArgs& args) {
648*38e8c45fSAndroid Build Coastguard Worker std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
649*38e8c45fSAndroid Build Coastguard Worker std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;
650*38e8c45fSAndroid Build Coastguard Worker
651*38e8c45fSAndroid Build Coastguard Worker // Store the slot state before we call getTouches and update it. This way, we can find
652*38e8c45fSAndroid Build Coastguard Worker // the slots that have been removed due to the incoming event.
653*38e8c45fSAndroid Build Coastguard Worker SlotState oldSlotState = mSlotState;
654*38e8c45fSAndroid Build Coastguard Worker mSlotState.update(args);
655*38e8c45fSAndroid Build Coastguard Worker
656*38e8c45fSAndroid Build Coastguard Worker std::vector<::ui::InProgressTouchEvdev> touches =
657*38e8c45fSAndroid Build Coastguard Worker getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
658*38e8c45fSAndroid Build Coastguard Worker ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
659*38e8c45fSAndroid Build Coastguard Worker
660*38e8c45fSAndroid Build Coastguard Worker if (DEBUG_MODEL) {
661*38e8c45fSAndroid Build Coastguard Worker std::stringstream touchesStream;
662*38e8c45fSAndroid Build Coastguard Worker for (const ::ui::InProgressTouchEvdev& touch : touches) {
663*38e8c45fSAndroid Build Coastguard Worker touchesStream << touch.tracking_id << " : " << touch << "\n";
664*38e8c45fSAndroid Build Coastguard Worker }
665*38e8c45fSAndroid Build Coastguard Worker ALOGD("Filter: touches = %s", touchesStream.str().c_str());
666*38e8c45fSAndroid Build Coastguard Worker }
667*38e8c45fSAndroid Build Coastguard Worker
668*38e8c45fSAndroid Build Coastguard Worker mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
669*38e8c45fSAndroid Build Coastguard Worker
670*38e8c45fSAndroid Build Coastguard Worker ALOGD_IF(DEBUG_MODEL, "Response: slotsToHold = %s, slotsToSuppress = %s",
671*38e8c45fSAndroid Build Coastguard Worker slotsToHold.to_string().c_str(), slotsToSuppress.to_string().c_str());
672*38e8c45fSAndroid Build Coastguard Worker
673*38e8c45fSAndroid Build Coastguard Worker // Now that we know which slots should be suppressed, let's convert those to pointer id's.
674*38e8c45fSAndroid Build Coastguard Worker std::set<int32_t> newSuppressedIds;
675*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < args.getPointerCount(); i++) {
676*38e8c45fSAndroid Build Coastguard Worker const int32_t pointerId = args.pointerProperties[i].id;
677*38e8c45fSAndroid Build Coastguard Worker std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
678*38e8c45fSAndroid Build Coastguard Worker if (!slot) {
679*38e8c45fSAndroid Build Coastguard Worker slot = mSlotState.getSlotForPointerId(pointerId);
680*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
681*38e8c45fSAndroid Build Coastguard Worker }
682*38e8c45fSAndroid Build Coastguard Worker if (slotsToSuppress.test(*slot)) {
683*38e8c45fSAndroid Build Coastguard Worker newSuppressedIds.insert(pointerId);
684*38e8c45fSAndroid Build Coastguard Worker }
685*38e8c45fSAndroid Build Coastguard Worker }
686*38e8c45fSAndroid Build Coastguard Worker return newSuppressedIds;
687*38e8c45fSAndroid Build Coastguard Worker }
688*38e8c45fSAndroid Build Coastguard Worker
processMotion(const NotifyMotionArgs & args)689*38e8c45fSAndroid Build Coastguard Worker std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs& args) {
690*38e8c45fSAndroid Build Coastguard Worker if (mPalmDetectionFilter == nullptr) {
691*38e8c45fSAndroid Build Coastguard Worker return {args};
692*38e8c45fSAndroid Build Coastguard Worker }
693*38e8c45fSAndroid Build Coastguard Worker const bool skipThisEvent = args.action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
694*38e8c45fSAndroid Build Coastguard Worker args.action == AMOTION_EVENT_ACTION_HOVER_MOVE ||
695*38e8c45fSAndroid Build Coastguard Worker args.action == AMOTION_EVENT_ACTION_HOVER_EXIT ||
696*38e8c45fSAndroid Build Coastguard Worker args.action == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
697*38e8c45fSAndroid Build Coastguard Worker args.action == AMOTION_EVENT_ACTION_BUTTON_RELEASE ||
698*38e8c45fSAndroid Build Coastguard Worker args.action == AMOTION_EVENT_ACTION_SCROLL;
699*38e8c45fSAndroid Build Coastguard Worker if (skipThisEvent) {
700*38e8c45fSAndroid Build Coastguard Worker // Lets not process hover events, button events, or scroll for now.
701*38e8c45fSAndroid Build Coastguard Worker return {args};
702*38e8c45fSAndroid Build Coastguard Worker }
703*38e8c45fSAndroid Build Coastguard Worker if (args.action == AMOTION_EVENT_ACTION_DOWN) {
704*38e8c45fSAndroid Build Coastguard Worker mSuppressedPointerIds.clear();
705*38e8c45fSAndroid Build Coastguard Worker }
706*38e8c45fSAndroid Build Coastguard Worker
707*38e8c45fSAndroid Build Coastguard Worker std::set<int32_t> oldSuppressedIds;
708*38e8c45fSAndroid Build Coastguard Worker std::swap(oldSuppressedIds, mSuppressedPointerIds);
709*38e8c45fSAndroid Build Coastguard Worker
710*38e8c45fSAndroid Build Coastguard Worker std::optional<NotifyMotionArgs> touchOnlyArgs = removeStylusPointerIds(args);
711*38e8c45fSAndroid Build Coastguard Worker if (touchOnlyArgs) {
712*38e8c45fSAndroid Build Coastguard Worker mSuppressedPointerIds = detectPalmPointers(*touchOnlyArgs);
713*38e8c45fSAndroid Build Coastguard Worker } else {
714*38e8c45fSAndroid Build Coastguard Worker // This is a stylus-only event.
715*38e8c45fSAndroid Build Coastguard Worker // We can skip this event and just keep the suppressed pointer ids the same as before.
716*38e8c45fSAndroid Build Coastguard Worker mSuppressedPointerIds = oldSuppressedIds;
717*38e8c45fSAndroid Build Coastguard Worker }
718*38e8c45fSAndroid Build Coastguard Worker
719*38e8c45fSAndroid Build Coastguard Worker std::vector<NotifyMotionArgs> argsWithoutUnwantedPointers =
720*38e8c45fSAndroid Build Coastguard Worker cancelSuppressedPointers(args, oldSuppressedIds, mSuppressedPointerIds);
721*38e8c45fSAndroid Build Coastguard Worker for (const NotifyMotionArgs& checkArgs : argsWithoutUnwantedPointers) {
722*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(checkArgs.action == ACTION_UNKNOWN, "%s", checkArgs.dump().c_str());
723*38e8c45fSAndroid Build Coastguard Worker }
724*38e8c45fSAndroid Build Coastguard Worker
725*38e8c45fSAndroid Build Coastguard Worker // Only log if new pointers are getting rejected. That means mSuppressedPointerIds is not a
726*38e8c45fSAndroid Build Coastguard Worker // subset of oldSuppressedIds.
727*38e8c45fSAndroid Build Coastguard Worker if (!std::includes(oldSuppressedIds.begin(), oldSuppressedIds.end(),
728*38e8c45fSAndroid Build Coastguard Worker mSuppressedPointerIds.begin(), mSuppressedPointerIds.end())) {
729*38e8c45fSAndroid Build Coastguard Worker ALOGI("Palm detected, removing pointer ids %s after %" PRId64 "ms from %s",
730*38e8c45fSAndroid Build Coastguard Worker dumpSet(mSuppressedPointerIds).c_str(), ns2ms(args.eventTime - args.downTime),
731*38e8c45fSAndroid Build Coastguard Worker args.dump().c_str());
732*38e8c45fSAndroid Build Coastguard Worker }
733*38e8c45fSAndroid Build Coastguard Worker
734*38e8c45fSAndroid Build Coastguard Worker return argsWithoutUnwantedPointers;
735*38e8c45fSAndroid Build Coastguard Worker }
736*38e8c45fSAndroid Build Coastguard Worker
getPalmFilterDeviceInfo() const737*38e8c45fSAndroid Build Coastguard Worker const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() const {
738*38e8c45fSAndroid Build Coastguard Worker return mDeviceInfo;
739*38e8c45fSAndroid Build Coastguard Worker }
740*38e8c45fSAndroid Build Coastguard Worker
dump() const741*38e8c45fSAndroid Build Coastguard Worker std::string PalmRejector::dump() const {
742*38e8c45fSAndroid Build Coastguard Worker std::string out;
743*38e8c45fSAndroid Build Coastguard Worker out += "mDeviceInfo:\n";
744*38e8c45fSAndroid Build Coastguard Worker std::stringstream deviceInfo;
745*38e8c45fSAndroid Build Coastguard Worker deviceInfo << mDeviceInfo << ", touch_major_res=" << mDeviceInfo.touch_major_res
746*38e8c45fSAndroid Build Coastguard Worker << ", touch_minor_res=" << mDeviceInfo.touch_minor_res << "\n";
747*38e8c45fSAndroid Build Coastguard Worker out += addLinePrefix(deviceInfo.str(), " ");
748*38e8c45fSAndroid Build Coastguard Worker out += "mSlotState:\n";
749*38e8c45fSAndroid Build Coastguard Worker out += addLinePrefix(mSlotState.dump(), " ");
750*38e8c45fSAndroid Build Coastguard Worker out += "mSuppressedPointerIds: ";
751*38e8c45fSAndroid Build Coastguard Worker out += dumpSet(mSuppressedPointerIds) + "\n";
752*38e8c45fSAndroid Build Coastguard Worker std::stringstream state;
753*38e8c45fSAndroid Build Coastguard Worker state << *mSharedPalmState;
754*38e8c45fSAndroid Build Coastguard Worker out += "mSharedPalmState: " + state.str() + "\n";
755*38e8c45fSAndroid Build Coastguard Worker std::stringstream filter;
756*38e8c45fSAndroid Build Coastguard Worker filter << static_cast<const PalmFilterImplementation&>(*mPalmDetectionFilter);
757*38e8c45fSAndroid Build Coastguard Worker out += "mPalmDetectionFilter:\n";
758*38e8c45fSAndroid Build Coastguard Worker out += addLinePrefix(filter.str(), " ") + "\n";
759*38e8c45fSAndroid Build Coastguard Worker return out;
760*38e8c45fSAndroid Build Coastguard Worker }
761*38e8c45fSAndroid Build Coastguard Worker
762*38e8c45fSAndroid Build Coastguard Worker } // namespace android
763