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