blob: bf10920e61c928f506a8e3436b5d26f4fe1e210a [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#ifndef _UI_INPUT_CLASSIFIER_H
18#define _UI_INPUT_CLASSIFIER_H
19
Siarhei Vishniakou61291d42019-02-11 18:13:20 -080020#include <android-base/thread_annotations.h>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080021#include <utils/RefBase.h>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080022#include <thread>
Siarhei Vishniakou16523972020-03-04 17:48:39 -080023#include <unordered_map>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080024
25#include "BlockingQueue.h"
26#include "InputListener.h"
27#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
28
29namespace android {
30
31enum class ClassifierEventType : uint8_t {
32 MOTION = 0,
33 DEVICE_RESET = 1,
34 HAL_RESET = 2,
35 EXIT = 3,
36};
37
38struct ClassifierEvent {
39 ClassifierEventType type;
40 std::unique_ptr<NotifyArgs> args;
41
42 ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args);
43 ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args);
44 ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args);
45 ClassifierEvent(ClassifierEvent&& other);
46 ClassifierEvent& operator=(ClassifierEvent&& other);
47
48 // Convenience function to create a HAL_RESET event
49 static ClassifierEvent createHalResetEvent();
50 // Convenience function to create an EXIT event
51 static ClassifierEvent createExitEvent();
52
53 std::optional<int32_t> getDeviceId() const;
54};
55
56// --- Interfaces ---
57
58/**
59 * Interface for adding a MotionClassification to NotifyMotionArgs.
60 *
61 * To implement, override the classify function.
62 */
63class MotionClassifierInterface {
64public:
65 MotionClassifierInterface() { }
66 virtual ~MotionClassifierInterface() { }
67 /**
68 * Based on the motion event described by NotifyMotionArgs,
69 * provide a MotionClassification for the current gesture.
70 */
71 virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -080072 /**
73 * Reset all internal HAL state.
74 */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080075 virtual void reset() = 0;
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -080076 /**
77 * Reset HAL state for a specific device.
78 */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080079 virtual void reset(const NotifyDeviceResetArgs& args) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080080
81 /**
82 * Dump the state of the motion classifier
83 */
84 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080085};
86
87/**
88 * Base interface for an InputListener stage.
89 * Provides classification to events.
90 */
91class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080092public:
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -070093 virtual void setMotionClassifierEnabled(bool enabled) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080094 /**
95 * Dump the state of the input classifier.
96 * This method may be called on any thread (usually by the input manager).
97 */
98 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080099protected:
100 InputClassifierInterface() { }
101 virtual ~InputClassifierInterface() { }
102};
103
104// --- Implementations ---
105
106/**
107 * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
108 * in order to determine the classification for the current gesture.
109 *
110 * The InputClassifier HAL may keep track of the entire gesture in order to determine
111 * the classification, and may be hardware-specific. It may use the data in
112 * NotifyMotionArgs::videoFrames field to drive the classification decisions.
113 * The HAL is called from a separate thread.
114 */
Greg Kaiser04b3a052019-01-29 07:10:14 -0800115class MotionClassifier final : public MotionClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800116public:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800117 /*
118 * Create an instance of MotionClassifier.
119 * The death recipient, if provided, will be subscribed to the HAL death.
120 * The death recipient could be used to destroy MotionClassifier.
121 *
122 * This function should be called asynchronously, because getService takes a long time.
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800123 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800124 static std::unique_ptr<MotionClassifierInterface> create(
125 sp<android::hardware::hidl_death_recipient> deathRecipient);
126
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800127 ~MotionClassifier();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700128
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800129 /**
130 * Classifies events asynchronously; that is, it doesn't block events on a classification,
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800131 * but instead sends them over to the classifier HAL. After a classification of a specific
132 * event is determined, MotionClassifier then marks the next event in the stream with this
133 * classification.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800134 *
135 * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
136 * in a particular gesture.
137 */
138 virtual MotionClassification classify(const NotifyMotionArgs& args) override;
139 virtual void reset() override;
140 virtual void reset(const NotifyDeviceResetArgs& args) override;
141
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800142 virtual void dump(std::string& dump) override;
143
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800144private:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800145 friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
146 explicit MotionClassifier(
147 sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700148
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800149 // The events that need to be sent to the HAL.
150 BlockingQueue<ClassifierEvent> mEvents;
151 /**
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800152 * Add an event to the queue mEvents.
153 */
154 void enqueueEvent(ClassifierEvent&& event);
155 /**
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800156 * Thread that will communicate with InputClassifier HAL.
157 * This should be the only thread that communicates with InputClassifier HAL,
158 * because this thread is allowed to block on the HAL calls.
159 */
160 std::thread mHalThread;
161 /**
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800162 * Process events and call the InputClassifier HAL
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800163 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800164 void processEvents();
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800165 /**
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700166 * Access to the InputClassifier HAL. May be null if init() hasn't completed yet.
167 * When init() successfully completes, mService is guaranteed to remain non-null and to not
168 * change its value until MotionClassifier is destroyed.
169 * This variable is *not* guarded by mLock in the InputClassifier thread, because
170 * that thread knows exactly when this variable is initialized.
171 * When accessed in any other thread, mService is checked for nullness with a lock.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800172 */
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700173 sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800174 std::mutex mLock;
175 /**
176 * Per-device input classifications. Should only be accessed using the
177 * getClassification / setClassification methods.
178 */
179 std::unordered_map<int32_t /*deviceId*/, MotionClassification>
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800180 mClassifications GUARDED_BY(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800181 /**
182 * Set the current classification for a given device.
183 */
184 void setClassification(int32_t deviceId, MotionClassification classification);
185 /**
186 * Get the current classification for a given device.
187 */
188 MotionClassification getClassification(int32_t deviceId);
189 void updateClassification(int32_t deviceId, nsecs_t eventTime,
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800190 MotionClassification classification);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800191 /**
192 * Clear all current classifications
193 */
194 void clearClassifications();
195 /**
196 * Per-device times when the last ACTION_DOWN was received.
197 * Used to reject late classifications that do not belong to the current gesture.
198 *
199 * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
200 */
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800201 std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
202
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800203 void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800204
Siarhei Vishniakoue3021d72020-02-28 15:25:41 -0800205 void clearDeviceState(int32_t deviceId);
206
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800207 /**
208 * Exit the InputClassifier HAL thread.
209 * Useful for tests to ensure proper cleanup.
210 */
211 void requestExit();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700212 /**
213 * Return string status of mService
214 */
215 const char* getServiceStatus() REQUIRES(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800216};
217
218/**
219 * Implementation of the InputClassifierInterface.
220 * Represents a separate stage of input processing. All of the input events go through this stage.
221 * Acts as a passthrough for all input events except for motion events.
222 * The events of motion type are sent to MotionClassifier.
223 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800224class InputClassifier : public InputClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800225public:
226 explicit InputClassifier(const sp<InputListenerInterface>& listener);
Siarhei Vishniakou45bb0882019-02-04 14:25:28 -0800227
228 virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
229 virtual void notifyKey(const NotifyKeyArgs* args) override;
230 virtual void notifyMotion(const NotifyMotionArgs* args) override;
231 virtual void notifySwitch(const NotifySwitchArgs* args) override;
Chris Yef59a2f42020-10-16 12:55:26 -0700232 virtual void notifySensor(const NotifySensorArgs* args) override;
Siarhei Vishniakou45bb0882019-02-04 14:25:28 -0800233 virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
Prabir Pradhan7e186182020-11-10 13:56:45 -0800234 void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800235
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800236 virtual void dump(std::string& dump) override;
237
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800238 ~InputClassifier();
239
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700240 // Called from InputManager
241 virtual void setMotionClassifierEnabled(bool enabled) override;
242
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800243private:
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800244 // Protect access to mMotionClassifier, since it may become null via a hidl callback
245 std::mutex mLock;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800246 // The next stage to pass input events to
247 sp<InputListenerInterface> mListener;
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800248
249 std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
250 std::thread mInitializeMotionClassifierThread;
251 /**
252 * Set the value of mMotionClassifier.
253 * This is called from 2 different threads:
254 * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier
255 * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause
256 * mMotionClassifier to become nullptr.
257 */
258 void setMotionClassifier(std::unique_ptr<MotionClassifierInterface> motionClassifier);
259
260 /**
261 * The deathRecipient will call setMotionClassifier(null) when the HAL dies.
262 */
263 class HalDeathRecipient : public android::hardware::hidl_death_recipient {
264 public:
265 explicit HalDeathRecipient(InputClassifier& parent);
266 virtual void serviceDied(uint64_t cookie,
267 const wp<android::hidl::base::V1_0::IBase>& who) override;
268
269 private:
270 InputClassifier& mParent;
271 };
272 // We retain a reference to death recipient, because the death recipient will be calling
273 // ~MotionClassifier if the HAL dies.
274 // If we don't retain a reference, and MotionClassifier is the only owner of the death
275 // recipient, the serviceDied call will cause death recipient to call its own destructor.
276 sp<HalDeathRecipient> mHalDeathRecipient;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800277};
278
279} // namespace android
Greg Kaiser04b3a052019-01-29 07:10:14 -0800280#endif