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 "CursorInputMapper.h"
18
19 #include <list>
20 #include <string>
21 #include <tuple>
22 #include <variant>
23
24 #include <android-base/logging.h>
25 #include <com_android_input_flags.h>
26 #include <gtest/gtest.h>
27 #include <input/DisplayViewport.h>
28 #include <linux/input-event-codes.h>
29 #include <linux/input.h>
30 #include <utils/Timers.h>
31
32 #include "InputMapperTest.h"
33 #include "InputReaderBase.h"
34 #include "InterfaceMocks.h"
35 #include "NotifyArgs.h"
36 #include "TestEventMatchers.h"
37 #include "ui/Rotation.h"
38
39 #define TAG "CursorInputMapper_test"
40
41 namespace android {
42
43 using testing::AllOf;
44 using testing::Return;
45 using testing::VariantWith;
46 constexpr auto ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
47 constexpr auto ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
48 constexpr auto ACTION_UP = AMOTION_EVENT_ACTION_UP;
49 constexpr auto BUTTON_PRESS = AMOTION_EVENT_ACTION_BUTTON_PRESS;
50 constexpr auto BUTTON_RELEASE = AMOTION_EVENT_ACTION_BUTTON_RELEASE;
51 constexpr auto HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE;
52 constexpr auto INVALID_CURSOR_POSITION = AMOTION_EVENT_INVALID_CURSOR_POSITION;
53 constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT;
54 constexpr ui::LogicalDisplayId SECONDARY_DISPLAY_ID = ui::LogicalDisplayId{DISPLAY_ID.val() + 1};
55 constexpr int32_t DISPLAY_WIDTH = 480;
56 constexpr int32_t DISPLAY_HEIGHT = 800;
57
58 constexpr int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
59
60 namespace {
61
createPrimaryViewport(ui::Rotation orientation)62 DisplayViewport createPrimaryViewport(ui::Rotation orientation) {
63 const bool isRotated =
64 orientation == ui::Rotation::Rotation90 || orientation == ui::Rotation::Rotation270;
65 DisplayViewport v;
66 v.displayId = DISPLAY_ID;
67 v.orientation = orientation;
68 v.logicalRight = isRotated ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
69 v.logicalBottom = isRotated ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
70 v.physicalRight = isRotated ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
71 v.physicalBottom = isRotated ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
72 v.deviceWidth = isRotated ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
73 v.deviceHeight = isRotated ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
74 v.isActive = true;
75 v.uniqueId = "local:1";
76 return v;
77 }
78
createSecondaryViewport()79 DisplayViewport createSecondaryViewport() {
80 DisplayViewport v;
81 v.displayId = SECONDARY_DISPLAY_ID;
82 v.orientation = ui::Rotation::Rotation0;
83 v.logicalRight = DISPLAY_HEIGHT;
84 v.logicalBottom = DISPLAY_WIDTH;
85 v.physicalRight = DISPLAY_HEIGHT;
86 v.physicalBottom = DISPLAY_WIDTH;
87 v.deviceWidth = DISPLAY_HEIGHT;
88 v.deviceHeight = DISPLAY_WIDTH;
89 v.isActive = true;
90 v.uniqueId = "local:2";
91 v.type = ViewportType::EXTERNAL;
92 return v;
93 }
94
95 /**
96 * A fake InputDeviceContext that allows the associated viewport to be specified for the mapper.
97 *
98 * This is currently necessary because InputMapperUnitTest doesn't register the mappers it creates
99 * with the InputDevice object, meaning that InputDevice::isIgnored becomes true, and the input
100 * device doesn't set its associated viewport when it's configured.
101 *
102 * TODO(b/319217713): work out a way to avoid this fake.
103 */
104 class ViewportFakingInputDeviceContext : public InputDeviceContext {
105 public:
ViewportFakingInputDeviceContext(InputDevice & device,int32_t eventHubId,std::optional<DisplayViewport> viewport)106 ViewportFakingInputDeviceContext(InputDevice& device, int32_t eventHubId,
107 std::optional<DisplayViewport> viewport)
108 : InputDeviceContext(device, eventHubId), mAssociatedViewport(viewport) {}
109
ViewportFakingInputDeviceContext(InputDevice & device,int32_t eventHubId,ui::Rotation orientation)110 ViewportFakingInputDeviceContext(InputDevice& device, int32_t eventHubId,
111 ui::Rotation orientation)
112 : ViewportFakingInputDeviceContext(device, eventHubId,
113 createPrimaryViewport(orientation)) {}
114
getAssociatedViewport() const115 std::optional<DisplayViewport> getAssociatedViewport() const override {
116 return mAssociatedViewport;
117 }
118
setViewport(const std::optional<DisplayViewport> & viewport)119 void setViewport(const std::optional<DisplayViewport>& viewport) {
120 mAssociatedViewport = viewport;
121 }
122
123 private:
124 std::optional<DisplayViewport> mAssociatedViewport;
125 };
126
127 } // namespace
128
129 namespace input_flags = com::android::input::flags;
130
131 /**
132 * Unit tests for CursorInputMapper.
133 * These classes are named 'CursorInputMapperUnitTest...' to avoid name collision with the existing
134 * 'CursorInputMapperTest...' classes. If all of the CursorInputMapper tests are migrated here, the
135 * name can be simplified to 'CursorInputMapperTest'.
136 *
137 * TODO(b/283812079): move the remaining CursorInputMapper tests here. The ones that are left all
138 * depend on viewport association, for which we'll need to fake InputDeviceContext.
139 */
140 class CursorInputMapperUnitTestBase : public InputMapperUnitTest {
141 protected:
SetUp()142 void SetUp() override { SetUpWithBus(BUS_USB); }
SetUpWithBus(int bus)143 void SetUpWithBus(int bus) override {
144 InputMapperUnitTest::SetUpWithBus(bus);
145
146 // Current scan code state - all keys are UP by default
147 setScanCodeState(KeyState::UP,
148 {BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_BACK, BTN_SIDE, BTN_FORWARD,
149 BTN_EXTRA, BTN_TASK});
150 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_WHEEL))
151 .WillRepeatedly(Return(false));
152 EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL))
153 .WillRepeatedly(Return(false));
154
155 mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
156 mFakePolicy->addDisplayViewport(createPrimaryViewport(ui::Rotation::Rotation0));
157 }
158
createMapper()159 void createMapper() {
160 createDevice();
161 mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration);
162 }
163
setPointerCapture(bool enabled)164 void setPointerCapture(bool enabled) {
165 mReaderConfiguration.pointerCaptureRequest.window = enabled ? sp<BBinder>::make() : nullptr;
166 mReaderConfiguration.pointerCaptureRequest.seq = 1;
167 int32_t generation = mDevice->getGeneration();
168 std::list<NotifyArgs> args =
169 mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
170 InputReaderConfiguration::Change::POINTER_CAPTURE);
171 ASSERT_THAT(args,
172 ElementsAre(VariantWith<NotifyDeviceResetArgs>(
173 AllOf(WithDeviceId(DEVICE_ID), WithEventTime(ARBITRARY_TIME)))));
174
175 // Check that generation also got bumped
176 ASSERT_GT(mDevice->getGeneration(), generation);
177 }
178
testMotionRotation(int32_t originalX,int32_t originalY,int32_t rotatedX,int32_t rotatedY)179 void testMotionRotation(int32_t originalX, int32_t originalY, int32_t rotatedX,
180 int32_t rotatedY) {
181 std::list<NotifyArgs> args;
182 args += process(ARBITRARY_TIME, EV_REL, REL_X, originalX);
183 args += process(ARBITRARY_TIME, EV_REL, REL_Y, originalY);
184 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
185 ASSERT_THAT(args,
186 ElementsAre(VariantWith<NotifyMotionArgs>(
187 AllOf(WithMotionAction(ACTION_MOVE),
188 WithCoords(float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD,
189 float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD)))));
190 }
191 };
192
193 class CursorInputMapperUnitTest : public CursorInputMapperUnitTestBase {
194 protected:
SetUp()195 void SetUp() override {
196 input_flags::enable_new_mouse_pointer_ballistics(false);
197 CursorInputMapperUnitTestBase::SetUp();
198 }
199 };
200
TEST_F(CursorInputMapperUnitTest,GetSourcesReturnsMouseInPointerMode)201 TEST_F(CursorInputMapperUnitTest, GetSourcesReturnsMouseInPointerMode) {
202 mPropertyMap.addProperty("cursor.mode", "pointer");
203 createMapper();
204
205 ASSERT_EQ(AINPUT_SOURCE_MOUSE, mMapper->getSources());
206 }
207
TEST_F(CursorInputMapperUnitTest,GetSourcesReturnsTrackballInNavigationMode)208 TEST_F(CursorInputMapperUnitTest, GetSourcesReturnsTrackballInNavigationMode) {
209 mPropertyMap.addProperty("cursor.mode", "navigation");
210 createMapper();
211
212 ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mMapper->getSources());
213 }
214
215 /**
216 * Move the mouse and then click the button. Check whether HOVER_EXIT is generated when hovering
217 * ends. Currently, it is not.
218 */
TEST_F(CursorInputMapperUnitTest,HoverAndLeftButtonPress)219 TEST_F(CursorInputMapperUnitTest, HoverAndLeftButtonPress) {
220 createMapper();
221 std::list<NotifyArgs> args;
222
223 // Move the cursor a little
224 args += process(EV_REL, REL_X, 10);
225 args += process(EV_REL, REL_Y, 20);
226 args += process(EV_SYN, SYN_REPORT, 0);
227 ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
228
229 // Now click the mouse button
230 args.clear();
231 args += process(EV_KEY, BTN_LEFT, 1);
232 args += process(EV_SYN, SYN_REPORT, 0);
233 ASSERT_THAT(args,
234 ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
235 VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS))));
236
237 // Move some more.
238 args.clear();
239 args += process(EV_REL, REL_X, 10);
240 args += process(EV_REL, REL_Y, 20);
241 args += process(EV_SYN, SYN_REPORT, 0);
242 ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_MOVE))));
243
244 // Release the button
245 args.clear();
246 args += process(EV_KEY, BTN_LEFT, 0);
247 args += process(EV_SYN, SYN_REPORT, 0);
248 ASSERT_THAT(args,
249 ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
250 VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
251 VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
252 }
253
254 /**
255 * Set pointer capture and check that ACTION_MOVE events are emitted from CursorInputMapper.
256 * During pointer capture, source should be set to MOUSE_RELATIVE. When the capture is disabled,
257 * the events should be generated normally:
258 * 1) The source should return to SOURCE_MOUSE
259 * 2) Cursor position should be incremented by the relative device movements
260 * 3) Cursor position of NotifyMotionArgs should now be getting populated.
261 * When it's not SOURCE_MOUSE, CursorInputMapper doesn't populate cursor position values.
262 */
TEST_F(CursorInputMapperUnitTest,ProcessPointerCapture)263 TEST_F(CursorInputMapperUnitTest, ProcessPointerCapture) {
264 createMapper();
265 setPointerCapture(true);
266 std::list<NotifyArgs> args;
267
268 // Move.
269 args += process(EV_REL, REL_X, 10);
270 args += process(EV_REL, REL_Y, 20);
271 args += process(EV_SYN, SYN_REPORT, 0);
272
273 ASSERT_THAT(args,
274 ElementsAre(VariantWith<NotifyMotionArgs>(
275 AllOf(WithMotionAction(ACTION_MOVE),
276 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), WithCoords(10.0f, 20.0f),
277 WithRelativeMotion(10.0f, 20.0f),
278 WithCursorPosition(INVALID_CURSOR_POSITION,
279 INVALID_CURSOR_POSITION)))));
280
281 // Button press.
282 args.clear();
283 args += process(EV_KEY, BTN_MOUSE, 1);
284 args += process(EV_SYN, SYN_REPORT, 0);
285 ASSERT_THAT(args,
286 ElementsAre(VariantWith<NotifyMotionArgs>(
287 AllOf(WithMotionAction(ACTION_DOWN),
288 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
289 WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
290 VariantWith<NotifyMotionArgs>(
291 AllOf(WithMotionAction(BUTTON_PRESS),
292 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
293 WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
294
295 // Button release.
296 args.clear();
297 args += process(EV_KEY, BTN_MOUSE, 0);
298 args += process(EV_SYN, SYN_REPORT, 0);
299 ASSERT_THAT(args,
300 ElementsAre(VariantWith<NotifyMotionArgs>(
301 AllOf(WithMotionAction(BUTTON_RELEASE),
302 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
303 WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
304 VariantWith<NotifyMotionArgs>(
305 AllOf(WithMotionAction(ACTION_UP),
306 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
307 WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
308
309 // Another move.
310 args.clear();
311 args += process(EV_REL, REL_X, 30);
312 args += process(EV_REL, REL_Y, 40);
313 args += process(EV_SYN, SYN_REPORT, 0);
314 ASSERT_THAT(args,
315 ElementsAre(VariantWith<NotifyMotionArgs>(
316 AllOf(WithMotionAction(ACTION_MOVE),
317 WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), WithCoords(30.0f, 40.0f),
318 WithRelativeMotion(30.0f, 40.0f)))));
319
320 // Disable pointer capture. Afterwards, events should be generated the usual way.
321 setPointerCapture(false);
322 const auto expectedCoords = WithCoords(0, 0);
323 const auto expectedCursorPosition =
324 WithCursorPosition(INVALID_CURSOR_POSITION, INVALID_CURSOR_POSITION);
325 args.clear();
326 args += process(EV_REL, REL_X, 10);
327 args += process(EV_REL, REL_Y, 20);
328 args += process(EV_SYN, SYN_REPORT, 0);
329 ASSERT_THAT(args,
330 ElementsAre(VariantWith<NotifyMotionArgs>(
331 AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
332 expectedCoords, expectedCursorPosition,
333 WithRelativeMotion(10.0f, 20.0f)))));
334 }
335
TEST_F(CursorInputMapperUnitTest,PopulateDeviceInfoReturnsScaledRangeInNavigationMode)336 TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsScaledRangeInNavigationMode) {
337 mPropertyMap.addProperty("cursor.mode", "navigation");
338 createMapper();
339
340 InputDeviceInfo info;
341 mMapper->populateDeviceInfo(info);
342
343 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
344 -1.0f, 1.0f, 0.0f,
345 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
346 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL,
347 -1.0f, 1.0f, 0.0f,
348 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
349 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
350 AINPUT_SOURCE_TRACKBALL, 0.0f, 1.0f, 0.0f, 0.0f));
351 }
352
TEST_F(CursorInputMapperUnitTest,ProcessShouldSetAllFieldsAndIncludeGlobalMetaState)353 TEST_F(CursorInputMapperUnitTest, ProcessShouldSetAllFieldsAndIncludeGlobalMetaState) {
354 mPropertyMap.addProperty("cursor.mode", "navigation");
355 createMapper();
356
357 EXPECT_CALL(mMockInputReaderContext, getGlobalMetaState())
358 .WillRepeatedly(Return(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON));
359
360 std::list<NotifyArgs> args;
361
362 // Button press.
363 // Mostly testing non x/y behavior here so we don't need to check again elsewhere.
364 args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
365 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
366 EXPECT_THAT(args,
367 ElementsAre(VariantWith<NotifyMotionArgs>(
368 AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID),
369 WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
370 WithEdgeFlags(0), WithPolicyFlags(0),
371 WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
372 WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
373 WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
374 WithPointerCount(1), WithPointerId(0, 0),
375 WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f),
376 WithPressure(1.0f),
377 WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
378 TRACKBALL_MOVEMENT_THRESHOLD),
379 WithDownTime(ARBITRARY_TIME))),
380 VariantWith<NotifyMotionArgs>(
381 AllOf(WithEventTime(ARBITRARY_TIME), WithDeviceId(DEVICE_ID),
382 WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
383 WithEdgeFlags(0), WithPolicyFlags(0),
384 WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
385 WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
386 WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
387 WithPointerCount(1), WithPointerId(0, 0),
388 WithToolType(ToolType::MOUSE), WithCoords(0.0f, 0.0f),
389 WithPressure(1.0f),
390 WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
391 TRACKBALL_MOVEMENT_THRESHOLD),
392 WithDownTime(ARBITRARY_TIME)))));
393 args.clear();
394
395 // Button release. Should have same down time.
396 args += process(ARBITRARY_TIME + 1, EV_KEY, BTN_MOUSE, 0);
397 args += process(ARBITRARY_TIME + 1, EV_SYN, SYN_REPORT, 0);
398 EXPECT_THAT(args,
399 ElementsAre(VariantWith<NotifyMotionArgs>(
400 AllOf(WithEventTime(ARBITRARY_TIME + 1),
401 WithDeviceId(DEVICE_ID),
402 WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
403 WithEdgeFlags(0), WithPolicyFlags(0),
404 WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
405 WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
406 WithButtonState(0), WithPointerCount(1),
407 WithPointerId(0, 0), WithToolType(ToolType::MOUSE),
408 WithCoords(0.0f, 0.0f), WithPressure(0.0f),
409 WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
410 TRACKBALL_MOVEMENT_THRESHOLD),
411 WithDownTime(ARBITRARY_TIME))),
412 VariantWith<NotifyMotionArgs>(
413 AllOf(WithEventTime(ARBITRARY_TIME + 1),
414 WithDeviceId(DEVICE_ID),
415 WithSource(AINPUT_SOURCE_TRACKBALL), WithFlags(0),
416 WithEdgeFlags(0), WithPolicyFlags(0),
417 WithMotionAction(AMOTION_EVENT_ACTION_UP),
418 WithMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON),
419 WithButtonState(0), WithPointerCount(1),
420 WithPointerId(0, 0), WithToolType(ToolType::MOUSE),
421 WithCoords(0.0f, 0.0f), WithPressure(0.0f),
422 WithPrecision(TRACKBALL_MOVEMENT_THRESHOLD,
423 TRACKBALL_MOVEMENT_THRESHOLD),
424 WithDownTime(ARBITRARY_TIME)))));
425 }
426
TEST_F(CursorInputMapperUnitTest,ProcessShouldHandleIndependentXYUpdates)427 TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentXYUpdates) {
428 mPropertyMap.addProperty("cursor.mode", "navigation");
429 createMapper();
430
431 std::list<NotifyArgs> args;
432
433 // Motion in X but not Y.
434 args += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
435 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
436 EXPECT_THAT(args,
437 ElementsAre(VariantWith<NotifyMotionArgs>(
438 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
439 WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f),
440 WithPressure(0.0f)))));
441 args.clear();
442
443 // Motion in Y but not X.
444 args += process(ARBITRARY_TIME, EV_REL, REL_Y, -2);
445 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
446 EXPECT_THAT(args,
447 ElementsAre(VariantWith<NotifyMotionArgs>(
448 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
449 WithCoords(0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD),
450 WithPressure(0.0f)))));
451 args.clear();
452 }
453
TEST_F(CursorInputMapperUnitTest,ProcessShouldHandleIndependentButtonUpdates)454 TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleIndependentButtonUpdates) {
455 mPropertyMap.addProperty("cursor.mode", "navigation");
456 createMapper();
457
458 std::list<NotifyArgs> args;
459
460 // Button press.
461 args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
462 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
463 EXPECT_THAT(args,
464 ElementsAre(VariantWith<NotifyMotionArgs>(
465 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
466 WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
467 VariantWith<NotifyMotionArgs>(
468 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
469 WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
470 args.clear();
471
472 // Button release.
473 args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 0);
474 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
475 EXPECT_THAT(args,
476 ElementsAre(VariantWith<NotifyMotionArgs>(
477 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
478 WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
479 VariantWith<NotifyMotionArgs>(
480 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
481 WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
482 }
483
TEST_F(CursorInputMapperUnitTest,ProcessShouldHandleCombinedXYAndButtonUpdates)484 TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleCombinedXYAndButtonUpdates) {
485 mPropertyMap.addProperty("cursor.mode", "navigation");
486 createMapper();
487
488 std::list<NotifyArgs> args;
489
490 // Combined X, Y and Button.
491 args += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
492 args += process(ARBITRARY_TIME, EV_REL, REL_Y, -2);
493 args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
494 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
495 EXPECT_THAT(args,
496 ElementsAre(VariantWith<NotifyMotionArgs>(
497 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
498 WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD,
499 -2.0f / TRACKBALL_MOVEMENT_THRESHOLD),
500 WithPressure(1.0f))),
501 VariantWith<NotifyMotionArgs>(
502 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
503 WithCoords(1.0f / TRACKBALL_MOVEMENT_THRESHOLD,
504 -2.0f / TRACKBALL_MOVEMENT_THRESHOLD),
505 WithPressure(1.0f)))));
506 args.clear();
507
508 // Move X, Y a bit while pressed.
509 args += process(ARBITRARY_TIME, EV_REL, REL_X, 2);
510 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 1);
511 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
512 EXPECT_THAT(args,
513 ElementsAre(VariantWith<NotifyMotionArgs>(
514 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
515 WithCoords(2.0f / TRACKBALL_MOVEMENT_THRESHOLD,
516 1.0f / TRACKBALL_MOVEMENT_THRESHOLD),
517 WithPressure(1.0f)))));
518 args.clear();
519
520 // Release Button.
521 args += process(ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 0);
522 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
523 EXPECT_THAT(args,
524 ElementsAre(VariantWith<NotifyMotionArgs>(
525 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
526 WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
527 VariantWith<NotifyMotionArgs>(
528 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
529 WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
530 args.clear();
531 }
532
TEST_F(CursorInputMapperUnitTest,ProcessShouldNotRotateMotionsWhenOrientationAware)533 TEST_F(CursorInputMapperUnitTest, ProcessShouldNotRotateMotionsWhenOrientationAware) {
534 // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
535 // need to be rotated.
536 mPropertyMap.addProperty("cursor.mode", "navigation");
537 mPropertyMap.addProperty("cursor.orientationAware", "1");
538 createDevice();
539 ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, ui::Rotation::Rotation90);
540 mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
541
542 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, 1));
543 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, 1));
544 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 1, 0));
545 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, -1));
546 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, -1));
547 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, -1));
548 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, -1, 0));
549 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, 1));
550 }
551
TEST_F(CursorInputMapperUnitTest,ProcessShouldRotateMotionsWhenNotOrientationAware)552 TEST_F(CursorInputMapperUnitTest, ProcessShouldRotateMotionsWhenNotOrientationAware) {
553 // Since InputReader works in the un-rotated coordinate space, only devices that are not
554 // orientation-aware are affected by display rotation.
555 mPropertyMap.addProperty("cursor.mode", "navigation");
556 createDevice();
557 ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, ui::Rotation::Rotation0);
558 mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
559
560 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, 1));
561 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, 1));
562 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 1, 0));
563 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, -1));
564 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, -1));
565 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, -1));
566 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, -1, 0));
567 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, 1));
568
569 deviceContext.setViewport(createPrimaryViewport(ui::Rotation::Rotation90));
570 std::list<NotifyArgs> args =
571 mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
572 InputReaderConfiguration::Change::DISPLAY_INFO);
573 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, -1, 0));
574 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, -1, 1));
575 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 0, 1));
576 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, 1, 1));
577 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 1, 0));
578 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, 1, -1));
579 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 0, -1));
580 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, -1, -1));
581
582 deviceContext.setViewport(createPrimaryViewport(ui::Rotation::Rotation180));
583 args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
584 InputReaderConfiguration::Change::DISPLAY_INFO);
585 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 0, -1));
586 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, -1, -1));
587 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, -1, 0));
588 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, -1, 1));
589 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, 0, 1));
590 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, 1, 1));
591 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 1, 0));
592 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, -1));
593
594 deviceContext.setViewport(createPrimaryViewport(ui::Rotation::Rotation270));
595 args = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
596 InputReaderConfiguration::Change::DISPLAY_INFO);
597 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, 1, 1, 0));
598 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 1, 1, -1));
599 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, 0, 0, -1));
600 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 1, -1, -1, -1));
601 ASSERT_NO_FATAL_FAILURE(testMotionRotation( 0, -1, -1, 0));
602 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, -1, -1, 1));
603 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 0, 0, 1));
604 ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, 1));
605 }
606
TEST_F(CursorInputMapperUnitTest,PopulateDeviceInfoReturnsRangeFromPolicy)607 TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsRangeFromPolicy) {
608 mPropertyMap.addProperty("cursor.mode", "pointer");
609 mFakePolicy->clearViewports();
610 createMapper();
611
612 InputDeviceInfo info;
613 mMapper->populateDeviceInfo(info);
614
615 // Initially there should not be a valid motion range because there's no viewport or pointer
616 // bounds.
617 ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
618 ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
619 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
620 AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
621
622 // When the viewport and the default pointer display ID is set, then there should be a valid
623 // motion range.
624 mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
625 mFakePolicy->addDisplayViewport(createPrimaryViewport(ui::Rotation::Rotation0));
626 std::list<NotifyArgs> args =
627 mMapper->reconfigure(systemTime(), mReaderConfiguration,
628 InputReaderConfiguration::Change::DISPLAY_INFO);
629 ASSERT_THAT(args, testing::IsEmpty());
630
631 InputDeviceInfo info2;
632 mMapper->populateDeviceInfo(info2);
633
634 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE, 0,
635 DISPLAY_WIDTH - 1, 0.0f, 0.0f));
636 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE, 0,
637 DISPLAY_HEIGHT - 1, 0.0f, 0.0f));
638 ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE,
639 AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
640 }
641
TEST_F(CursorInputMapperUnitTest,ConfigureDisplayIdWithAssociatedViewport)642 TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdWithAssociatedViewport) {
643 DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
644 DisplayViewport secondaryViewport = createSecondaryViewport();
645 mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
646 // Set up the secondary display as the display on which the pointer should be shown.
647 // The InputDevice is not associated with any display.
648 createDevice();
649 ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
650 mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
651
652 std::list<NotifyArgs> args;
653 // Ensure input events are generated for the secondary display.
654 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
655 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
656 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
657 ASSERT_THAT(args,
658 ElementsAre(VariantWith<NotifyMotionArgs>(
659 AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
660 WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(0.0f, 0.0f)))));
661 }
662
TEST_F(CursorInputMapperUnitTest,ConfigureDisplayIdShouldGenerateEventForMismatchedPointerDisplay)663 TEST_F(CursorInputMapperUnitTest,
664 ConfigureDisplayIdShouldGenerateEventForMismatchedPointerDisplay) {
665 DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
666 DisplayViewport secondaryViewport = createSecondaryViewport();
667 mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
668 // Set up the primary display as the display on which the pointer should be shown.
669 createDevice();
670 // Associate the InputDevice with the secondary display.
671 ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
672 mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
673
674 // With PointerChoreographer enabled, there could be a PointerController for the associated
675 // display even if it is different from the pointer display. So the mapper should generate an
676 // event.
677 std::list<NotifyArgs> args;
678 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
679 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
680 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
681 ASSERT_THAT(args,
682 ElementsAre(VariantWith<NotifyMotionArgs>(
683 AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
684 WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(0.0f, 0.0f)))));
685 }
686
TEST_F(CursorInputMapperUnitTest,ProcessShouldHandleAllButtonsWithZeroCoords)687 TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleAllButtonsWithZeroCoords) {
688 mPropertyMap.addProperty("cursor.mode", "pointer");
689 createMapper();
690
691 std::list<NotifyArgs> args;
692
693 // press BTN_LEFT, release BTN_LEFT
694 args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 1);
695 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
696 EXPECT_THAT(args,
697 ElementsAre(VariantWith<NotifyMotionArgs>(
698 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
699 WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
700 WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
701 VariantWith<NotifyMotionArgs>(
702 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
703 WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
704 WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
705 args.clear();
706 args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 0);
707 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
708 EXPECT_THAT(args,
709 ElementsAre(VariantWith<NotifyMotionArgs>(
710 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
711 WithButtonState(0), WithCoords(0.0f, 0.0f),
712 WithPressure(0.0f))),
713 VariantWith<NotifyMotionArgs>(
714 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
715 WithButtonState(0), WithCoords(0.0f, 0.0f),
716 WithPressure(0.0f))),
717 VariantWith<NotifyMotionArgs>(
718 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
719 WithButtonState(0), WithCoords(0.0f, 0.0f),
720 WithPressure(0.0f)))));
721 args.clear();
722
723 // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE
724 args += process(ARBITRARY_TIME, EV_KEY, BTN_RIGHT, 1);
725 args += process(ARBITRARY_TIME, EV_KEY, BTN_MIDDLE, 1);
726 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
727 EXPECT_THAT(args,
728 ElementsAre(VariantWith<NotifyMotionArgs>(
729 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
730 WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY |
731 AMOTION_EVENT_BUTTON_TERTIARY),
732 WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
733 VariantWith<NotifyMotionArgs>(
734 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
735 WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
736 WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
737 VariantWith<NotifyMotionArgs>(
738 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
739 WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY |
740 AMOTION_EVENT_BUTTON_TERTIARY),
741 WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
742 args.clear();
743
744 args += process(ARBITRARY_TIME, EV_KEY, BTN_RIGHT, 0);
745 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
746 EXPECT_THAT(args,
747 ElementsAre(VariantWith<NotifyMotionArgs>(
748 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
749 WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
750 WithCoords(0.0f, 0.0f), WithPressure(1.0f))),
751 VariantWith<NotifyMotionArgs>(
752 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
753 WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
754 WithCoords(0.0f, 0.0f), WithPressure(1.0f)))));
755 args.clear();
756
757 args += process(ARBITRARY_TIME, EV_KEY, BTN_MIDDLE, 0);
758 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
759 EXPECT_THAT(args,
760 ElementsAre(VariantWith<NotifyMotionArgs>(
761 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
762 WithButtonState(0), WithCoords(0.0f, 0.0f),
763 WithPressure(0.0f))),
764 VariantWith<NotifyMotionArgs>(
765 AllOf(WithButtonState(0),
766 WithMotionAction(AMOTION_EVENT_ACTION_UP),
767 WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
768 VariantWith<NotifyMotionArgs>(
769 AllOf(WithButtonState(0),
770 WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
771 WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
772 }
773
774 class CursorInputMapperButtonKeyTest
775 : public CursorInputMapperUnitTest,
776 public testing::WithParamInterface<
777 std::tuple<int32_t /*evdevCode*/, int32_t /*expectedButtonState*/,
778 int32_t /*expectedKeyCode*/>> {};
779
TEST_P(CursorInputMapperButtonKeyTest,ProcessShouldHandleButtonKeyWithZeroCoords)780 TEST_P(CursorInputMapperButtonKeyTest, ProcessShouldHandleButtonKeyWithZeroCoords) {
781 auto [evdevCode, expectedButtonState, expectedKeyCode] = GetParam();
782 mPropertyMap.addProperty("cursor.mode", "pointer");
783 createMapper();
784
785 std::list<NotifyArgs> args;
786
787 args += process(ARBITRARY_TIME, EV_KEY, evdevCode, 1);
788 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
789 EXPECT_THAT(args,
790 ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
791 WithKeyCode(expectedKeyCode))),
792 VariantWith<NotifyMotionArgs>(
793 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
794 WithButtonState(expectedButtonState),
795 WithCoords(0.0f, 0.0f), WithPressure(0.0f))),
796 VariantWith<NotifyMotionArgs>(
797 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
798 WithButtonState(expectedButtonState),
799 WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
800 args.clear();
801
802 args += process(ARBITRARY_TIME, EV_KEY, evdevCode, 0);
803 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
804 EXPECT_THAT(args,
805 ElementsAre(VariantWith<NotifyMotionArgs>(
806 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
807 WithButtonState(0), WithCoords(0.0f, 0.0f),
808 WithPressure(0.0f))),
809 VariantWith<NotifyMotionArgs>(
810 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
811 WithButtonState(0), WithCoords(0.0f, 0.0f),
812 WithPressure(0.0f))),
813 VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
814 WithKeyCode(expectedKeyCode)))));
815 }
816
817 INSTANTIATE_TEST_SUITE_P(
818 SideExtraBackAndForward, CursorInputMapperButtonKeyTest,
819 testing::Values(std::make_tuple(BTN_SIDE, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK),
820 std::make_tuple(BTN_EXTRA, AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD),
821 std::make_tuple(BTN_BACK, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK),
822 std::make_tuple(BTN_FORWARD, AMOTION_EVENT_BUTTON_FORWARD,
823 AKEYCODE_FORWARD)));
824
TEST_F(CursorInputMapperUnitTest,ProcessWhenModeIsPointerShouldKeepZeroCoords)825 TEST_F(CursorInputMapperUnitTest, ProcessWhenModeIsPointerShouldKeepZeroCoords) {
826 mPropertyMap.addProperty("cursor.mode", "pointer");
827 createMapper();
828
829 std::list<NotifyArgs> args;
830
831 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
832 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
833 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
834 EXPECT_THAT(args,
835 ElementsAre(VariantWith<NotifyMotionArgs>(
836 AllOf(WithSource(AINPUT_SOURCE_MOUSE),
837 WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
838 WithCoords(0.0f, 0.0f), WithPressure(0.0f), WithSize(0.0f),
839 WithTouchDimensions(0.0f, 0.0f), WithToolDimensions(0.0f, 0.0f),
840 WithOrientation(0.0f), WithDistance(0.0f)))));
841 }
842
843 /**
844 * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any
845 * pointer acceleration or speed processing should not be applied.
846 */
TEST_F(CursorInputMapperUnitTest,PointerCaptureDisablesVelocityProcessing)847 TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) {
848 mPropertyMap.addProperty("cursor.mode", "pointer");
849 const VelocityControlParameters testParams(/*scale=*/5.f, /*lowThreshold=*/0.f,
850 /*highThreshold=*/100.f, /*acceleration=*/10.f);
851 mReaderConfiguration.pointerVelocityControlParameters = testParams;
852 mFakePolicy->setVelocityControlParams(testParams);
853 createMapper();
854
855 NotifyMotionArgs motionArgs;
856 std::list<NotifyArgs> args;
857
858 // Move and verify scale is applied.
859 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
860 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
861 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
862 EXPECT_THAT(args,
863 ElementsAre(VariantWith<NotifyMotionArgs>(
864 AllOf(WithSource(AINPUT_SOURCE_MOUSE),
865 WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))));
866 motionArgs = std::get<NotifyMotionArgs>(args.front());
867 const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
868 const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
869 ASSERT_GT(relX, 10);
870 ASSERT_GT(relY, 20);
871 args.clear();
872
873 // Enable Pointer Capture
874 setPointerCapture(true);
875
876 // Move and verify scale is not applied.
877 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
878 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
879 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
880 EXPECT_THAT(args,
881 ElementsAre(VariantWith<NotifyMotionArgs>(
882 AllOf(WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
883 WithMotionAction(AMOTION_EVENT_ACTION_MOVE)))));
884 motionArgs = std::get<NotifyMotionArgs>(args.front());
885 const float relX2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
886 const float relY2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
887 ASSERT_EQ(10, relX2);
888 ASSERT_EQ(20, relY2);
889 }
890
TEST_F(CursorInputMapperUnitTest,ConfigureDisplayIdNoAssociatedViewport)891 TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) {
892 // Set up the default display.
893 mFakePolicy->clearViewports();
894 mFakePolicy->addDisplayViewport(createPrimaryViewport(ui::Rotation::Rotation0));
895
896 // Set up the secondary display as the display on which the pointer should be shown.
897 // The InputDevice is not associated with any display.
898 mFakePolicy->addDisplayViewport(createSecondaryViewport());
899 mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
900
901 createMapper();
902
903 // Ensure input events are generated without display ID or coords, because they will be decided
904 // later by PointerChoreographer.
905 std::list<NotifyArgs> args;
906 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
907 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
908 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
909 EXPECT_THAT(args,
910 ElementsAre(VariantWith<NotifyMotionArgs>(
911 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
912 WithSource(AINPUT_SOURCE_MOUSE),
913 WithDisplayId(ui::LogicalDisplayId::INVALID),
914 WithCoords(0.0f, 0.0f)))));
915 }
916
917 // TODO(b/320433834): De-duplicate the test cases once the flag is removed.
918 class CursorInputMapperUnitTestWithNewBallistics : public CursorInputMapperUnitTestBase {
919 protected:
SetUp()920 void SetUp() override {
921 input_flags::enable_new_mouse_pointer_ballistics(true);
922 CursorInputMapperUnitTestBase::SetUp();
923 }
924 };
925
TEST_F(CursorInputMapperUnitTestWithNewBallistics,PointerCaptureDisablesVelocityProcessing)926 TEST_F(CursorInputMapperUnitTestWithNewBallistics, PointerCaptureDisablesVelocityProcessing) {
927 mPropertyMap.addProperty("cursor.mode", "pointer");
928 createMapper();
929
930 NotifyMotionArgs motionArgs;
931 std::list<NotifyArgs> args;
932
933 // Move and verify scale is applied.
934 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
935 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
936 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
937 motionArgs = std::get<NotifyMotionArgs>(args.front());
938 const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
939 const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
940 ASSERT_GT(relX, 10);
941 ASSERT_GT(relY, 20);
942 args.clear();
943
944 // Enable Pointer Capture
945 setPointerCapture(true);
946
947 // Move and verify scale is not applied.
948 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
949 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
950 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
951 motionArgs = std::get<NotifyMotionArgs>(args.front());
952 const float relX2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
953 const float relY2 = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
954 ASSERT_EQ(10, relX2);
955 ASSERT_EQ(20, relY2);
956 }
957
TEST_F(CursorInputMapperUnitTestWithNewBallistics,ConfigureAccelerationWithAssociatedViewport)958 TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAssociatedViewport) {
959 mPropertyMap.addProperty("cursor.mode", "pointer");
960 DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
961 mReaderConfiguration.setDisplayViewports({primaryViewport});
962 createDevice();
963 ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, primaryViewport);
964 mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
965
966 std::list<NotifyArgs> args;
967
968 // Verify that acceleration is being applied by default by checking that the movement is scaled.
969 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
970 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
971 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
972 ASSERT_THAT(args,
973 ElementsAre(VariantWith<NotifyMotionArgs>(
974 AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID)))));
975 const auto& coords = get<NotifyMotionArgs>(args.back()).pointerCoords[0];
976 ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), 10.f);
977 ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), 20.f);
978
979 // Disable acceleration for the display, and verify that acceleration is no longer applied.
980 mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID);
981 args += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
982 InputReaderConfiguration::Change::POINTER_SPEED);
983 args.clear();
984
985 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
986 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
987 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
988 ASSERT_THAT(args,
989 ElementsAre(VariantWith<NotifyMotionArgs>(AllOf(WithMotionAction(HOVER_MOVE),
990 WithDisplayId(DISPLAY_ID),
991 WithRelativeMotion(10, 20)))));
992 }
993
TEST_F(CursorInputMapperUnitTestWithNewBallistics,ConfigureAccelerationOnDisplayChange)994 TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationOnDisplayChange) {
995 mPropertyMap.addProperty("cursor.mode", "pointer");
996 DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
997 mReaderConfiguration.setDisplayViewports({primaryViewport});
998 // Disable acceleration for the display.
999 mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID);
1000 createDevice();
1001
1002 // Don't associate the device with the display yet.
1003 ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID,
1004 /*viewport=*/std::nullopt);
1005 mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
1006
1007 std::list<NotifyArgs> args;
1008
1009 // Verify that acceleration is being applied by default by checking that the movement is scaled.
1010 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
1011 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
1012 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
1013 ASSERT_THAT(args, ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE))));
1014 const auto& coords = get<NotifyMotionArgs>(args.back()).pointerCoords[0];
1015 ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), 10.f);
1016 ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), 20.f);
1017
1018 // Now associate the device with the display, and verify that acceleration is disabled.
1019 deviceContext.setViewport(primaryViewport);
1020 args += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
1021 InputReaderConfiguration::Change::DISPLAY_INFO);
1022 args.clear();
1023
1024 args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
1025 args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
1026 args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
1027 ASSERT_THAT(args,
1028 ElementsAre(VariantWith<NotifyMotionArgs>(
1029 AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID),
1030 WithRelativeMotion(10, 20)))));
1031 }
1032
1033 namespace {
1034
1035 // Minimum timestamp separation between subsequent input events from a Bluetooth device.
1036 constexpr nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4);
1037 // Maximum smoothing time delta so that we don't generate events too far into the future.
1038 constexpr nsecs_t MAX_BLUETOOTH_SMOOTHING_DELTA = ms2ns(32);
1039
1040 } // namespace
1041
1042 // --- BluetoothCursorInputMapperUnitTest ---
1043
1044 class BluetoothCursorInputMapperUnitTest : public CursorInputMapperUnitTestBase {
1045 protected:
SetUp()1046 void SetUp() override { SetUpWithBus(BUS_BLUETOOTH); }
1047 };
1048
TEST_F(BluetoothCursorInputMapperUnitTest,TimestampSmoothening)1049 TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmoothening) {
1050 mPropertyMap.addProperty("cursor.mode", "pointer");
1051 createMapper();
1052 std::list<NotifyArgs> argsList;
1053
1054 nsecs_t kernelEventTime = ARBITRARY_TIME;
1055 nsecs_t expectedEventTime = ARBITRARY_TIME;
1056 argsList += process(kernelEventTime, EV_REL, REL_X, 1);
1057 argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
1058 EXPECT_THAT(argsList,
1059 ElementsAre(VariantWith<NotifyMotionArgs>(
1060 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1061 WithEventTime(expectedEventTime)))));
1062 argsList.clear();
1063
1064 // Process several events that come in quick succession, according to their timestamps.
1065 for (int i = 0; i < 3; i++) {
1066 constexpr static nsecs_t delta = ms2ns(1);
1067 static_assert(delta < MIN_BLUETOOTH_TIMESTAMP_DELTA);
1068 kernelEventTime += delta;
1069 expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
1070
1071 argsList += process(kernelEventTime, EV_REL, REL_X, 1);
1072 argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
1073 EXPECT_THAT(argsList,
1074 ElementsAre(VariantWith<NotifyMotionArgs>(
1075 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1076 WithEventTime(expectedEventTime)))));
1077 argsList.clear();
1078 }
1079 }
1080
TEST_F(BluetoothCursorInputMapperUnitTest,TimestampSmootheningIsCapped)1081 TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningIsCapped) {
1082 mPropertyMap.addProperty("cursor.mode", "pointer");
1083 createMapper();
1084 std::list<NotifyArgs> argsList;
1085
1086 nsecs_t expectedEventTime = ARBITRARY_TIME;
1087 argsList += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
1088 argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
1089 EXPECT_THAT(argsList,
1090 ElementsAre(VariantWith<NotifyMotionArgs>(
1091 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1092 WithEventTime(expectedEventTime)))));
1093 argsList.clear();
1094
1095 // Process several events with the same timestamp from the kernel.
1096 // Ensure that we do not generate events too far into the future.
1097 constexpr static int32_t numEvents =
1098 MAX_BLUETOOTH_SMOOTHING_DELTA / MIN_BLUETOOTH_TIMESTAMP_DELTA;
1099 for (int i = 0; i < numEvents; i++) {
1100 expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
1101
1102 argsList += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
1103 argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
1104 EXPECT_THAT(argsList,
1105 ElementsAre(VariantWith<NotifyMotionArgs>(
1106 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1107 WithEventTime(expectedEventTime)))));
1108 argsList.clear();
1109 }
1110
1111 // By processing more events with the same timestamp, we should not generate events with a
1112 // timestamp that is more than the specified max time delta from the timestamp at its injection.
1113 const nsecs_t cappedEventTime = ARBITRARY_TIME + MAX_BLUETOOTH_SMOOTHING_DELTA;
1114 for (int i = 0; i < 3; i++) {
1115 argsList += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
1116 argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
1117 EXPECT_THAT(argsList,
1118 ElementsAre(VariantWith<NotifyMotionArgs>(
1119 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1120 WithEventTime(cappedEventTime)))));
1121 argsList.clear();
1122 }
1123 }
1124
TEST_F(BluetoothCursorInputMapperUnitTest,TimestampSmootheningNotUsed)1125 TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmootheningNotUsed) {
1126 mPropertyMap.addProperty("cursor.mode", "pointer");
1127 createMapper();
1128 std::list<NotifyArgs> argsList;
1129
1130 nsecs_t kernelEventTime = ARBITRARY_TIME;
1131 nsecs_t expectedEventTime = ARBITRARY_TIME;
1132 argsList += process(kernelEventTime, EV_REL, REL_X, 1);
1133 argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
1134 EXPECT_THAT(argsList,
1135 ElementsAre(VariantWith<NotifyMotionArgs>(
1136 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1137 WithEventTime(expectedEventTime)))));
1138 argsList.clear();
1139
1140 // If the next event has a timestamp that is sufficiently spaced out so that Bluetooth timestamp
1141 // smoothening is not needed, its timestamp is not affected.
1142 kernelEventTime += MAX_BLUETOOTH_SMOOTHING_DELTA + ms2ns(1);
1143 expectedEventTime = kernelEventTime;
1144
1145 argsList += process(kernelEventTime, EV_REL, REL_X, 1);
1146 argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
1147 EXPECT_THAT(argsList,
1148 ElementsAre(VariantWith<NotifyMotionArgs>(
1149 AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
1150 WithEventTime(expectedEventTime)))));
1151 argsList.clear();
1152 }
1153
1154 } // namespace android
1155