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