blob: 4b9dae275b47842d464e1abbbccdc931ba04cc4a [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
20#include <utils/RefBase.h>
21#include <unordered_map>
22#include <thread>
23
24#include "BlockingQueue.h"
25#include "InputListener.h"
26#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
27
28namespace android {
29
30enum class ClassifierEventType : uint8_t {
31 MOTION = 0,
32 DEVICE_RESET = 1,
33 HAL_RESET = 2,
34 EXIT = 3,
35};
36
37struct ClassifierEvent {
38 ClassifierEventType type;
39 std::unique_ptr<NotifyArgs> args;
40
41 ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args);
42 ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args);
43 ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args);
44 ClassifierEvent(ClassifierEvent&& other);
45 ClassifierEvent& operator=(ClassifierEvent&& other);
46
47 // Convenience function to create a HAL_RESET event
48 static ClassifierEvent createHalResetEvent();
49 // Convenience function to create an EXIT event
50 static ClassifierEvent createExitEvent();
51
52 std::optional<int32_t> getDeviceId() const;
53};
54
55// --- Interfaces ---
56
57/**
58 * Interface for adding a MotionClassification to NotifyMotionArgs.
59 *
60 * To implement, override the classify function.
61 */
62class MotionClassifierInterface {
63public:
64 MotionClassifierInterface() { }
65 virtual ~MotionClassifierInterface() { }
66 /**
67 * Based on the motion event described by NotifyMotionArgs,
68 * provide a MotionClassification for the current gesture.
69 */
70 virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
71 virtual void reset() = 0;
72 virtual void reset(const NotifyDeviceResetArgs& args) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080073
74 /**
75 * Dump the state of the motion classifier
76 */
77 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080078};
79
80/**
81 * Base interface for an InputListener stage.
82 * Provides classification to events.
83 */
84class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080085public:
86 /**
87 * Dump the state of the input classifier.
88 * This method may be called on any thread (usually by the input manager).
89 */
90 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080091protected:
92 InputClassifierInterface() { }
93 virtual ~InputClassifierInterface() { }
94};
95
96// --- Implementations ---
97
98/**
99 * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
100 * in order to determine the classification for the current gesture.
101 *
102 * The InputClassifier HAL may keep track of the entire gesture in order to determine
103 * the classification, and may be hardware-specific. It may use the data in
104 * NotifyMotionArgs::videoFrames field to drive the classification decisions.
105 * The HAL is called from a separate thread.
106 */
Greg Kaiser04b3a052019-01-29 07:10:14 -0800107class MotionClassifier final : public MotionClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800108public:
109 MotionClassifier(sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
110 ~MotionClassifier();
111 /**
112 * Classifies events asynchronously; that is, it doesn't block events on a classification,
113 * but instead sends them over to the classifier HAL
114 * and after a classification is determined,
115 * it then marks the next event it sees in the stream with it.
116 *
117 * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
118 * in a particular gesture.
119 */
120 virtual MotionClassification classify(const NotifyMotionArgs& args) override;
121 virtual void reset() override;
122 virtual void reset(const NotifyDeviceResetArgs& args) override;
123
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800124 virtual void dump(std::string& dump) override;
125
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800126private:
127 // The events that need to be sent to the HAL.
128 BlockingQueue<ClassifierEvent> mEvents;
129 /**
130 * Thread that will communicate with InputClassifier HAL.
131 * This should be the only thread that communicates with InputClassifier HAL,
132 * because this thread is allowed to block on the HAL calls.
133 */
134 std::thread mHalThread;
135 /**
136 * Print an error message if the caller is not on the InputClassifier thread.
137 * Caller must supply the name of the calling function as __function__
138 */
139 void ensureHalThread(const char* function);
140 /**
141 * Call the InputClassifier HAL
142 */
143 void callInputClassifierHal();
144 /**
145 * Access to the InputClassifier HAL
146 */
147 sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
148 std::mutex mLock;
149 /**
150 * Per-device input classifications. Should only be accessed using the
151 * getClassification / setClassification methods.
152 */
153 std::unordered_map<int32_t /*deviceId*/, MotionClassification>
154 mClassifications; //GUARDED_BY(mLock);
155 /**
156 * Set the current classification for a given device.
157 */
158 void setClassification(int32_t deviceId, MotionClassification classification);
159 /**
160 * Get the current classification for a given device.
161 */
162 MotionClassification getClassification(int32_t deviceId);
163 void updateClassification(int32_t deviceId, nsecs_t eventTime,
164 MotionClassification classification);
165 /**
166 * Clear all current classifications
167 */
168 void clearClassifications();
169 /**
170 * Per-device times when the last ACTION_DOWN was received.
171 * Used to reject late classifications that do not belong to the current gesture.
172 *
173 * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
174 */
175 std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/>
176 mLastDownTimes; //GUARDED_BY(mLock);
177 void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800178
179 /**
180 * Exit the InputClassifier HAL thread.
181 * Useful for tests to ensure proper cleanup.
182 */
183 void requestExit();
184};
185
186/**
187 * Implementation of the InputClassifierInterface.
188 * Represents a separate stage of input processing. All of the input events go through this stage.
189 * Acts as a passthrough for all input events except for motion events.
190 * The events of motion type are sent to MotionClassifier.
191 */
192class InputClassifier : public InputClassifierInterface {
193public:
194 explicit InputClassifier(const sp<InputListenerInterface>& listener);
Siarhei Vishniakou45bb0882019-02-04 14:25:28 -0800195
196 virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
197 virtual void notifyKey(const NotifyKeyArgs* args) override;
198 virtual void notifyMotion(const NotifyMotionArgs* args) override;
199 virtual void notifySwitch(const NotifySwitchArgs* args) override;
200 virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800201
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800202 virtual void dump(std::string& dump) override;
203
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800204private:
205 std::unique_ptr<MotionClassifierInterface> mMotionClassifier = nullptr;
206 // The next stage to pass input events to
207 sp<InputListenerInterface> mListener;
208};
209
210} // namespace android
Greg Kaiser04b3a052019-01-29 07:10:14 -0800211#endif