• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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