blob: 3ea0986d4109c7689b315a058e98ea2d4ca8fe0c [file] [log] [blame]
Siarhei Vishniakou473174e2017-12-27 16:44:42 -08001/*
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
17#define LOG_TAG "InputClassifier"
18
19#include "InputClassifier.h"
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080020#include "InputCommonConverter.h"
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080021
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080022#include <android-base/stringprintf.h>
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080023#include <android/binder_manager.h>
24#include <android/binder_process.h>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080025#include <inttypes.h>
26#include <log/log.h>
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080027#include <algorithm>
28#include <cmath>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080029#if defined(__linux__)
30 #include <pthread.h>
31#endif
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080032#include <unordered_set>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080033
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080034#define INDENT1 " "
35#define INDENT2 " "
36#define INDENT3 " "
37#define INDENT4 " "
38#define INDENT5 " "
39
40using android::base::StringPrintf;
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080041using namespace std::chrono_literals;
42using namespace ::aidl::android::hardware::input;
43using aidl::android::hardware::input::processor::IInputProcessor;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080044
45namespace android {
46
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080047//Max number of elements to store in mEvents.
48static constexpr size_t MAX_EVENTS = 5;
49
50template<class K, class V>
51static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultValue) {
52 auto it = map.find(key);
53 if (it == map.end()) {
54 return defaultValue;
55 }
56 return it->second;
57}
58
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080059static MotionClassification getMotionClassification(common::Classification classification) {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080060 static_assert(MotionClassification::NONE ==
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080061 static_cast<MotionClassification>(common::Classification::NONE));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080062 static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080063 static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080064 static_assert(MotionClassification::DEEP_PRESS ==
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080065 static_cast<MotionClassification>(common::Classification::DEEP_PRESS));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080066 return static_cast<MotionClassification>(classification);
67}
68
69static bool isTouchEvent(const NotifyMotionArgs& args) {
Siarhei Vishniakoud9489572021-11-12 20:08:38 -080070 return isFromSource(args.source, AINPUT_SOURCE_TOUCHPAD) ||
71 isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080072}
73
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080074static void setCurrentThreadName(const char* name) {
75#if defined(__linux__)
76 // Set the thread name for debugging
77 pthread_setname_np(pthread_self(), name);
78#else
79 (void*)(name); // prevent unused variable warning
80#endif
81}
82
83static std::shared_ptr<IInputProcessor> getService() {
84 const std::string aidl_instance_name = std::string(IInputProcessor::descriptor) + "/default";
85
86 if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
87 ALOGI("HAL %s is not declared", aidl_instance_name.c_str());
88 return nullptr;
89 }
90
91 ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_instance_name.c_str()));
92 return IInputProcessor::fromBinder(binder);
93}
94
95// Temporarily releases a held mutex for the lifetime of the instance.
96// Named to match std::scoped_lock
97class scoped_unlock {
98public:
99 explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
100 ~scoped_unlock() { mMutex.lock(); }
101
102private:
103 std::mutex& mMutex;
104};
105
106// --- ScopedDeathRecipient ---
107ScopedDeathRecipient::ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied,
108 void* cookie)
109 : mCookie(cookie) {
110 mRecipient = AIBinder_DeathRecipient_new(onBinderDied);
111}
112
113void ScopedDeathRecipient::linkToDeath(AIBinder* binder) {
114 binder_status_t linked = AIBinder_linkToDeath(binder, mRecipient, mCookie);
115 if (linked != STATUS_OK) {
116 ALOGE("Could not link death recipient to the HAL death");
117 }
118}
119
120ScopedDeathRecipient::~ScopedDeathRecipient() {
121 AIBinder_DeathRecipient_delete(mRecipient);
122}
123
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800124// --- ClassifierEvent ---
125
126ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
127 type(ClassifierEventType::MOTION), args(std::move(args)) { };
128ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args) :
129 type(ClassifierEventType::DEVICE_RESET), args(std::move(args)) { };
130ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args) :
131 type(type), args(std::move(args)) { };
132
133ClassifierEvent::ClassifierEvent(ClassifierEvent&& other) :
134 type(other.type), args(std::move(other.args)) { };
135
136ClassifierEvent& ClassifierEvent::operator=(ClassifierEvent&& other) {
137 type = other.type;
138 args = std::move(other.args);
139 return *this;
140}
141
142ClassifierEvent ClassifierEvent::createHalResetEvent() {
143 return ClassifierEvent(ClassifierEventType::HAL_RESET, nullptr);
144}
145
146ClassifierEvent ClassifierEvent::createExitEvent() {
147 return ClassifierEvent(ClassifierEventType::EXIT, nullptr);
148}
149
150std::optional<int32_t> ClassifierEvent::getDeviceId() const {
151 switch (type) {
152 case ClassifierEventType::MOTION: {
153 NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(args.get());
154 return motionArgs->deviceId;
155 }
156 case ClassifierEventType::DEVICE_RESET: {
157 NotifyDeviceResetArgs* deviceResetArgs =
158 static_cast<NotifyDeviceResetArgs*>(args.get());
159 return deviceResetArgs->deviceId;
160 }
161 case ClassifierEventType::HAL_RESET: {
162 return std::nullopt;
163 }
164 case ClassifierEventType::EXIT: {
165 return std::nullopt;
166 }
167 }
168}
169
170// --- MotionClassifier ---
171
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800172MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service)
173 : mEvents(MAX_EVENTS), mService(std::move(service)) {
Siarhei Vishniakou6dbc3f62019-02-04 14:30:11 -0800174 // Under normal operation, we do not need to reset the HAL here. But in the case where system
175 // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
176 // have received events in the past. That means, that HAL could be in an inconsistent state
177 // once it receives events from the newly created MotionClassifier.
178 mEvents.push(ClassifierEvent::createHalResetEvent());
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700179
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800180 mHalThread = std::thread(&MotionClassifier::processEvents, this);
181#if defined(__linux__)
182 // Set the thread name for debugging
183 pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
184#endif
185}
186
187std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800188 std::shared_ptr<IInputProcessor> service) {
189 LOG_ALWAYS_FATAL_IF(service == nullptr);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800190 // Using 'new' to access a non-public constructor
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800191 return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service)));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800192}
193
194MotionClassifier::~MotionClassifier() {
195 requestExit();
196 mHalThread.join();
197}
198
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800199/**
200 * Obtain the classification from the HAL for a given MotionEvent.
201 * Should only be called from the InputClassifier thread (mHalThread).
202 * Should not be called from the thread that notifyMotion runs on.
203 *
204 * There is no way to provide a timeout for a HAL call. So if the HAL takes too long
205 * to return a classification, this would directly impact the touch latency.
206 * To remove any possibility of negatively affecting the touch latency, the HAL
207 * is called from a dedicated thread.
208 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800209void MotionClassifier::processEvents() {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800210 while (true) {
211 ClassifierEvent event = mEvents.pop();
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800212 bool halResponseOk = true;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800213 switch (event.type) {
214 case ClassifierEventType::MOTION: {
215 NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800216 common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs);
217 common::Classification classification;
218 ndk::ScopedAStatus response = mService->classify(motionEvent, &classification);
219 if (response.isOk()) {
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800220 updateClassification(motionArgs->deviceId, motionArgs->eventTime,
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800221 getMotionClassification(classification));
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800222 }
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800223 break;
224 }
225 case ClassifierEventType::DEVICE_RESET: {
226 const int32_t deviceId = *(event.getDeviceId());
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800227 halResponseOk = mService->resetDevice(deviceId).isOk();
Siarhei Vishniakoue3021d72020-02-28 15:25:41 -0800228 clearDeviceState(deviceId);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800229 break;
230 }
231 case ClassifierEventType::HAL_RESET: {
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800232 halResponseOk = mService->reset().isOk();
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800233 clearClassifications();
234 break;
235 }
236 case ClassifierEventType::EXIT: {
237 clearClassifications();
238 return;
239 }
240 }
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800241 if (!halResponseOk) {
242 ALOGE("Error communicating with InputClassifier HAL. "
243 "Exiting MotionClassifier HAL thread");
244 clearClassifications();
245 return;
246 }
247 }
248}
249
250void MotionClassifier::enqueueEvent(ClassifierEvent&& event) {
251 bool eventAdded = mEvents.push(std::move(event));
252 if (!eventAdded) {
253 // If the queue is full, suspect the HAL is slow in processing the events.
Siarhei Vishniakou9b5a8212019-07-01 14:25:40 -0700254 ALOGE("Could not add the event to the queue. Resetting");
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800255 reset();
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800256 }
257}
258
259void MotionClassifier::requestExit() {
260 reset();
261 mEvents.push(ClassifierEvent::createExitEvent());
262}
263
264void MotionClassifier::updateClassification(int32_t deviceId, nsecs_t eventTime,
265 MotionClassification classification) {
266 std::scoped_lock lock(mLock);
267 const nsecs_t lastDownTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
268 if (eventTime < lastDownTime) {
269 // HAL just finished processing an event that belonged to an earlier gesture,
270 // but new gesture is already in progress. Drop this classification.
271 ALOGW("Received late classification. Late by at least %" PRId64 " ms.",
272 nanoseconds_to_milliseconds(lastDownTime - eventTime));
273 return;
274 }
275 mClassifications[deviceId] = classification;
276}
277
278void MotionClassifier::setClassification(int32_t deviceId, MotionClassification classification) {
279 std::scoped_lock lock(mLock);
280 mClassifications[deviceId] = classification;
281}
282
283void MotionClassifier::clearClassifications() {
284 std::scoped_lock lock(mLock);
285 mClassifications.clear();
286}
287
288MotionClassification MotionClassifier::getClassification(int32_t deviceId) {
289 std::scoped_lock lock(mLock);
290 return getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
291}
292
293void MotionClassifier::updateLastDownTime(int32_t deviceId, nsecs_t downTime) {
294 std::scoped_lock lock(mLock);
295 mLastDownTimes[deviceId] = downTime;
296 mClassifications[deviceId] = MotionClassification::NONE;
297}
298
Siarhei Vishniakoue3021d72020-02-28 15:25:41 -0800299void MotionClassifier::clearDeviceState(int32_t deviceId) {
300 std::scoped_lock lock(mLock);
301 mClassifications.erase(deviceId);
302 mLastDownTimes.erase(deviceId);
303}
304
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800305MotionClassification MotionClassifier::classify(const NotifyMotionArgs& args) {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800306 if ((args.action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN) {
307 updateLastDownTime(args.deviceId, args.downTime);
308 }
309
310 ClassifierEvent event(std::make_unique<NotifyMotionArgs>(args));
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800311 enqueueEvent(std::move(event));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800312 return getClassification(args.deviceId);
313}
314
315void MotionClassifier::reset() {
316 mEvents.clear();
317 mEvents.push(ClassifierEvent::createHalResetEvent());
318}
319
320/**
321 * Per-device reset. Clear the outstanding events that are going to be sent to HAL.
322 * Request InputClassifier thread to call resetDevice for this particular device.
323 */
324void MotionClassifier::reset(const NotifyDeviceResetArgs& args) {
325 int32_t deviceId = args.deviceId;
326 // Clear the pending events right away, to avoid unnecessary work done by the HAL.
327 mEvents.erase([deviceId](const ClassifierEvent& event) {
328 std::optional<int32_t> eventDeviceId = event.getDeviceId();
329 return eventDeviceId && (*eventDeviceId == deviceId);
330 });
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800331 enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800332}
333
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700334const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) {
335 if (!mService) {
336 return "null";
337 }
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800338
339 if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) {
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700340 return "running";
341 }
342 return "not responding";
343}
344
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800345void MotionClassifier::dump(std::string& dump) {
346 std::scoped_lock lock(mLock);
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700347 dump += StringPrintf(INDENT2 "mService status: %s\n", getServiceStatus());
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800348 dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
349 mEvents.size(), MAX_EVENTS);
350 dump += INDENT2 "mClassifications, mLastDownTimes:\n";
351 dump += INDENT3 "Device Id\tClassification\tLast down time";
352 // Combine mClassifications and mLastDownTimes into a single table.
353 // Create a superset of device ids.
354 std::unordered_set<int32_t> deviceIds;
355 std::for_each(mClassifications.begin(), mClassifications.end(),
356 [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
357 std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(),
358 [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
359 for(int32_t deviceId : deviceIds) {
360 const MotionClassification classification =
361 getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
362 const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
363 dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64,
364 deviceId, motionClassificationToString(classification), downTime);
365 }
366}
367
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800368// --- InputClassifier ---
369
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800370InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
371
372void InputClassifier::onBinderDied(void* cookie) {
373 InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
374 if (classifier == nullptr) {
375 LOG_ALWAYS_FATAL("Cookie is not valid");
376 return;
377 }
378 classifier->setMotionClassifierEnabled(false);
379}
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700380
381void InputClassifier::setMotionClassifierEnabled(bool enabled) {
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800382 std::scoped_lock lock(mLock);
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700383 if (enabled) {
384 ALOGI("Enabling motion classifier");
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800385 if (mInitializeMotionClassifier.valid()) {
386 scoped_unlock unlock(mLock);
387 std::future_status status = mInitializeMotionClassifier.wait_for(5s);
388 if (status != std::future_status::ready) {
389 /**
390 * We don't have a better option here than to crash. We can't stop the thread,
391 * and we can't continue because 'mInitializeMotionClassifier' will block in its
392 * destructor.
393 */
394 LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!");
395 }
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700396 }
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800397 mInitializeMotionClassifier = std::async(std::launch::async, [this] {
398 setCurrentThreadName("Create MotionClassifier");
399 std::shared_ptr<IInputProcessor> service = getService();
400 if (service == nullptr) {
401 // Keep the MotionClassifier null, no service was found
402 return;
403 }
404 { // acquire lock
405 std::scoped_lock threadLock(mLock);
406 mHalDeathRecipient =
407 std::make_unique<ScopedDeathRecipient>(onBinderDied, this /*cookie*/);
408 mHalDeathRecipient->linkToDeath(service->asBinder().get());
409 setMotionClassifierLocked(MotionClassifier::create(std::move(service)));
410 } // release lock
411 });
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700412 } else {
413 ALOGI("Disabling motion classifier");
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800414 setMotionClassifierLocked(nullptr);
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700415 }
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800416}
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800417
418void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
419 // pass through
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700420 mListener.notifyConfigurationChanged(args);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800421}
422
423void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
424 // pass through
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700425 mListener.notifyKey(args);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800426}
427
428void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800429 std::scoped_lock lock(mLock);
430 // MotionClassifier is only used for touch events, for now
431 const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args);
432 if (!sendToMotionClassifier) {
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700433 mListener.notifyMotion(args);
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800434 return;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800435 }
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800436
437 NotifyMotionArgs newArgs(*args);
438 newArgs.classification = mMotionClassifier->classify(newArgs);
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700439 mListener.notifyMotion(&newArgs);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800440}
441
Chris Yef59a2f42020-10-16 12:55:26 -0700442void InputClassifier::notifySensor(const NotifySensorArgs* args) {
443 // pass through
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700444 mListener.notifySensor(args);
Chris Yef59a2f42020-10-16 12:55:26 -0700445}
446
Chris Yefb552902021-02-03 17:18:37 -0800447void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) {
448 // pass through
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700449 mListener.notifyVibratorState(args);
Chris Yefb552902021-02-03 17:18:37 -0800450}
451
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800452void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
453 // pass through
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700454 mListener.notifySwitch(args);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800455}
456
457void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800458 std::scoped_lock lock(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800459 if (mMotionClassifier) {
460 mMotionClassifier->reset(*args);
461 }
462 // continue to next stage
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700463 mListener.notifyDeviceReset(args);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800464}
465
Prabir Pradhan7e186182020-11-10 13:56:45 -0800466void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
467 // pass through
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700468 mListener.notifyPointerCaptureChanged(args);
Prabir Pradhan7e186182020-11-10 13:56:45 -0800469}
470
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800471void InputClassifier::setMotionClassifierLocked(
472 std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
473 if (motionClassifier == nullptr) {
474 // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
475 // We can't call 'unlink' here because we don't have the binder handle.
476 mHalDeathRecipient = nullptr;
477 }
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800478 mMotionClassifier = std::move(motionClassifier);
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800479}
480
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800481void InputClassifier::dump(std::string& dump) {
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800482 std::scoped_lock lock(mLock);
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800483 dump += "Input Classifier State:\n";
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800484 dump += INDENT1 "Motion Classifier:\n";
485 if (mMotionClassifier) {
486 mMotionClassifier->dump(dump);
487 } else {
488 dump += INDENT2 "<nullptr>";
489 }
490 dump += "\n";
491}
492
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800493InputClassifier::~InputClassifier() {
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800494}
495
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700496} // namespace android