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