1 /*
2 * Copyright 2023 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 #include "../InputDeviceMetricsSource.h"
18
19 #include <NotifyArgsBuilders.h>
20
21 #include <android/input.h>
22 #include <ftl/enum.h>
23 #include <gtest/gtest.h>
24 #include <input/Input.h>
25 #include <input/InputEventBuilders.h>
26 #include <linux/input.h>
27
28 #include <set>
29
30 namespace android {
31
32 namespace {
33
34 constexpr auto ALL_USAGE_SOURCES = ftl::enum_range<InputDeviceUsageSource>();
35 constexpr uint32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN;
36 constexpr uint32_t STYLUS = AINPUT_SOURCE_STYLUS;
37 constexpr uint32_t KEY_SOURCES =
38 AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD;
39 constexpr int32_t POINTER_1_DOWN =
40 AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
41
42 } // namespace
43
44 // --- InputDeviceMetricsSourceDeviceClassificationTest ---
45
46 class DeviceClassificationFixture : public ::testing::Test,
47 public ::testing::WithParamInterface<InputDeviceUsageSource> {};
48
TEST_P(DeviceClassificationFixture,ValidClassifications)49 TEST_P(DeviceClassificationFixture, ValidClassifications) {
50 const InputDeviceUsageSource usageSource = GetParam();
51
52 // Use a switch to ensure a test is added for all source classifications.
53 switch (usageSource) {
54 case InputDeviceUsageSource::UNKNOWN: {
55 ASSERT_EQ(InputDeviceUsageSource::UNKNOWN,
56 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NONE,
57 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, TOUCHSCREEN)
58 .build()));
59
60 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::UNKNOWN};
61 ASSERT_EQ(srcs,
62 getUsageSourcesForMotionArgs(
63 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_KEYBOARD)
64 .pointer(PointerBuilder(/*id=*/1, ToolType::PALM)
65 .x(100)
66 .y(200))
67 .build()));
68 break;
69 }
70
71 case InputDeviceUsageSource::BUTTONS: {
72 ASSERT_EQ(InputDeviceUsageSource::BUTTONS,
73 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC,
74 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES)
75 .keyCode(AKEYCODE_STYLUS_BUTTON_TAIL)
76 .build()));
77 break;
78 }
79
80 case InputDeviceUsageSource::KEYBOARD: {
81 ASSERT_EQ(InputDeviceUsageSource::KEYBOARD,
82 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC,
83 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES)
84 .build()));
85 break;
86 }
87
88 case InputDeviceUsageSource::DPAD: {
89 ASSERT_EQ(InputDeviceUsageSource::DPAD,
90 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC,
91 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES)
92 .keyCode(AKEYCODE_DPAD_CENTER)
93 .build()));
94
95 ASSERT_EQ(InputDeviceUsageSource::DPAD,
96 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC,
97 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES)
98 .keyCode(AKEYCODE_DPAD_CENTER)
99 .build()));
100 break;
101 }
102
103 case InputDeviceUsageSource::GAMEPAD: {
104 ASSERT_EQ(InputDeviceUsageSource::GAMEPAD,
105 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC,
106 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES)
107 .keyCode(AKEYCODE_BUTTON_A)
108 .build()));
109
110 ASSERT_EQ(InputDeviceUsageSource::GAMEPAD,
111 getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC,
112 KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES)
113 .keyCode(AKEYCODE_BUTTON_A)
114 .build()));
115 break;
116 }
117
118 case InputDeviceUsageSource::JOYSTICK: {
119 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::JOYSTICK};
120 ASSERT_EQ(srcs,
121 getUsageSourcesForMotionArgs(
122 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_JOYSTICK)
123 .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN)
124 .axis(AMOTION_EVENT_AXIS_GAS, 1.f))
125 .build()));
126 break;
127 }
128
129 case InputDeviceUsageSource::MOUSE: {
130 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::MOUSE};
131 ASSERT_EQ(srcs,
132 getUsageSourcesForMotionArgs(
133 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
134 AINPUT_SOURCE_MOUSE)
135 .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE)
136 .x(100)
137 .y(200))
138 .build()));
139 break;
140 }
141
142 case InputDeviceUsageSource::MOUSE_CAPTURED: {
143 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::MOUSE_CAPTURED};
144 ASSERT_EQ(srcs,
145 getUsageSourcesForMotionArgs(
146 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE,
147 AINPUT_SOURCE_MOUSE_RELATIVE)
148 .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE)
149 .x(100)
150 .y(200)
151 .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 100)
152 .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 200))
153 .build()));
154 break;
155 }
156
157 case InputDeviceUsageSource::TOUCHPAD: {
158 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::TOUCHPAD};
159 ASSERT_EQ(srcs,
160 getUsageSourcesForMotionArgs(
161 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
162 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
163 .x(100)
164 .y(200))
165 .build()));
166 break;
167 }
168
169 case InputDeviceUsageSource::TOUCHPAD_CAPTURED: {
170 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::TOUCHPAD_CAPTURED};
171 ASSERT_EQ(srcs,
172 getUsageSourcesForMotionArgs(
173 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHPAD)
174 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
175 .x(100)
176 .y(200)
177 .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 1)
178 .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 2))
179 .build()));
180 break;
181 }
182
183 case InputDeviceUsageSource::ROTARY_ENCODER: {
184 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::ROTARY_ENCODER};
185 ASSERT_EQ(srcs,
186 getUsageSourcesForMotionArgs(
187 MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL,
188 AINPUT_SOURCE_ROTARY_ENCODER)
189 .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN)
190 .axis(AMOTION_EVENT_AXIS_SCROLL, 10)
191 .axis(AMOTION_EVENT_AXIS_VSCROLL, 10))
192 .build()));
193 break;
194 }
195
196 case InputDeviceUsageSource::STYLUS_DIRECT: {
197 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::STYLUS_DIRECT};
198 ASSERT_EQ(srcs,
199 getUsageSourcesForMotionArgs(
200 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
201 STYLUS | TOUCHSCREEN)
202 .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS)
203 .x(100)
204 .y(200))
205 .build()));
206 break;
207 }
208
209 case InputDeviceUsageSource::STYLUS_INDIRECT: {
210 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::STYLUS_INDIRECT};
211 ASSERT_EQ(srcs,
212 getUsageSourcesForMotionArgs(
213 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
214 STYLUS | TOUCHSCREEN | AINPUT_SOURCE_MOUSE)
215 .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS)
216 .x(100)
217 .y(200))
218 .build()));
219 break;
220 }
221
222 case InputDeviceUsageSource::STYLUS_FUSED: {
223 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::STYLUS_FUSED};
224 ASSERT_EQ(srcs,
225 getUsageSourcesForMotionArgs(
226 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
227 AINPUT_SOURCE_BLUETOOTH_STYLUS | TOUCHSCREEN)
228 .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS)
229 .x(100)
230 .y(200))
231 .build()));
232 break;
233 }
234
235 case InputDeviceUsageSource::TOUCH_NAVIGATION: {
236 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::TOUCH_NAVIGATION};
237 ASSERT_EQ(srcs,
238 getUsageSourcesForMotionArgs(
239 MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE,
240 AINPUT_SOURCE_TOUCH_NAVIGATION)
241 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
242 .x(100)
243 .y(200))
244 .build()));
245 break;
246 }
247
248 case InputDeviceUsageSource::TOUCHSCREEN: {
249 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::TOUCHSCREEN};
250 ASSERT_EQ(srcs,
251 getUsageSourcesForMotionArgs(
252 MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN)
253 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER)
254 .x(100)
255 .y(200))
256 .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER)
257 .x(300)
258 .y(400))
259 .build()));
260 break;
261 }
262
263 case InputDeviceUsageSource::TRACKBALL: {
264 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::TRACKBALL};
265 ASSERT_EQ(srcs,
266 getUsageSourcesForMotionArgs(
267 MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL,
268 AINPUT_SOURCE_TRACKBALL)
269 .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN)
270 .axis(AMOTION_EVENT_AXIS_VSCROLL, 100)
271 .axis(AMOTION_EVENT_AXIS_HSCROLL, 200))
272 .build()));
273 break;
274 }
275 }
276 }
277
278 INSTANTIATE_TEST_SUITE_P(InputDeviceMetricsSourceDeviceClassificationTest,
279 DeviceClassificationFixture,
280 ::testing::ValuesIn(ALL_USAGE_SOURCES.begin(), ALL_USAGE_SOURCES.end()),
__anon548648b80202(const testing::TestParamInfo<InputDeviceUsageSource>& testParamInfo) 281 [](const testing::TestParamInfo<InputDeviceUsageSource>& testParamInfo) {
282 return ftl::enum_string(testParamInfo.param);
283 });
284
TEST(InputDeviceMetricsSourceDeviceClassificationTest,MixedClassificationTouchscreenStylus)285 TEST(InputDeviceMetricsSourceDeviceClassificationTest, MixedClassificationTouchscreenStylus) {
286 std::set<InputDeviceUsageSource> srcs{InputDeviceUsageSource::TOUCHSCREEN,
287 InputDeviceUsageSource::STYLUS_DIRECT};
288 ASSERT_EQ(srcs,
289 getUsageSourcesForMotionArgs(
290 MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN | STYLUS)
291 .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(100).y(200))
292 .pointer(PointerBuilder(/*id=*/2, ToolType::STYLUS).x(300).y(400))
293 .build()));
294 }
295
296 } // namespace android
297