xref: /aosp_15_r20/frameworks/native/services/inputflinger/tests/PointerChoreographer_test.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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 "../PointerChoreographer.h"
18 #include <com_android_input_flags.h>
19 #include <flag_macros.h>
20 #include <gtest/gtest.h>
21 #include <deque>
22 #include <vector>
23 
24 #include "FakePointerController.h"
25 #include "InterfaceMocks.h"
26 #include "NotifyArgsBuilders.h"
27 #include "TestEventMatchers.h"
28 #include "TestInputListener.h"
29 
30 namespace android {
31 
32 namespace input_flags = com::android::input::flags;
33 
34 using ControllerType = PointerControllerInterface::ControllerType;
35 using testing::AllOf;
36 
37 namespace {
38 
39 // Helpers to std::visit with lambdas.
40 template <typename... V>
41 struct Visitor : V... {
42     using V::operator()...;
43 };
44 template <typename... V>
45 Visitor(V...) -> Visitor<V...>;
46 
47 constexpr int32_t DEVICE_ID = 3;
48 constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
49 constexpr int32_t THIRD_DEVICE_ID = SECOND_DEVICE_ID + 1;
50 constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId{5};
51 constexpr ui::LogicalDisplayId ANOTHER_DISPLAY_ID = ui::LogicalDisplayId{10};
52 constexpr int32_t DISPLAY_WIDTH = 480;
53 constexpr int32_t DISPLAY_HEIGHT = 800;
54 constexpr auto DRAWING_TABLET_SOURCE = AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS;
55 
56 const auto MOUSE_POINTER = PointerBuilder(/*id=*/0, ToolType::MOUSE)
57                                    .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 10)
58                                    .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 20);
59 const auto FIRST_TOUCH_POINTER = PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200);
60 const auto SECOND_TOUCH_POINTER = PointerBuilder(/*id=*/1, ToolType::FINGER).x(200).y(300);
61 const auto STYLUS_POINTER = PointerBuilder(/*id=*/0, ToolType::STYLUS).x(100).y(200);
62 const auto TOUCHPAD_POINTER = PointerBuilder(/*id=*/0, ToolType::FINGER)
63                                       .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 10)
64                                       .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 20);
65 
generateTestDeviceInfo(int32_t deviceId,uint32_t source,ui::LogicalDisplayId associatedDisplayId)66 static InputDeviceInfo generateTestDeviceInfo(int32_t deviceId, uint32_t source,
67                                               ui::LogicalDisplayId associatedDisplayId) {
68     InputDeviceIdentifier identifier;
69 
70     auto info = InputDeviceInfo();
71     info.initialize(deviceId, /*generation=*/1, /*controllerNumber=*/1, identifier, "alias",
72                     /*isExternal=*/false, /*hasMic=*/false, associatedDisplayId);
73     info.addSource(source);
74     return info;
75 }
76 
createViewports(std::vector<ui::LogicalDisplayId> displayIds)77 static std::vector<DisplayViewport> createViewports(std::vector<ui::LogicalDisplayId> displayIds) {
78     std::vector<DisplayViewport> viewports;
79     for (auto displayId : displayIds) {
80         DisplayViewport viewport;
81         viewport.displayId = displayId;
82         viewport.logicalRight = DISPLAY_WIDTH;
83         viewport.logicalBottom = DISPLAY_HEIGHT;
84         viewports.push_back(viewport);
85     }
86     return viewports;
87 }
88 
89 } // namespace
90 
91 // --- PointerChoreographerTest ---
92 
93 class TestPointerChoreographer : public PointerChoreographer {
94 public:
95     TestPointerChoreographer(InputListenerInterface& inputListener,
96                              PointerChoreographerPolicyInterface& policy,
97                              sp<gui::WindowInfosListener>& windowInfoListener,
98                              const std::vector<gui::WindowInfo>& mInitialWindowInfos);
99 };
100 
TestPointerChoreographer(InputListenerInterface & inputListener,PointerChoreographerPolicyInterface & policy,sp<gui::WindowInfosListener> & windowInfoListener,const std::vector<gui::WindowInfo> & mInitialWindowInfos)101 TestPointerChoreographer::TestPointerChoreographer(
102         InputListenerInterface& inputListener, PointerChoreographerPolicyInterface& policy,
103         sp<gui::WindowInfosListener>& windowInfoListener,
104         const std::vector<gui::WindowInfo>& mInitialWindowInfos)
105       : PointerChoreographer(
106                 inputListener, policy,
107                 [&windowInfoListener,
108                  &mInitialWindowInfos](const sp<android::gui::WindowInfosListener>& listener) {
109                     windowInfoListener = listener;
110                     return mInitialWindowInfos;
111                 },
__anon062b71b00302(const sp<android::gui::WindowInfosListener>& listener) 112                 [&windowInfoListener](const sp<android::gui::WindowInfosListener>& listener) {
113                     windowInfoListener = nullptr;
114                 }) {}
115 
116 class PointerChoreographerTest : public testing::Test {
117 protected:
118     TestInputListener mTestListener;
119     sp<gui::WindowInfosListener> mRegisteredWindowInfoListener;
120     std::vector<gui::WindowInfo> mInjectedInitialWindowInfos;
121     testing::NiceMock<MockPointerChoreographerPolicyInterface> mMockPolicy;
122     TestPointerChoreographer mChoreographer{mTestListener, mMockPolicy,
123                                             mRegisteredWindowInfoListener,
124                                             mInjectedInitialWindowInfos};
125 
SetUp()126     void SetUp() override {
127         // flag overrides
128         input_flags::hide_pointer_indicators_for_secure_windows(true);
129 
130         ON_CALL(mMockPolicy, createPointerController).WillByDefault([this](ControllerType type) {
131             std::shared_ptr<FakePointerController> pc = std::make_shared<FakePointerController>();
132             EXPECT_FALSE(pc->isPointerShown());
133             mCreatedControllers.emplace_back(type, pc);
134             return pc;
135         });
136 
137         ON_CALL(mMockPolicy, notifyPointerDisplayIdChanged)
138                 .WillByDefault([this](ui::LogicalDisplayId displayId, const vec2& position) {
139                     mPointerDisplayIdNotified = displayId;
140                 });
141     }
142 
assertPointerControllerCreated(ControllerType expectedType)143     std::shared_ptr<FakePointerController> assertPointerControllerCreated(
144             ControllerType expectedType) {
145         EXPECT_FALSE(mCreatedControllers.empty()) << "No PointerController was created";
146         auto [type, controller] = std::move(mCreatedControllers.front());
147         EXPECT_EQ(expectedType, type);
148         mCreatedControllers.pop_front();
149         return controller;
150     }
151 
assertPointerControllerNotCreated()152     void assertPointerControllerNotCreated() { ASSERT_TRUE(mCreatedControllers.empty()); }
153 
assertPointerControllerRemoved(const std::shared_ptr<FakePointerController> & pc)154     void assertPointerControllerRemoved(const std::shared_ptr<FakePointerController>& pc) {
155         // Ensure that the code under test is not holding onto this PointerController.
156         // While the policy initially creates the PointerControllers, the PointerChoreographer is
157         // expected to manage their lifecycles. Although we may not want to strictly enforce how
158         // the object is managed, in this case, we need to have a way of ensuring that the
159         // corresponding graphical resources have been released by the PointerController, and the
160         // simplest way of checking for that is to just make sure that the PointerControllers
161         // themselves are released by Choreographer when no longer in use. This check is ensuring
162         // that the reference retained by the test is the last one.
163         ASSERT_EQ(1, pc.use_count()) << "Expected PointerChoreographer to release all references "
164                                         "to this PointerController";
165     }
166 
assertPointerControllerNotRemoved(const std::shared_ptr<FakePointerController> & pc)167     void assertPointerControllerNotRemoved(const std::shared_ptr<FakePointerController>& pc) {
168         // See assertPointerControllerRemoved above.
169         ASSERT_GT(pc.use_count(), 1) << "Expected PointerChoreographer to hold at least one "
170                                         "reference to this PointerController";
171     }
172 
assertPointerDisplayIdNotified(ui::LogicalDisplayId displayId)173     void assertPointerDisplayIdNotified(ui::LogicalDisplayId displayId) {
174         ASSERT_EQ(displayId, mPointerDisplayIdNotified);
175         mPointerDisplayIdNotified.reset();
176     }
177 
assertPointerDisplayIdNotNotified()178     void assertPointerDisplayIdNotNotified() { ASSERT_EQ(std::nullopt, mPointerDisplayIdNotified); }
179 
assertWindowInfosListenerRegistered()180     void assertWindowInfosListenerRegistered() {
181         ASSERT_NE(nullptr, mRegisteredWindowInfoListener)
182                 << "WindowInfosListener was not registered";
183     }
184 
assertWindowInfosListenerNotRegistered()185     void assertWindowInfosListenerNotRegistered() {
186         ASSERT_EQ(nullptr, mRegisteredWindowInfoListener)
187                 << "WindowInfosListener was not unregistered";
188     }
189 
190 private:
191     std::deque<std::pair<ControllerType, std::shared_ptr<FakePointerController>>>
192             mCreatedControllers;
193     std::optional<ui::LogicalDisplayId> mPointerDisplayIdNotified;
194 };
195 
TEST_F(PointerChoreographerTest,ForwardsArgsToInnerListener)196 TEST_F(PointerChoreographerTest, ForwardsArgsToInnerListener) {
197     const std::vector<NotifyArgs>
198             allArgs{NotifyInputDevicesChangedArgs{},
199                     KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build(),
200                     MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
201                             .pointer(FIRST_TOUCH_POINTER)
202                             .build(),
203                     NotifySensorArgs{},
204                     NotifySwitchArgs{},
205                     NotifyDeviceResetArgs{},
206                     NotifyPointerCaptureChangedArgs{},
207                     NotifyVibratorStateArgs{}};
208 
209     for (auto notifyArgs : allArgs) {
210         mChoreographer.notify(notifyArgs);
211         EXPECT_NO_FATAL_FAILURE(
212                 std::visit(Visitor{
213                                    [&](const NotifyInputDevicesChangedArgs& args) {
214                                        mTestListener.assertNotifyInputDevicesChangedWasCalled();
215                                    },
216                                    [&](const NotifyKeyArgs& args) {
217                                        mTestListener.assertNotifyKeyWasCalled();
218                                    },
219                                    [&](const NotifyMotionArgs& args) {
220                                        mTestListener.assertNotifyMotionWasCalled();
221                                    },
222                                    [&](const NotifySensorArgs& args) {
223                                        mTestListener.assertNotifySensorWasCalled();
224                                    },
225                                    [&](const NotifySwitchArgs& args) {
226                                        mTestListener.assertNotifySwitchWasCalled();
227                                    },
228                                    [&](const NotifyDeviceResetArgs& args) {
229                                        mTestListener.assertNotifyDeviceResetWasCalled();
230                                    },
231                                    [&](const NotifyPointerCaptureChangedArgs& args) {
232                                        mTestListener.assertNotifyCaptureWasCalled();
233                                    },
234                                    [&](const NotifyVibratorStateArgs& args) {
235                                        mTestListener.assertNotifyVibratorStateWasCalled();
236                                    },
237                            },
238                            notifyArgs));
239     }
240 }
241 
TEST_F(PointerChoreographerTest,WhenMouseIsAddedCreatesPointerController)242 TEST_F(PointerChoreographerTest, WhenMouseIsAddedCreatesPointerController) {
243     mChoreographer.notifyInputDevicesChanged(
244             {/*id=*/0,
245              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
246                                      ui::LogicalDisplayId::INVALID)}});
247     assertPointerControllerCreated(ControllerType::MOUSE);
248 }
249 
TEST_F(PointerChoreographerTest,WhenMouseIsRemovedRemovesPointerController)250 TEST_F(PointerChoreographerTest, WhenMouseIsRemovedRemovesPointerController) {
251     mChoreographer.notifyInputDevicesChanged(
252             {/*id=*/0,
253              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
254                                      ui::LogicalDisplayId::INVALID)}});
255     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
256 
257     // Remove the mouse.
258     mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}});
259     assertPointerControllerRemoved(pc);
260 }
261 
TEST_F(PointerChoreographerTest,WhenKeyboardIsAddedDoesNotCreatePointerController)262 TEST_F(PointerChoreographerTest, WhenKeyboardIsAddedDoesNotCreatePointerController) {
263     mChoreographer.notifyInputDevicesChanged(
264             {/*id=*/0,
265              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
266                                      ui::LogicalDisplayId::INVALID)}});
267     assertPointerControllerNotCreated();
268 }
269 
TEST_F(PointerChoreographerTest,SetsViewportForAssociatedMouse)270 TEST_F(PointerChoreographerTest, SetsViewportForAssociatedMouse) {
271     // Just adding a viewport or device should create a PointerController.
272     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
273     mChoreographer.notifyInputDevicesChanged(
274             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, DISPLAY_ID)}});
275 
276     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
277     pc->assertViewportSet(DISPLAY_ID);
278     ASSERT_TRUE(pc->isPointerShown());
279 }
280 
TEST_F(PointerChoreographerTest,WhenViewportSetLaterSetsViewportForAssociatedMouse)281 TEST_F(PointerChoreographerTest, WhenViewportSetLaterSetsViewportForAssociatedMouse) {
282     // Without viewport information, PointerController will be created but viewport won't be set.
283     mChoreographer.notifyInputDevicesChanged(
284             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, DISPLAY_ID)}});
285     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
286     pc->assertViewportNotSet();
287 
288     // After Choreographer gets viewport, PointerController should also have viewport.
289     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
290     pc->assertViewportSet(DISPLAY_ID);
291 }
292 
TEST_F(PointerChoreographerTest,SetsDefaultMouseViewportForPointerController)293 TEST_F(PointerChoreographerTest, SetsDefaultMouseViewportForPointerController) {
294     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
295     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
296 
297     // For a mouse event without a target display, default viewport should be set for
298     // the PointerController.
299     mChoreographer.notifyInputDevicesChanged(
300             {/*id=*/0,
301              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
302                                      ui::LogicalDisplayId::INVALID)}});
303     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
304     pc->assertViewportSet(DISPLAY_ID);
305     ASSERT_TRUE(pc->isPointerShown());
306 }
307 
TEST_F(PointerChoreographerTest,WhenDefaultMouseDisplayChangesSetsDefaultMouseViewportForPointerController)308 TEST_F(PointerChoreographerTest,
309        WhenDefaultMouseDisplayChangesSetsDefaultMouseViewportForPointerController) {
310     // Set one display as a default mouse display and emit mouse event to create PointerController.
311     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
312     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
313     mChoreographer.notifyInputDevicesChanged(
314             {/*id=*/0,
315              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
316                                      ui::LogicalDisplayId::INVALID)}});
317     auto firstDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
318     firstDisplayPc->assertViewportSet(DISPLAY_ID);
319     ASSERT_TRUE(firstDisplayPc->isPointerShown());
320 
321     // Change default mouse display. Existing PointerController should be removed and a new one
322     // should be created.
323     mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
324     assertPointerControllerRemoved(firstDisplayPc);
325 
326     auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
327     secondDisplayPc->assertViewportSet(ANOTHER_DISPLAY_ID);
328     ASSERT_TRUE(secondDisplayPc->isPointerShown());
329 }
330 
TEST_F(PointerChoreographerTest,CallsNotifyPointerDisplayIdChanged)331 TEST_F(PointerChoreographerTest, CallsNotifyPointerDisplayIdChanged) {
332     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
333     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
334     mChoreographer.notifyInputDevicesChanged(
335             {/*id=*/0,
336              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
337                                      ui::LogicalDisplayId::INVALID)}});
338     assertPointerControllerCreated(ControllerType::MOUSE);
339 
340     assertPointerDisplayIdNotified(DISPLAY_ID);
341 }
342 
TEST_F(PointerChoreographerTest,WhenViewportIsSetLaterCallsNotifyPointerDisplayIdChanged)343 TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterCallsNotifyPointerDisplayIdChanged) {
344     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
345     mChoreographer.notifyInputDevicesChanged(
346             {/*id=*/0,
347              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
348                                      ui::LogicalDisplayId::INVALID)}});
349     assertPointerControllerCreated(ControllerType::MOUSE);
350     assertPointerDisplayIdNotNotified();
351 
352     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
353     assertPointerDisplayIdNotified(DISPLAY_ID);
354 }
355 
TEST_F(PointerChoreographerTest,WhenMouseIsRemovedCallsNotifyPointerDisplayIdChanged)356 TEST_F(PointerChoreographerTest, WhenMouseIsRemovedCallsNotifyPointerDisplayIdChanged) {
357     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
358     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
359     mChoreographer.notifyInputDevicesChanged(
360             {/*id=*/0,
361              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
362                                      ui::LogicalDisplayId::INVALID)}});
363     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
364     assertPointerDisplayIdNotified(DISPLAY_ID);
365 
366     mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}});
367     assertPointerDisplayIdNotified(ui::LogicalDisplayId::INVALID);
368     assertPointerControllerRemoved(pc);
369 }
370 
TEST_F(PointerChoreographerTest,WhenDefaultMouseDisplayChangesCallsNotifyPointerDisplayIdChanged)371 TEST_F(PointerChoreographerTest, WhenDefaultMouseDisplayChangesCallsNotifyPointerDisplayIdChanged) {
372     // Add two viewports.
373     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
374 
375     // Set one viewport as a default mouse display ID.
376     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
377     mChoreographer.notifyInputDevicesChanged(
378             {/*id=*/0,
379              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
380                                      ui::LogicalDisplayId::INVALID)}});
381     auto firstDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
382     assertPointerDisplayIdNotified(DISPLAY_ID);
383 
384     // Set another viewport as a default mouse display ID. The mouse is moved to the other display.
385     mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
386     assertPointerControllerRemoved(firstDisplayPc);
387 
388     assertPointerControllerCreated(ControllerType::MOUSE);
389     assertPointerDisplayIdNotified(ANOTHER_DISPLAY_ID);
390 }
391 
TEST_F(PointerChoreographerTest,MouseMovesPointerAndReturnsNewArgs)392 TEST_F(PointerChoreographerTest, MouseMovesPointerAndReturnsNewArgs) {
393     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
394     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
395     mChoreographer.notifyInputDevicesChanged(
396             {/*id=*/0,
397              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
398                                      ui::LogicalDisplayId::INVALID)}});
399     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
400     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
401 
402     // Set initial position of the PointerController.
403     pc->setPosition(100, 200);
404 
405     // Make NotifyMotionArgs and notify Choreographer.
406     mChoreographer.notifyMotion(
407             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
408                     .pointer(MOUSE_POINTER)
409                     .deviceId(DEVICE_ID)
410                     .displayId(ui::LogicalDisplayId::INVALID)
411                     .build());
412 
413     // Check that the PointerController updated the position and the pointer is shown.
414     pc->assertPosition(110, 220);
415     ASSERT_TRUE(pc->isPointerShown());
416 
417     // Check that x-y coordinates, displayId and cursor position are correctly updated.
418     mTestListener.assertNotifyMotionWasCalled(
419             AllOf(WithCoords(110, 220), WithDisplayId(DISPLAY_ID), WithCursorPosition(110, 220)));
420 }
421 
TEST_F(PointerChoreographerTest,AbsoluteMouseMovesPointerAndReturnsNewArgs)422 TEST_F(PointerChoreographerTest, AbsoluteMouseMovesPointerAndReturnsNewArgs) {
423     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
424     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
425     mChoreographer.notifyInputDevicesChanged(
426             {/*id=*/0,
427              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
428                                      ui::LogicalDisplayId::INVALID)}});
429     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
430     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
431 
432     // Set initial position of the PointerController.
433     pc->setPosition(100, 200);
434     const auto absoluteMousePointer = PointerBuilder(/*id=*/0, ToolType::MOUSE)
435                                               .axis(AMOTION_EVENT_AXIS_X, 110)
436                                               .axis(AMOTION_EVENT_AXIS_Y, 220);
437 
438     // Make NotifyMotionArgs and notify Choreographer.
439     mChoreographer.notifyMotion(
440             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
441                     .pointer(absoluteMousePointer)
442                     .deviceId(DEVICE_ID)
443                     .displayId(ui::LogicalDisplayId::INVALID)
444                     .build());
445 
446     // Check that the PointerController updated the position and the pointer is shown.
447     pc->assertPosition(110, 220);
448     ASSERT_TRUE(pc->isPointerShown());
449 
450     // Check that x-y coordinates, displayId and cursor position are correctly updated.
451     mTestListener.assertNotifyMotionWasCalled(
452             AllOf(WithCoords(110, 220), WithRelativeMotion(10, 20), WithDisplayId(DISPLAY_ID),
453                   WithCursorPosition(110, 220)));
454 }
455 
TEST_F(PointerChoreographerTest,AssociatedMouseMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay)456 TEST_F(PointerChoreographerTest,
457        AssociatedMouseMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) {
458     // Add two displays and set one to default.
459     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
460     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
461 
462     // Add two devices, one unassociated and the other associated with non-default mouse display.
463     mChoreographer.notifyInputDevicesChanged(
464             {/*id=*/0,
465              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
466               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
467     auto unassociatedMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
468     ASSERT_EQ(DISPLAY_ID, unassociatedMousePc->getDisplayId());
469     auto associatedMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
470     ASSERT_EQ(ANOTHER_DISPLAY_ID, associatedMousePc->getDisplayId());
471 
472     // Set initial position for PointerControllers.
473     unassociatedMousePc->setPosition(100, 200);
474     associatedMousePc->setPosition(300, 400);
475 
476     // Make NotifyMotionArgs from the associated mouse and notify Choreographer.
477     mChoreographer.notifyMotion(
478             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
479                     .pointer(MOUSE_POINTER)
480                     .deviceId(SECOND_DEVICE_ID)
481                     .displayId(ANOTHER_DISPLAY_ID)
482                     .build());
483 
484     // Check the status of the PointerControllers.
485     unassociatedMousePc->assertPosition(100, 200);
486     ASSERT_EQ(DISPLAY_ID, unassociatedMousePc->getDisplayId());
487     associatedMousePc->assertPosition(310, 420);
488     ASSERT_EQ(ANOTHER_DISPLAY_ID, associatedMousePc->getDisplayId());
489     ASSERT_TRUE(associatedMousePc->isPointerShown());
490 
491     // Check that x-y coordinates, displayId and cursor position are correctly updated.
492     mTestListener.assertNotifyMotionWasCalled(
493             AllOf(WithCoords(310, 420), WithDeviceId(SECOND_DEVICE_ID),
494                   WithDisplayId(ANOTHER_DISPLAY_ID), WithCursorPosition(310, 420)));
495 }
496 
TEST_F(PointerChoreographerTest,DoesNotMovePointerForMouseRelativeSource)497 TEST_F(PointerChoreographerTest, DoesNotMovePointerForMouseRelativeSource) {
498     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
499     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
500     mChoreographer.notifyInputDevicesChanged(
501             {/*id=*/0,
502              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
503                                      ui::LogicalDisplayId::INVALID)}});
504     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
505     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
506 
507     // Set initial position of the PointerController.
508     pc->setPosition(100, 200);
509 
510     // Assume that pointer capture is enabled.
511     mChoreographer.notifyInputDevicesChanged(
512             {/*id=*/1,
513              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE_RELATIVE,
514                                      ui::LogicalDisplayId::INVALID)}});
515     mChoreographer.notifyPointerCaptureChanged(
516             NotifyPointerCaptureChangedArgs(/*id=*/2, systemTime(SYSTEM_TIME_MONOTONIC),
517                                             PointerCaptureRequest(/*window=*/sp<BBinder>::make(),
518                                                                   /*seq=*/0)));
519 
520     // Notify motion as if pointer capture is enabled.
521     mChoreographer.notifyMotion(
522             MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE)
523                     .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE)
524                                      .x(10)
525                                      .y(20)
526                                      .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 10)
527                                      .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 20))
528                     .deviceId(DEVICE_ID)
529                     .displayId(ui::LogicalDisplayId::INVALID)
530                     .build());
531 
532     // Check that there's no update on the PointerController.
533     pc->assertPosition(100, 200);
534     ASSERT_FALSE(pc->isPointerShown());
535 
536     // Check x-y coordinates, displayId and cursor position are not changed.
537     mTestListener.assertNotifyMotionWasCalled(
538             AllOf(WithCoords(10, 20), WithRelativeMotion(10, 20),
539                   WithDisplayId(ui::LogicalDisplayId::INVALID),
540                   WithCursorPosition(AMOTION_EVENT_INVALID_CURSOR_POSITION,
541                                      AMOTION_EVENT_INVALID_CURSOR_POSITION)));
542 }
543 
TEST_F(PointerChoreographerTest,WhenPointerCaptureEnabledHidesPointer)544 TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledHidesPointer) {
545     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
546     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
547     mChoreographer.notifyInputDevicesChanged(
548             {/*id=*/0,
549              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
550                                      ui::LogicalDisplayId::INVALID)}});
551     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
552     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
553     ASSERT_TRUE(pc->isPointerShown());
554 
555     // Enable pointer capture and check if the PointerController hid the pointer.
556     mChoreographer.notifyPointerCaptureChanged(
557             NotifyPointerCaptureChangedArgs(/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC),
558                                             PointerCaptureRequest(/*window=*/sp<BBinder>::make(),
559                                                                   /*seq=*/0)));
560     ASSERT_FALSE(pc->isPointerShown());
561 }
562 
TEST_F(PointerChoreographerTest,MultipleMiceConnectionAndRemoval)563 TEST_F(PointerChoreographerTest, MultipleMiceConnectionAndRemoval) {
564     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
565     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
566 
567     // A mouse is connected, and the pointer is shown.
568     mChoreographer.notifyInputDevicesChanged(
569             {/*id=*/0,
570              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
571                                      ui::LogicalDisplayId::INVALID)}});
572 
573     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
574     ASSERT_TRUE(pc->isPointerShown());
575 
576     pc->fade(PointerControllerInterface::Transition::IMMEDIATE);
577 
578     // Add a second mouse is added, the pointer is shown again.
579     mChoreographer.notifyInputDevicesChanged(
580             {/*id=*/0,
581              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
582               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE,
583                                      ui::LogicalDisplayId::INVALID)}});
584     ASSERT_TRUE(pc->isPointerShown());
585 
586     // One of the mice is removed, and it does not cause the mouse pointer to fade, because
587     // we have one more mouse connected.
588     mChoreographer.notifyInputDevicesChanged(
589             {/*id=*/0,
590              {generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE,
591                                      ui::LogicalDisplayId::INVALID)}});
592     assertPointerControllerNotRemoved(pc);
593     ASSERT_TRUE(pc->isPointerShown());
594 
595     // The final mouse is removed. The pointer is removed.
596     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
597     assertPointerControllerRemoved(pc);
598 }
599 
TEST_F(PointerChoreographerTest,UnrelatedChangeDoesNotUnfadePointer)600 TEST_F(PointerChoreographerTest, UnrelatedChangeDoesNotUnfadePointer) {
601     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
602     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
603     mChoreographer.notifyInputDevicesChanged(
604             {/*id=*/0,
605              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
606                                      ui::LogicalDisplayId::INVALID)}});
607 
608     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
609     ASSERT_TRUE(pc->isPointerShown());
610 
611     pc->fade(PointerControllerInterface::Transition::IMMEDIATE);
612 
613     // Adding a touchscreen device does not unfade the mouse pointer.
614     mChoreographer.notifyInputDevicesChanged(
615             {/*id=*/0,
616              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
617               generateTestDeviceInfo(SECOND_DEVICE_ID,
618                                      AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
619                                      DISPLAY_ID)}});
620 
621     ASSERT_FALSE(pc->isPointerShown());
622 
623     // Show touches setting change does not unfade the mouse pointer.
624     mChoreographer.setShowTouchesEnabled(true);
625 
626     ASSERT_FALSE(pc->isPointerShown());
627 }
628 
TEST_F(PointerChoreographerTest,DisabledMouseConnected)629 TEST_F(PointerChoreographerTest, DisabledMouseConnected) {
630     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
631     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
632     InputDeviceInfo mouseDeviceInfo =
633             generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
634     // Disable this mouse device.
635     mouseDeviceInfo.setEnabled(false);
636     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {mouseDeviceInfo}});
637 
638     // Disabled mouse device should not create PointerController
639     assertPointerControllerNotCreated();
640 }
641 
TEST_F(PointerChoreographerTest,MouseDeviceDisableLater)642 TEST_F(PointerChoreographerTest, MouseDeviceDisableLater) {
643     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
644     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
645     InputDeviceInfo mouseDeviceInfo =
646             generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
647 
648     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {mouseDeviceInfo}});
649 
650     auto pc = assertPointerControllerCreated(PointerControllerInterface::ControllerType::MOUSE);
651     ASSERT_TRUE(pc->isPointerShown());
652 
653     // Now we disable this mouse device
654     mouseDeviceInfo.setEnabled(false);
655     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {mouseDeviceInfo}});
656 
657     // Because the mouse device disabled, the PointerController should be removed.
658     assertPointerControllerRemoved(pc);
659 }
660 
TEST_F(PointerChoreographerTest,MultipleEnabledAndDisabledMiceConnectionAndRemoval)661 TEST_F(PointerChoreographerTest, MultipleEnabledAndDisabledMiceConnectionAndRemoval) {
662     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
663     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
664     InputDeviceInfo disabledMouseDeviceInfo =
665             generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
666     disabledMouseDeviceInfo.setEnabled(false);
667 
668     InputDeviceInfo enabledMouseDeviceInfo =
669             generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE,
670                                    ui::LogicalDisplayId::INVALID);
671 
672     InputDeviceInfo anotherEnabledMouseDeviceInfo =
673             generateTestDeviceInfo(THIRD_DEVICE_ID, AINPUT_SOURCE_MOUSE,
674                                    ui::LogicalDisplayId::INVALID);
675 
676     mChoreographer.notifyInputDevicesChanged(
677             {/*id=*/0,
678              {disabledMouseDeviceInfo, enabledMouseDeviceInfo, anotherEnabledMouseDeviceInfo}});
679 
680     // Mouse should show, because we have two enabled mice device.
681     auto pc = assertPointerControllerCreated(PointerControllerInterface::ControllerType::MOUSE);
682     ASSERT_TRUE(pc->isPointerShown());
683 
684     // Now we remove one of enabled mice device.
685     mChoreographer.notifyInputDevicesChanged(
686             {/*id=*/0, {disabledMouseDeviceInfo, enabledMouseDeviceInfo}});
687 
688     // Because we still have an enabled mouse device, pointer should still show.
689     ASSERT_TRUE(pc->isPointerShown());
690 
691     // We finally remove last enabled mouse device.
692     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {disabledMouseDeviceInfo}});
693 
694     // The PointerController should be removed, because there is no enabled mouse device.
695     assertPointerControllerRemoved(pc);
696 }
697 
TEST_F(PointerChoreographerTest,WhenShowTouchesEnabledAndDisabledDoesNotCreatePointerController)698 TEST_F(PointerChoreographerTest, WhenShowTouchesEnabledAndDisabledDoesNotCreatePointerController) {
699     // Disable show touches and add a touch device.
700     mChoreographer.setShowTouchesEnabled(false);
701     mChoreographer.notifyInputDevicesChanged(
702             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
703     assertPointerControllerNotCreated();
704 
705     // Enable show touches. PointerController still should not be created.
706     mChoreographer.setShowTouchesEnabled(true);
707     assertPointerControllerNotCreated();
708 }
709 
TEST_F(PointerChoreographerTest,WhenTouchEventOccursCreatesPointerController)710 TEST_F(PointerChoreographerTest, WhenTouchEventOccursCreatesPointerController) {
711     // Add a touch device and enable show touches.
712     mChoreographer.notifyInputDevicesChanged(
713             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
714     mChoreographer.setShowTouchesEnabled(true);
715 
716     // Emit touch event. Now PointerController should be created.
717     mChoreographer.notifyMotion(
718             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
719                     .pointer(FIRST_TOUCH_POINTER)
720                     .deviceId(DEVICE_ID)
721                     .displayId(DISPLAY_ID)
722                     .build());
723     assertPointerControllerCreated(ControllerType::TOUCH);
724 }
725 
TEST_F(PointerChoreographerTest,WhenShowTouchesDisabledAndTouchEventOccursDoesNotCreatePointerController)726 TEST_F(PointerChoreographerTest,
727        WhenShowTouchesDisabledAndTouchEventOccursDoesNotCreatePointerController) {
728     // Add a touch device and disable show touches.
729     mChoreographer.notifyInputDevicesChanged(
730             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
731     mChoreographer.setShowTouchesEnabled(false);
732     assertPointerControllerNotCreated();
733 
734     // Emit touch event. Still, PointerController should not be created.
735     mChoreographer.notifyMotion(
736             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
737                     .pointer(FIRST_TOUCH_POINTER)
738                     .deviceId(DEVICE_ID)
739                     .displayId(DISPLAY_ID)
740                     .build());
741     assertPointerControllerNotCreated();
742 }
743 
TEST_F(PointerChoreographerTest,WhenTouchDeviceIsRemovedRemovesPointerController)744 TEST_F(PointerChoreographerTest, WhenTouchDeviceIsRemovedRemovesPointerController) {
745     // Make sure the PointerController is created.
746     mChoreographer.notifyInputDevicesChanged(
747             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
748     mChoreographer.setShowTouchesEnabled(true);
749     mChoreographer.notifyMotion(
750             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
751                     .pointer(FIRST_TOUCH_POINTER)
752                     .deviceId(DEVICE_ID)
753                     .displayId(DISPLAY_ID)
754                     .build());
755     auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
756 
757     // Remove the device.
758     mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}});
759     assertPointerControllerRemoved(pc);
760 }
761 
TEST_F(PointerChoreographerTest,WhenShowTouchesDisabledRemovesPointerController)762 TEST_F(PointerChoreographerTest, WhenShowTouchesDisabledRemovesPointerController) {
763     // Make sure the PointerController is created.
764     mChoreographer.notifyInputDevicesChanged(
765             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
766     mChoreographer.setShowTouchesEnabled(true);
767     mChoreographer.notifyMotion(
768             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
769                     .pointer(FIRST_TOUCH_POINTER)
770                     .deviceId(DEVICE_ID)
771                     .displayId(DISPLAY_ID)
772                     .build());
773     auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
774 
775     // Disable show touches.
776     mChoreographer.setShowTouchesEnabled(false);
777     assertPointerControllerRemoved(pc);
778 }
779 
TEST_F(PointerChoreographerTest,TouchSetsSpots)780 TEST_F(PointerChoreographerTest, TouchSetsSpots) {
781     mChoreographer.setShowTouchesEnabled(true);
782     mChoreographer.notifyInputDevicesChanged(
783             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
784 
785     // Emit first pointer down.
786     mChoreographer.notifyMotion(
787             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
788                     .pointer(FIRST_TOUCH_POINTER)
789                     .deviceId(DEVICE_ID)
790                     .displayId(DISPLAY_ID)
791                     .build());
792     auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
793     pc->assertSpotCount(DISPLAY_ID, 1);
794 
795     // Emit second pointer down.
796     mChoreographer.notifyMotion(
797             MotionArgsBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
798                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
799                               AINPUT_SOURCE_TOUCHSCREEN)
800                     .pointer(FIRST_TOUCH_POINTER)
801                     .pointer(SECOND_TOUCH_POINTER)
802                     .deviceId(DEVICE_ID)
803                     .displayId(DISPLAY_ID)
804                     .build());
805     pc->assertSpotCount(DISPLAY_ID, 2);
806 
807     // Emit second pointer up.
808     mChoreographer.notifyMotion(
809             MotionArgsBuilder(AMOTION_EVENT_ACTION_POINTER_UP |
810                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
811                               AINPUT_SOURCE_TOUCHSCREEN)
812                     .pointer(FIRST_TOUCH_POINTER)
813                     .pointer(SECOND_TOUCH_POINTER)
814                     .deviceId(DEVICE_ID)
815                     .displayId(DISPLAY_ID)
816                     .build());
817     pc->assertSpotCount(DISPLAY_ID, 1);
818 
819     // Emit first pointer up.
820     mChoreographer.notifyMotion(
821             MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
822                     .pointer(FIRST_TOUCH_POINTER)
823                     .deviceId(DEVICE_ID)
824                     .displayId(DISPLAY_ID)
825                     .build());
826     pc->assertSpotCount(DISPLAY_ID, 0);
827 }
828 
829 /**
830  * In this test, we simulate the complete event of the stylus approaching and clicking on the
831  * screen, and then leaving the screen. We should ensure that spots are displayed correctly.
832  */
TEST_F(PointerChoreographerTest,TouchSetsSpotsForStylusEvent)833 TEST_F(PointerChoreographerTest, TouchSetsSpotsForStylusEvent) {
834     mChoreographer.setShowTouchesEnabled(true);
835     mChoreographer.setStylusPointerIconEnabled(false);
836     mChoreographer.notifyInputDevicesChanged(
837             {/*id=*/0,
838              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
839                                      DISPLAY_ID)}});
840 
841     // First, the stylus begin to approach the screen.
842     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
843                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
844                                         .pointer(STYLUS_POINTER)
845                                         .deviceId(DEVICE_ID)
846                                         .displayId(DISPLAY_ID)
847                                         .build());
848     auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
849     pc->assertSpotCount(DISPLAY_ID, 1);
850 
851     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
852                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
853                                         .pointer(STYLUS_POINTER)
854                                         .deviceId(DEVICE_ID)
855                                         .displayId(DISPLAY_ID)
856                                         .build());
857     pc->assertSpotCount(DISPLAY_ID, 1);
858 
859     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
860                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
861                                         .pointer(STYLUS_POINTER)
862                                         .deviceId(DEVICE_ID)
863                                         .displayId(DISPLAY_ID)
864                                         .build());
865     pc->assertSpotCount(DISPLAY_ID, 0);
866 
867     // Now, use stylus touch the screen.
868     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN,
869                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
870                                         .pointer(STYLUS_POINTER)
871                                         .deviceId(DEVICE_ID)
872                                         .displayId(DISPLAY_ID)
873                                         .build());
874     pc->assertSpotCount(DISPLAY_ID, 1);
875 
876     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE,
877                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
878                                         .pointer(STYLUS_POINTER)
879                                         .deviceId(DEVICE_ID)
880                                         .displayId(DISPLAY_ID)
881                                         .build());
882     pc->assertSpotCount(DISPLAY_ID, 1);
883 
884     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP,
885                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
886                                         .pointer(STYLUS_POINTER)
887                                         .deviceId(DEVICE_ID)
888                                         .displayId(DISPLAY_ID)
889                                         .build());
890     pc->assertSpotCount(DISPLAY_ID, 0);
891 
892     // Then, the stylus start leave from the screen.
893     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
894                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
895                                         .pointer(STYLUS_POINTER)
896                                         .deviceId(DEVICE_ID)
897                                         .displayId(DISPLAY_ID)
898                                         .build());
899     pc->assertSpotCount(DISPLAY_ID, 1);
900 
901     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
902                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
903                                         .pointer(STYLUS_POINTER)
904                                         .deviceId(DEVICE_ID)
905                                         .displayId(DISPLAY_ID)
906                                         .build());
907     pc->assertSpotCount(DISPLAY_ID, 1);
908 
909     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
910                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
911                                         .pointer(STYLUS_POINTER)
912                                         .deviceId(DEVICE_ID)
913                                         .displayId(DISPLAY_ID)
914                                         .build());
915     pc->assertSpotCount(DISPLAY_ID, 0);
916 }
917 
TEST_F(PointerChoreographerTest,TouchSetsSpotsForTwoDisplays)918 TEST_F(PointerChoreographerTest, TouchSetsSpotsForTwoDisplays) {
919     mChoreographer.setShowTouchesEnabled(true);
920     // Add two touch devices associated to different displays.
921     mChoreographer.notifyInputDevicesChanged(
922             {/*id=*/0,
923              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID),
924               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
925                                      ANOTHER_DISPLAY_ID)}});
926 
927     // Emit touch event with first device.
928     mChoreographer.notifyMotion(
929             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
930                     .pointer(FIRST_TOUCH_POINTER)
931                     .deviceId(DEVICE_ID)
932                     .displayId(DISPLAY_ID)
933                     .build());
934     auto firstDisplayPc = assertPointerControllerCreated(ControllerType::TOUCH);
935     firstDisplayPc->assertSpotCount(DISPLAY_ID, 1);
936 
937     // Emit touch events with second device.
938     mChoreographer.notifyMotion(
939             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
940                     .pointer(FIRST_TOUCH_POINTER)
941                     .deviceId(SECOND_DEVICE_ID)
942                     .displayId(ANOTHER_DISPLAY_ID)
943                     .build());
944     mChoreographer.notifyMotion(
945             MotionArgsBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
946                     .pointer(FIRST_TOUCH_POINTER)
947                     .pointer(SECOND_TOUCH_POINTER)
948                     .deviceId(SECOND_DEVICE_ID)
949                     .displayId(ANOTHER_DISPLAY_ID)
950                     .build());
951 
952     // There should be another PointerController created.
953     auto secondDisplayPc = assertPointerControllerCreated(ControllerType::TOUCH);
954 
955     // Check if the spots are set for the second device.
956     secondDisplayPc->assertSpotCount(ANOTHER_DISPLAY_ID, 2);
957 
958     // Check if there's no change on the spot of the first device.
959     firstDisplayPc->assertSpotCount(DISPLAY_ID, 1);
960 }
961 
TEST_F(PointerChoreographerTest,WhenTouchDeviceIsResetClearsSpots)962 TEST_F(PointerChoreographerTest, WhenTouchDeviceIsResetClearsSpots) {
963     // Make sure the PointerController is created and there is a spot.
964     mChoreographer.notifyInputDevicesChanged(
965             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
966     mChoreographer.setShowTouchesEnabled(true);
967     mChoreographer.notifyMotion(
968             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
969                     .pointer(FIRST_TOUCH_POINTER)
970                     .deviceId(DEVICE_ID)
971                     .displayId(DISPLAY_ID)
972                     .build());
973     auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
974     pc->assertSpotCount(DISPLAY_ID, 1);
975 
976     // Reset the device and ensure the touch pointer controller was removed.
977     mChoreographer.notifyDeviceReset(NotifyDeviceResetArgs(/*id=*/1, /*eventTime=*/0, DEVICE_ID));
978     assertPointerControllerRemoved(pc);
979 }
980 
981 /**
982  * When both "show touches" and "stylus hover icons" are enabled, if the app doesn't specify an
983  * icon for the hovering stylus, fall back to using the spot hover icon.
984  */
TEST_F(PointerChoreographerTest,ShowTouchesOverridesUnspecifiedStylusIcon)985 TEST_F(PointerChoreographerTest, ShowTouchesOverridesUnspecifiedStylusIcon) {
986     mChoreographer.setShowTouchesEnabled(true);
987     mChoreographer.setStylusPointerIconEnabled(true);
988     mChoreographer.notifyInputDevicesChanged(
989             {/*id=*/0,
990              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
991                                      DISPLAY_ID)}});
992 
993     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
994                                                   AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
995                                         .pointer(STYLUS_POINTER)
996                                         .deviceId(DEVICE_ID)
997                                         .displayId(DISPLAY_ID)
998                                         .build());
999     auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
1000 
1001     mChoreographer.setPointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED, DISPLAY_ID, DEVICE_ID);
1002     pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER);
1003 
1004     mChoreographer.setPointerIcon(PointerIconStyle::TYPE_ARROW, DISPLAY_ID, DEVICE_ID);
1005     pc->assertPointerIconSet(PointerIconStyle::TYPE_ARROW);
1006 
1007     mChoreographer.setPointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED, DISPLAY_ID, DEVICE_ID);
1008     pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER);
1009 }
1010 
1011 using StylusFixtureParam =
1012         std::tuple</*name*/ std::string_view, /*source*/ uint32_t, ControllerType>;
1013 
1014 class StylusTestFixture : public PointerChoreographerTest,
1015                           public ::testing::WithParamInterface<StylusFixtureParam> {};
1016 
1017 INSTANTIATE_TEST_SUITE_P(PointerChoreographerTest, StylusTestFixture,
1018                          ::testing::Values(std::make_tuple("DirectStylus", AINPUT_SOURCE_STYLUS,
1019                                                            ControllerType::STYLUS),
1020                                            std::make_tuple("DrawingTablet", DRAWING_TABLET_SOURCE,
1021                                                            ControllerType::MOUSE)),
__anon062b71b00e02(const testing::TestParamInfo<StylusFixtureParam>& p) 1022                          [](const testing::TestParamInfo<StylusFixtureParam>& p) {
1023                              return std::string{std::get<0>(p.param)};
1024                          });
1025 
TEST_P(StylusTestFixture,WhenStylusPointerIconEnabledAndDisabledDoesNotCreatePointerController)1026 TEST_P(StylusTestFixture, WhenStylusPointerIconEnabledAndDisabledDoesNotCreatePointerController) {
1027     const auto& [name, source, controllerType] = GetParam();
1028 
1029     // Disable stylus pointer icon and add a stylus device.
1030     mChoreographer.setStylusPointerIconEnabled(false);
1031     mChoreographer.notifyInputDevicesChanged(
1032             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1033     assertPointerControllerNotCreated();
1034 
1035     // Enable stylus pointer icon. PointerController still should not be created.
1036     mChoreographer.setStylusPointerIconEnabled(true);
1037     assertPointerControllerNotCreated();
1038 }
1039 
TEST_P(StylusTestFixture,WhenStylusHoverEventOccursCreatesPointerController)1040 TEST_P(StylusTestFixture, WhenStylusHoverEventOccursCreatesPointerController) {
1041     const auto& [name, source, controllerType] = GetParam();
1042 
1043     // Add a stylus device and enable stylus pointer icon.
1044     mChoreographer.notifyInputDevicesChanged(
1045             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1046     mChoreographer.setStylusPointerIconEnabled(true);
1047     assertPointerControllerNotCreated();
1048 
1049     // Emit hover event. Now PointerController should be created.
1050     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1051                                         .pointer(STYLUS_POINTER)
1052                                         .deviceId(DEVICE_ID)
1053                                         .displayId(DISPLAY_ID)
1054                                         .build());
1055     assertPointerControllerCreated(controllerType);
1056 }
1057 
TEST_F(PointerChoreographerTest,StylusHoverEventWhenStylusPointerIconDisabled)1058 TEST_F(PointerChoreographerTest, StylusHoverEventWhenStylusPointerIconDisabled) {
1059     // Add a stylus device and disable stylus pointer icon.
1060     mChoreographer.notifyInputDevicesChanged(
1061             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
1062     mChoreographer.setStylusPointerIconEnabled(false);
1063     assertPointerControllerNotCreated();
1064 
1065     // Emit hover event. Still, PointerController should not be created.
1066     mChoreographer.notifyMotion(
1067             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1068                     .pointer(STYLUS_POINTER)
1069                     .deviceId(DEVICE_ID)
1070                     .displayId(DISPLAY_ID)
1071                     .build());
1072     assertPointerControllerNotCreated();
1073 }
1074 
TEST_F(PointerChoreographerTest,DrawingTabletHoverEventWhenStylusPointerIconDisabled)1075 TEST_F(PointerChoreographerTest, DrawingTabletHoverEventWhenStylusPointerIconDisabled) {
1076     // Add a drawing tablet and disable stylus pointer icon.
1077     mChoreographer.notifyInputDevicesChanged(
1078             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, DISPLAY_ID)}});
1079     mChoreographer.setStylusPointerIconEnabled(false);
1080     assertPointerControllerNotCreated();
1081 
1082     // Emit hover event. Drawing tablets are not affected by "stylus pointer icon" setting.
1083     mChoreographer.notifyMotion(
1084             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, DRAWING_TABLET_SOURCE)
1085                     .pointer(STYLUS_POINTER)
1086                     .deviceId(DEVICE_ID)
1087                     .displayId(DISPLAY_ID)
1088                     .build());
1089     assertPointerControllerCreated(ControllerType::MOUSE);
1090 }
1091 
TEST_P(StylusTestFixture,WhenStylusDeviceIsRemovedRemovesPointerController)1092 TEST_P(StylusTestFixture, WhenStylusDeviceIsRemovedRemovesPointerController) {
1093     const auto& [name, source, controllerType] = GetParam();
1094 
1095     // Make sure the PointerController is created.
1096     mChoreographer.notifyInputDevicesChanged(
1097             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1098     mChoreographer.setStylusPointerIconEnabled(true);
1099     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1100                                         .pointer(STYLUS_POINTER)
1101                                         .deviceId(DEVICE_ID)
1102                                         .displayId(DISPLAY_ID)
1103                                         .build());
1104     auto pc = assertPointerControllerCreated(controllerType);
1105 
1106     // Remove the device.
1107     mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}});
1108     assertPointerControllerRemoved(pc);
1109 }
1110 
TEST_F(PointerChoreographerTest,StylusPointerIconDisabledRemovesPointerController)1111 TEST_F(PointerChoreographerTest, StylusPointerIconDisabledRemovesPointerController) {
1112     // Make sure the PointerController is created.
1113     mChoreographer.notifyInputDevicesChanged(
1114             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
1115     mChoreographer.setStylusPointerIconEnabled(true);
1116     mChoreographer.notifyMotion(
1117             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
1118                     .pointer(STYLUS_POINTER)
1119                     .deviceId(DEVICE_ID)
1120                     .displayId(DISPLAY_ID)
1121                     .build());
1122     auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
1123 
1124     // Disable stylus pointer icon.
1125     mChoreographer.setStylusPointerIconEnabled(false);
1126     assertPointerControllerRemoved(pc);
1127 }
1128 
TEST_F(PointerChoreographerTest,StylusPointerIconDisabledDoesNotRemoveDrawingTabletPointerController)1129 TEST_F(PointerChoreographerTest,
1130        StylusPointerIconDisabledDoesNotRemoveDrawingTabletPointerController) {
1131     // Make sure the PointerController is created.
1132     mChoreographer.notifyInputDevicesChanged(
1133             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE, DISPLAY_ID)}});
1134     mChoreographer.setStylusPointerIconEnabled(true);
1135     mChoreographer.notifyMotion(
1136             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, DRAWING_TABLET_SOURCE)
1137                     .pointer(STYLUS_POINTER)
1138                     .deviceId(DEVICE_ID)
1139                     .displayId(DISPLAY_ID)
1140                     .build());
1141     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1142 
1143     // Disable stylus pointer icon. This should not affect drawing tablets.
1144     mChoreographer.setStylusPointerIconEnabled(false);
1145     assertPointerControllerNotRemoved(pc);
1146 }
1147 
TEST_P(StylusTestFixture,SetsViewportForStylusPointerController)1148 TEST_P(StylusTestFixture, SetsViewportForStylusPointerController) {
1149     const auto& [name, source, controllerType] = GetParam();
1150 
1151     // Set viewport.
1152     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1153 
1154     // Make sure the PointerController is created.
1155     mChoreographer.notifyInputDevicesChanged(
1156             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1157     mChoreographer.setStylusPointerIconEnabled(true);
1158     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1159                                         .pointer(STYLUS_POINTER)
1160                                         .deviceId(DEVICE_ID)
1161                                         .displayId(DISPLAY_ID)
1162                                         .build());
1163     auto pc = assertPointerControllerCreated(controllerType);
1164 
1165     // Check that viewport is set for the PointerController.
1166     pc->assertViewportSet(DISPLAY_ID);
1167 }
1168 
TEST_P(StylusTestFixture,WhenViewportIsSetLaterSetsViewportForStylusPointerController)1169 TEST_P(StylusTestFixture, WhenViewportIsSetLaterSetsViewportForStylusPointerController) {
1170     const auto& [name, source, controllerType] = GetParam();
1171 
1172     // Make sure the PointerController is created.
1173     mChoreographer.notifyInputDevicesChanged(
1174             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1175     mChoreographer.setStylusPointerIconEnabled(true);
1176     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1177                                         .pointer(STYLUS_POINTER)
1178                                         .deviceId(DEVICE_ID)
1179                                         .displayId(DISPLAY_ID)
1180                                         .build());
1181     auto pc = assertPointerControllerCreated(controllerType);
1182 
1183     // Check that viewport is unset.
1184     pc->assertViewportNotSet();
1185 
1186     // Set viewport.
1187     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1188 
1189     // Check that the viewport is set for the PointerController.
1190     pc->assertViewportSet(DISPLAY_ID);
1191 }
1192 
TEST_P(StylusTestFixture,WhenViewportDoesNotMatchDoesNotSetViewportForStylusPointerController)1193 TEST_P(StylusTestFixture, WhenViewportDoesNotMatchDoesNotSetViewportForStylusPointerController) {
1194     const auto& [name, source, controllerType] = GetParam();
1195 
1196     // Make sure the PointerController is created.
1197     mChoreographer.notifyInputDevicesChanged(
1198             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1199     mChoreographer.setStylusPointerIconEnabled(true);
1200     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1201                                         .pointer(STYLUS_POINTER)
1202                                         .deviceId(DEVICE_ID)
1203                                         .displayId(DISPLAY_ID)
1204                                         .build());
1205     auto pc = assertPointerControllerCreated(controllerType);
1206 
1207     // Check that viewport is unset.
1208     pc->assertViewportNotSet();
1209 
1210     // Set viewport which does not match the associated display of the stylus.
1211     mChoreographer.setDisplayViewports(createViewports({ANOTHER_DISPLAY_ID}));
1212 
1213     // Check that viewport is still unset.
1214     pc->assertViewportNotSet();
1215 }
1216 
TEST_P(StylusTestFixture,StylusHoverManipulatesPointer)1217 TEST_P(StylusTestFixture, StylusHoverManipulatesPointer) {
1218     const auto& [name, source, controllerType] = GetParam();
1219 
1220     mChoreographer.setStylusPointerIconEnabled(true);
1221     mChoreographer.notifyInputDevicesChanged(
1222             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1223     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1224 
1225     // Emit hover enter event. This is for creating PointerController.
1226     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1227                                         .pointer(STYLUS_POINTER)
1228                                         .deviceId(DEVICE_ID)
1229                                         .displayId(DISPLAY_ID)
1230                                         .build());
1231     auto pc = assertPointerControllerCreated(controllerType);
1232 
1233     // Emit hover move event. After bounds are set, PointerController will update the position.
1234     mChoreographer.notifyMotion(
1235             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, source)
1236                     .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(250))
1237                     .deviceId(DEVICE_ID)
1238                     .displayId(DISPLAY_ID)
1239                     .build());
1240     pc->assertPosition(150, 250);
1241     ASSERT_TRUE(pc->isPointerShown());
1242 
1243     // Emit hover exit event.
1244     mChoreographer.notifyMotion(
1245             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, source)
1246                     .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(250))
1247                     .deviceId(DEVICE_ID)
1248                     .displayId(DISPLAY_ID)
1249                     .build());
1250     // Check that the pointer is gone.
1251     ASSERT_FALSE(pc->isPointerShown());
1252 }
1253 
TEST_P(StylusTestFixture,StylusHoverManipulatesPointerForTwoDisplays)1254 TEST_P(StylusTestFixture, StylusHoverManipulatesPointerForTwoDisplays) {
1255     const auto& [name, source, controllerType] = GetParam();
1256 
1257     mChoreographer.setStylusPointerIconEnabled(true);
1258     // Add two stylus devices associated to different displays.
1259     mChoreographer.notifyInputDevicesChanged(
1260             {/*id=*/0,
1261              {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID),
1262               generateTestDeviceInfo(SECOND_DEVICE_ID, source, ANOTHER_DISPLAY_ID)}});
1263     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
1264 
1265     // Emit hover event with first device. This is for creating PointerController.
1266     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1267                                         .pointer(STYLUS_POINTER)
1268                                         .deviceId(DEVICE_ID)
1269                                         .displayId(DISPLAY_ID)
1270                                         .build());
1271     auto firstDisplayPc = assertPointerControllerCreated(controllerType);
1272 
1273     // Emit hover event with second device. This is for creating PointerController.
1274     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1275                                         .pointer(STYLUS_POINTER)
1276                                         .deviceId(SECOND_DEVICE_ID)
1277                                         .displayId(ANOTHER_DISPLAY_ID)
1278                                         .build());
1279 
1280     // There should be another PointerController created.
1281     auto secondDisplayPc = assertPointerControllerCreated(controllerType);
1282 
1283     // Emit hover event with first device.
1284     mChoreographer.notifyMotion(
1285             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, source)
1286                     .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(250))
1287                     .deviceId(DEVICE_ID)
1288                     .displayId(DISPLAY_ID)
1289                     .build());
1290 
1291     // Check the pointer of the first device.
1292     firstDisplayPc->assertPosition(150, 250);
1293     ASSERT_TRUE(firstDisplayPc->isPointerShown());
1294 
1295     // Emit hover event with second device.
1296     mChoreographer.notifyMotion(
1297             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, source)
1298                     .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(250).y(350))
1299                     .deviceId(SECOND_DEVICE_ID)
1300                     .displayId(ANOTHER_DISPLAY_ID)
1301                     .build());
1302 
1303     // Check the pointer of the second device.
1304     secondDisplayPc->assertPosition(250, 350);
1305     ASSERT_TRUE(secondDisplayPc->isPointerShown());
1306 
1307     // Check that there's no change on the pointer of the first device.
1308     firstDisplayPc->assertPosition(150, 250);
1309     ASSERT_TRUE(firstDisplayPc->isPointerShown());
1310 }
1311 
TEST_P(StylusTestFixture,WhenStylusDeviceIsResetRemovesPointer)1312 TEST_P(StylusTestFixture, WhenStylusDeviceIsResetRemovesPointer) {
1313     const auto& [name, source, controllerType] = GetParam();
1314 
1315     // Make sure the PointerController is created and there is a pointer.
1316     mChoreographer.notifyInputDevicesChanged(
1317             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1318     mChoreographer.setStylusPointerIconEnabled(true);
1319     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1320     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
1321                                         .pointer(STYLUS_POINTER)
1322                                         .deviceId(DEVICE_ID)
1323                                         .displayId(DISPLAY_ID)
1324                                         .build());
1325     auto pc = assertPointerControllerCreated(controllerType);
1326     ASSERT_TRUE(pc->isPointerShown());
1327 
1328     // Reset the device and see the pointer controller was removed.
1329     mChoreographer.notifyDeviceReset(NotifyDeviceResetArgs(/*id=*/1, /*eventTime=*/0, DEVICE_ID));
1330     assertPointerControllerRemoved(pc);
1331 }
1332 
TEST_F(PointerChoreographerTest,WhenTouchpadIsAddedCreatesPointerController)1333 TEST_F(PointerChoreographerTest, WhenTouchpadIsAddedCreatesPointerController) {
1334     mChoreographer.notifyInputDevicesChanged(
1335             {/*id=*/0,
1336              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1337                                      ui::LogicalDisplayId::INVALID)}});
1338     assertPointerControllerCreated(ControllerType::MOUSE);
1339 }
1340 
TEST_F(PointerChoreographerTest,WhenTouchpadIsRemovedRemovesPointerController)1341 TEST_F(PointerChoreographerTest, WhenTouchpadIsRemovedRemovesPointerController) {
1342     mChoreographer.notifyInputDevicesChanged(
1343             {/*id=*/0,
1344              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1345                                      ui::LogicalDisplayId::INVALID)}});
1346     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1347 
1348     // Remove the touchpad.
1349     mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}});
1350     assertPointerControllerRemoved(pc);
1351 }
1352 
TEST_F(PointerChoreographerTest,SetsViewportForAssociatedTouchpad)1353 TEST_F(PointerChoreographerTest, SetsViewportForAssociatedTouchpad) {
1354     // Just adding a viewport or device should not create a PointerController.
1355     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1356     mChoreographer.notifyInputDevicesChanged(
1357             {/*id=*/0,
1358              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1359                                      DISPLAY_ID)}});
1360     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1361     pc->assertViewportSet(DISPLAY_ID);
1362 }
1363 
TEST_F(PointerChoreographerTest,WhenViewportSetLaterSetsViewportForAssociatedTouchpad)1364 TEST_F(PointerChoreographerTest, WhenViewportSetLaterSetsViewportForAssociatedTouchpad) {
1365     // Without viewport information, PointerController will be created by a touchpad event
1366     // but viewport won't be set.
1367     mChoreographer.notifyInputDevicesChanged(
1368             {/*id=*/0,
1369              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1370                                      DISPLAY_ID)}});
1371     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1372     pc->assertViewportNotSet();
1373 
1374     // After Choreographer gets viewport, PointerController should also have viewport.
1375     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1376     pc->assertViewportSet(DISPLAY_ID);
1377 }
1378 
TEST_F(PointerChoreographerTest,SetsDefaultTouchpadViewportForPointerController)1379 TEST_F(PointerChoreographerTest, SetsDefaultTouchpadViewportForPointerController) {
1380     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1381     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1382 
1383     // For a touchpad event without a target display, default viewport should be set for
1384     // the PointerController.
1385     mChoreographer.notifyInputDevicesChanged(
1386             {/*id=*/0,
1387              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
1388                                      ui::LogicalDisplayId::INVALID)}});
1389     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1390     pc->assertViewportSet(DISPLAY_ID);
1391 }
1392 
TEST_F(PointerChoreographerTest,WhenDefaultTouchpadDisplayChangesSetsDefaultTouchpadViewportForPointerController)1393 TEST_F(PointerChoreographerTest,
1394        WhenDefaultTouchpadDisplayChangesSetsDefaultTouchpadViewportForPointerController) {
1395     // Set one display as a default touchpad display and create PointerController.
1396     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
1397     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1398     mChoreographer.notifyInputDevicesChanged(
1399             {/*id=*/0,
1400              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1401                                      ui::LogicalDisplayId::INVALID)}});
1402     auto firstDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
1403     firstDisplayPc->assertViewportSet(DISPLAY_ID);
1404 
1405     // Change default mouse display. Existing PointerController should be removed.
1406     mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
1407     assertPointerControllerRemoved(firstDisplayPc);
1408 
1409     auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
1410     secondDisplayPc->assertViewportSet(ANOTHER_DISPLAY_ID);
1411 }
1412 
TEST_F(PointerChoreographerTest,TouchpadCallsNotifyPointerDisplayIdChanged)1413 TEST_F(PointerChoreographerTest, TouchpadCallsNotifyPointerDisplayIdChanged) {
1414     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1415     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1416     mChoreographer.notifyInputDevicesChanged(
1417             {/*id=*/0,
1418              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1419                                      ui::LogicalDisplayId::INVALID)}});
1420     assertPointerControllerCreated(ControllerType::MOUSE);
1421 
1422     assertPointerDisplayIdNotified(DISPLAY_ID);
1423 }
1424 
TEST_F(PointerChoreographerTest,WhenViewportIsSetLaterTouchpadCallsNotifyPointerDisplayIdChanged)1425 TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterTouchpadCallsNotifyPointerDisplayIdChanged) {
1426     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1427     mChoreographer.notifyInputDevicesChanged(
1428             {/*id=*/0,
1429              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1430                                      ui::LogicalDisplayId::INVALID)}});
1431     assertPointerControllerCreated(ControllerType::MOUSE);
1432     assertPointerDisplayIdNotNotified();
1433 
1434     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1435     assertPointerDisplayIdNotified(DISPLAY_ID);
1436 }
1437 
TEST_F(PointerChoreographerTest,WhenTouchpadIsRemovedCallsNotifyPointerDisplayIdChanged)1438 TEST_F(PointerChoreographerTest, WhenTouchpadIsRemovedCallsNotifyPointerDisplayIdChanged) {
1439     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1440     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1441     mChoreographer.notifyInputDevicesChanged(
1442             {/*id=*/0,
1443              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1444                                      ui::LogicalDisplayId::INVALID)}});
1445     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1446     assertPointerDisplayIdNotified(DISPLAY_ID);
1447 
1448     mChoreographer.notifyInputDevicesChanged({/*id=*/1, {}});
1449     assertPointerDisplayIdNotified(ui::LogicalDisplayId::INVALID);
1450     assertPointerControllerRemoved(pc);
1451 }
1452 
TEST_F(PointerChoreographerTest,WhenDefaultMouseDisplayChangesTouchpadCallsNotifyPointerDisplayIdChanged)1453 TEST_F(PointerChoreographerTest,
1454        WhenDefaultMouseDisplayChangesTouchpadCallsNotifyPointerDisplayIdChanged) {
1455     // Add two viewports.
1456     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
1457 
1458     // Set one viewport as a default mouse display ID.
1459     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1460     mChoreographer.notifyInputDevicesChanged(
1461             {/*id=*/0,
1462              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1463                                      ui::LogicalDisplayId::INVALID)}});
1464     auto firstDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
1465     assertPointerDisplayIdNotified(DISPLAY_ID);
1466 
1467     // Set another viewport as a default mouse display ID. ui::LogicalDisplayId::INVALID will be
1468     // notified before a touchpad event.
1469     mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
1470     assertPointerControllerRemoved(firstDisplayPc);
1471 
1472     assertPointerControllerCreated(ControllerType::MOUSE);
1473     assertPointerDisplayIdNotified(ANOTHER_DISPLAY_ID);
1474 }
1475 
TEST_F(PointerChoreographerTest,TouchpadMovesPointerAndReturnsNewArgs)1476 TEST_F(PointerChoreographerTest, TouchpadMovesPointerAndReturnsNewArgs) {
1477     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1478     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1479     mChoreographer.notifyInputDevicesChanged(
1480             {/*id=*/0,
1481              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1482                                      ui::LogicalDisplayId::INVALID)}});
1483     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1484     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
1485 
1486     // Set initial position of the PointerController.
1487     pc->setPosition(100, 200);
1488 
1489     // Make NotifyMotionArgs and notify Choreographer.
1490     mChoreographer.notifyMotion(
1491             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1492                     .pointer(TOUCHPAD_POINTER)
1493                     .deviceId(DEVICE_ID)
1494                     .displayId(ui::LogicalDisplayId::INVALID)
1495                     .build());
1496 
1497     // Check that the PointerController updated the position and the pointer is shown.
1498     pc->assertPosition(110, 220);
1499     ASSERT_TRUE(pc->isPointerShown());
1500 
1501     // Check that x-y coordinates, displayId and cursor position are correctly updated.
1502     mTestListener.assertNotifyMotionWasCalled(
1503             AllOf(WithCoords(110, 220), WithDisplayId(DISPLAY_ID), WithCursorPosition(110, 220)));
1504 }
1505 
TEST_F(PointerChoreographerTest,TouchpadAddsPointerPositionToTheCoords)1506 TEST_F(PointerChoreographerTest, TouchpadAddsPointerPositionToTheCoords) {
1507     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1508     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1509     mChoreographer.notifyInputDevicesChanged(
1510             {/*id=*/0,
1511              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1512                                      ui::LogicalDisplayId::INVALID)}});
1513     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1514     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
1515 
1516     // Set initial position of the PointerController.
1517     pc->setPosition(100, 200);
1518 
1519     // Notify motion with fake fingers, as if it is multi-finger swipe.
1520     // Check if the position of the PointerController is added to the fake finger coords.
1521     mChoreographer.notifyMotion(
1522             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
1523                     .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(-100).y(0))
1524                     .classification(MotionClassification::MULTI_FINGER_SWIPE)
1525                     .deviceId(DEVICE_ID)
1526                     .displayId(ui::LogicalDisplayId::INVALID)
1527                     .build());
1528     mTestListener.assertNotifyMotionWasCalled(
1529             AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
1530                   WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
1531                   WithCoords(0, 200), WithCursorPosition(100, 200)));
1532     mChoreographer.notifyMotion(
1533             MotionArgsBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
1534                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
1535                               AINPUT_SOURCE_MOUSE)
1536                     .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(-100).y(0))
1537                     .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(0).y(0))
1538                     .classification(MotionClassification::MULTI_FINGER_SWIPE)
1539                     .deviceId(DEVICE_ID)
1540                     .displayId(ui::LogicalDisplayId::INVALID)
1541                     .build());
1542     mTestListener.assertNotifyMotionWasCalled(
1543             AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
1544                                    (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)),
1545                   WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
1546                   WithPointerCoords(0, 0, 200), WithPointerCoords(1, 100, 200),
1547                   WithCursorPosition(100, 200)));
1548     mChoreographer.notifyMotion(
1549             MotionArgsBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
1550                                       (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
1551                               AINPUT_SOURCE_MOUSE)
1552                     .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(-100).y(0))
1553                     .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(0).y(0))
1554                     .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(100).y(0))
1555                     .classification(MotionClassification::MULTI_FINGER_SWIPE)
1556                     .deviceId(DEVICE_ID)
1557                     .displayId(ui::LogicalDisplayId::INVALID)
1558                     .build());
1559     mTestListener.assertNotifyMotionWasCalled(
1560             AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
1561                                    (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)),
1562                   WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
1563                   WithPointerCoords(0, 0, 200), WithPointerCoords(1, 100, 200),
1564                   WithPointerCoords(2, 200, 200), WithCursorPosition(100, 200)));
1565     mChoreographer.notifyMotion(
1566             MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
1567                     .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(-90).y(10))
1568                     .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10))
1569                     .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(110).y(10))
1570                     .classification(MotionClassification::MULTI_FINGER_SWIPE)
1571                     .deviceId(DEVICE_ID)
1572                     .displayId(ui::LogicalDisplayId::INVALID)
1573                     .build());
1574     mTestListener.assertNotifyMotionWasCalled(
1575             AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
1576                   WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
1577                   WithPointerCoords(0, 10, 210), WithPointerCoords(1, 110, 210),
1578                   WithPointerCoords(2, 210, 210), WithCursorPosition(100, 200)));
1579 }
1580 
TEST_F(PointerChoreographerTest,AssociatedTouchpadMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay)1581 TEST_F(PointerChoreographerTest,
1582        AssociatedTouchpadMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) {
1583     // Add two displays and set one to default.
1584     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
1585     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1586 
1587     // Add two devices, one unassociated and the other associated with non-default mouse display.
1588     mChoreographer.notifyInputDevicesChanged(
1589             {/*id=*/0,
1590              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1591                                      ui::LogicalDisplayId::INVALID),
1592               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1593                                      ANOTHER_DISPLAY_ID)}});
1594     auto unassociatedMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
1595     ASSERT_EQ(DISPLAY_ID, unassociatedMousePc->getDisplayId());
1596     auto associatedMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
1597     ASSERT_EQ(ANOTHER_DISPLAY_ID, associatedMousePc->getDisplayId());
1598 
1599     // Set initial positions for PointerControllers.
1600     unassociatedMousePc->setPosition(100, 200);
1601     associatedMousePc->setPosition(300, 400);
1602 
1603     // Make NotifyMotionArgs from the associated mouse and notify Choreographer.
1604     mChoreographer.notifyMotion(
1605             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
1606                     .pointer(TOUCHPAD_POINTER)
1607                     .deviceId(SECOND_DEVICE_ID)
1608                     .displayId(ANOTHER_DISPLAY_ID)
1609                     .build());
1610 
1611     // Check the status of the PointerControllers.
1612     unassociatedMousePc->assertPosition(100, 200);
1613     ASSERT_EQ(DISPLAY_ID, unassociatedMousePc->getDisplayId());
1614     associatedMousePc->assertPosition(310, 420);
1615     ASSERT_EQ(ANOTHER_DISPLAY_ID, associatedMousePc->getDisplayId());
1616     ASSERT_TRUE(associatedMousePc->isPointerShown());
1617 
1618     // Check that x-y coordinates, displayId and cursor position are correctly updated.
1619     mTestListener.assertNotifyMotionWasCalled(
1620             AllOf(WithCoords(310, 420), WithDeviceId(SECOND_DEVICE_ID),
1621                   WithDisplayId(ANOTHER_DISPLAY_ID), WithCursorPosition(310, 420)));
1622 }
1623 
TEST_F(PointerChoreographerTest,DoesNotMovePointerForTouchpadSource)1624 TEST_F(PointerChoreographerTest, DoesNotMovePointerForTouchpadSource) {
1625     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1626     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1627     mChoreographer.notifyInputDevicesChanged(
1628             {/*id=*/0,
1629              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1630                                      ui::LogicalDisplayId::INVALID)}});
1631     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1632     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
1633 
1634     // Set initial position of the PointerController.
1635     pc->setPosition(200, 300);
1636 
1637     // Assume that pointer capture is enabled.
1638     mChoreographer.notifyPointerCaptureChanged(
1639             NotifyPointerCaptureChangedArgs(/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC),
1640                                             PointerCaptureRequest(/*window=*/sp<BBinder>::make(),
1641                                                                   /*seq=*/0)));
1642 
1643     // Notify motion as if pointer capture is enabled.
1644     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHPAD)
1645                                         .pointer(FIRST_TOUCH_POINTER)
1646                                         .deviceId(DEVICE_ID)
1647                                         .displayId(ui::LogicalDisplayId::INVALID)
1648                                         .build());
1649 
1650     // Check that there's no update on the PointerController.
1651     pc->assertPosition(200, 300);
1652     ASSERT_FALSE(pc->isPointerShown());
1653 
1654     // Check x-y coordinates, displayId and cursor position are not changed.
1655     mTestListener.assertNotifyMotionWasCalled(
1656             AllOf(WithCoords(100, 200), WithDisplayId(ui::LogicalDisplayId::INVALID),
1657                   WithCursorPosition(AMOTION_EVENT_INVALID_CURSOR_POSITION,
1658                                      AMOTION_EVENT_INVALID_CURSOR_POSITION)));
1659 }
1660 
TEST_F(PointerChoreographerTest,WhenPointerCaptureEnabledTouchpadHidesPointer)1661 TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledTouchpadHidesPointer) {
1662     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1663     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1664     mChoreographer.notifyInputDevicesChanged(
1665             {/*id=*/0,
1666              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
1667                                      ui::LogicalDisplayId::INVALID)}});
1668     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1669     ASSERT_EQ(DISPLAY_ID, pc->getDisplayId());
1670     ASSERT_TRUE(pc->isPointerShown());
1671 
1672     // Enable pointer capture and check if the PointerController hid the pointer.
1673     mChoreographer.notifyPointerCaptureChanged(
1674             NotifyPointerCaptureChangedArgs(/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC),
1675                                             PointerCaptureRequest(/*window=*/sp<BBinder>::make(),
1676                                                                   /*seq=*/0)));
1677     ASSERT_FALSE(pc->isPointerShown());
1678 }
1679 
TEST_F(PointerChoreographerTest,SetsPointerIconForMouse)1680 TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) {
1681     // Make sure there is a PointerController.
1682     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1683     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1684     mChoreographer.notifyInputDevicesChanged(
1685             {/*id=*/0,
1686              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
1687                                      ui::LogicalDisplayId::INVALID)}});
1688     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1689     pc->assertPointerIconNotSet();
1690 
1691     // Set pointer icon for the device.
1692     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
1693     pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
1694 }
1695 
TEST_F(PointerChoreographerTest,DoesNotSetMousePointerIconForWrongDisplayId)1696 TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) {
1697     // Make sure there is a PointerController.
1698     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1699     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1700     mChoreographer.notifyInputDevicesChanged(
1701             {/*id=*/0,
1702              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
1703                                      ui::LogicalDisplayId::INVALID)}});
1704     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1705     pc->assertPointerIconNotSet();
1706 
1707     // Set pointer icon for wrong display id. This should be ignored.
1708     ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
1709                                                SECOND_DEVICE_ID));
1710     pc->assertPointerIconNotSet();
1711 }
1712 
TEST_F(PointerChoreographerTest,DoesNotSetPointerIconForWrongDeviceId)1713 TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) {
1714     // Make sure there is a PointerController.
1715     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1716     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1717     mChoreographer.notifyInputDevicesChanged(
1718             {/*id=*/0,
1719              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
1720                                      ui::LogicalDisplayId::INVALID)}});
1721     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1722     pc->assertPointerIconNotSet();
1723 
1724     // Set pointer icon for wrong device id. This should be ignored.
1725     ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
1726                                                SECOND_DEVICE_ID));
1727     pc->assertPointerIconNotSet();
1728 }
1729 
TEST_F(PointerChoreographerTest,SetsCustomPointerIconForMouse)1730 TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) {
1731     // Make sure there is a PointerController.
1732     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1733     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1734     mChoreographer.notifyInputDevicesChanged(
1735             {/*id=*/0,
1736              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
1737                                      ui::LogicalDisplayId::INVALID)}});
1738     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1739     pc->assertCustomPointerIconNotSet();
1740 
1741     // Set custom pointer icon for the device.
1742     ASSERT_TRUE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
1743                                                       PointerIconStyle::TYPE_CUSTOM),
1744                                               DISPLAY_ID, DEVICE_ID));
1745     pc->assertCustomPointerIconSet(PointerIconStyle::TYPE_CUSTOM);
1746 
1747     // Set custom pointer icon for wrong device id. This should be ignored.
1748     ASSERT_FALSE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
1749                                                        PointerIconStyle::TYPE_CUSTOM),
1750                                                DISPLAY_ID, SECOND_DEVICE_ID));
1751     pc->assertCustomPointerIconNotSet();
1752 }
1753 
TEST_F(PointerChoreographerTest,SetsPointerIconForMouseOnTwoDisplays)1754 TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) {
1755     // Make sure there are two PointerControllers on different displays.
1756     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
1757     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
1758     mChoreographer.notifyInputDevicesChanged(
1759             {/*id=*/0,
1760              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
1761               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
1762     auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
1763     ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
1764     auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
1765     ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());
1766 
1767     // Set pointer icon for one mouse.
1768     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
1769     firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
1770     secondMousePc->assertPointerIconNotSet();
1771 
1772     // Set pointer icon for another mouse.
1773     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
1774                                               SECOND_DEVICE_ID));
1775     secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
1776     firstMousePc->assertPointerIconNotSet();
1777 }
1778 
1779 using SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam =
1780         std::tuple<std::string_view /*name*/, uint32_t /*source*/, ControllerType, PointerBuilder,
1781                    std::function<void(PointerChoreographer&)>, int32_t /*action*/>;
1782 
1783 class SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture
1784       : public PointerChoreographerTest,
1785         public ::testing::WithParamInterface<
1786                 SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam> {
1787 protected:
initializePointerDevice(const PointerBuilder & pointerBuilder,const uint32_t source,const std::function<void (PointerChoreographer &)> onControllerInit,const int32_t action)1788     void initializePointerDevice(const PointerBuilder& pointerBuilder, const uint32_t source,
1789                                  const std::function<void(PointerChoreographer&)> onControllerInit,
1790                                  const int32_t action) {
1791         mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1792 
1793         // Add appropriate pointer device
1794         mChoreographer.notifyInputDevicesChanged(
1795                 {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
1796         onControllerInit(mChoreographer);
1797 
1798         // Emit input events to create PointerController
1799         mChoreographer.notifyMotion(MotionArgsBuilder(action, source)
1800                                             .pointer(pointerBuilder)
1801                                             .deviceId(DEVICE_ID)
1802                                             .displayId(DISPLAY_ID)
1803                                             .build());
1804     }
1805 };
1806 
1807 INSTANTIATE_TEST_SUITE_P(
1808         PointerChoreographerTest, SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,
1809         ::testing::Values(
1810                 std::make_tuple(
1811                         "TouchSpots", AINPUT_SOURCE_TOUCHSCREEN, ControllerType::TOUCH,
1812                         FIRST_TOUCH_POINTER,
__anon062b71b00f02(PointerChoreographer& pc) 1813                         [](PointerChoreographer& pc) { pc.setShowTouchesEnabled(true); },
1814                         AMOTION_EVENT_ACTION_DOWN),
1815                 std::make_tuple(
1816                         "Mouse", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, MOUSE_POINTER,
__anon062b71b01002(PointerChoreographer& pc) 1817                         [](PointerChoreographer& pc) {}, AMOTION_EVENT_ACTION_DOWN),
1818                 std::make_tuple(
1819                         "Stylus", AINPUT_SOURCE_STYLUS, ControllerType::STYLUS, STYLUS_POINTER,
__anon062b71b01102(PointerChoreographer& pc) 1820                         [](PointerChoreographer& pc) { pc.setStylusPointerIconEnabled(true); },
1821                         AMOTION_EVENT_ACTION_HOVER_ENTER),
1822                 std::make_tuple(
1823                         "DrawingTablet", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS,
__anon062b71b01202(PointerChoreographer& pc) 1824                         ControllerType::MOUSE, STYLUS_POINTER, [](PointerChoreographer& pc) {},
1825                         AMOTION_EVENT_ACTION_HOVER_ENTER)),
1826         [](const testing::TestParamInfo<
__anon062b71b01302(const testing::TestParamInfo< SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam>& p) 1827                 SkipPointerScreenshotForPrivacySensitiveDisplaysFixtureParam>& p) {
1828             return std::string{std::get<0>(p.param)};
1829         });
1830 
TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,WindowInfosListenerIsOnlyRegisteredWhenRequired)1831 TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,
1832        WindowInfosListenerIsOnlyRegisteredWhenRequired) {
1833     const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] =
1834             GetParam();
1835     assertWindowInfosListenerNotRegistered();
1836 
1837     // Listener should registered when a pointer device is added
1838     initializePointerDevice(pointerBuilder, source, onControllerInit, action);
1839     assertWindowInfosListenerRegistered();
1840 
1841     mChoreographer.notifyInputDevicesChanged({});
1842     assertWindowInfosListenerNotRegistered();
1843 }
1844 
TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,InitialDisplayInfoIsPopulatedForListener)1845 TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,
1846        InitialDisplayInfoIsPopulatedForListener) {
1847     const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] =
1848             GetParam();
1849     // listener should not be registered if there is no pointer device
1850     assertWindowInfosListenerNotRegistered();
1851 
1852     gui::WindowInfo windowInfo;
1853     windowInfo.displayId = DISPLAY_ID;
1854     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
1855     mInjectedInitialWindowInfos = {windowInfo};
1856 
1857     initializePointerDevice(pointerBuilder, source, onControllerInit, action);
1858     assertWindowInfosListenerRegistered();
1859 
1860     // Pointer indicators should be hidden based on the initial display info
1861     auto pc = assertPointerControllerCreated(controllerType);
1862     pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID);
1863     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1864 
1865     // un-marking the privacy sensitive display should reset the state
1866     windowInfo.inputConfig.clear();
1867     gui::DisplayInfo displayInfo;
1868     displayInfo.displayId = DISPLAY_ID;
1869     mRegisteredWindowInfoListener
1870             ->onWindowInfosChanged(/*windowInfosUpdate=*/
1871                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
1872 
1873     pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
1874     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1875 }
1876 
TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,SkipsPointerScreenshotForPrivacySensitiveWindows)1877 TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,
1878        SkipsPointerScreenshotForPrivacySensitiveWindows) {
1879     const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] =
1880             GetParam();
1881     initializePointerDevice(pointerBuilder, source, onControllerInit, action);
1882 
1883     // By default pointer indicators should not be hidden
1884     auto pc = assertPointerControllerCreated(controllerType);
1885     pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
1886     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1887 
1888     // marking a display privacy sensitive should set flag to hide pointer indicators on the
1889     // display screenshot
1890     gui::WindowInfo windowInfo;
1891     windowInfo.displayId = DISPLAY_ID;
1892     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
1893     gui::DisplayInfo displayInfo;
1894     displayInfo.displayId = DISPLAY_ID;
1895     assertWindowInfosListenerRegistered();
1896     mRegisteredWindowInfoListener
1897             ->onWindowInfosChanged(/*windowInfosUpdate=*/
1898                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
1899 
1900     pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID);
1901     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1902 
1903     // un-marking the privacy sensitive display should reset the state
1904     windowInfo.inputConfig.clear();
1905     mRegisteredWindowInfoListener
1906             ->onWindowInfosChanged(/*windowInfosUpdate=*/
1907                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
1908 
1909     pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
1910     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1911 }
1912 
TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,DoesNotSkipPointerScreenshotForHiddenPrivacySensitiveWindows)1913 TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,
1914        DoesNotSkipPointerScreenshotForHiddenPrivacySensitiveWindows) {
1915     const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] =
1916             GetParam();
1917     initializePointerDevice(pointerBuilder, source, onControllerInit, action);
1918 
1919     // By default pointer indicators should not be hidden
1920     auto pc = assertPointerControllerCreated(controllerType);
1921     pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
1922     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1923 
1924     gui::WindowInfo windowInfo;
1925     windowInfo.displayId = DISPLAY_ID;
1926     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
1927     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::NOT_VISIBLE;
1928     gui::DisplayInfo displayInfo;
1929     displayInfo.displayId = DISPLAY_ID;
1930     assertWindowInfosListenerRegistered();
1931     mRegisteredWindowInfoListener
1932             ->onWindowInfosChanged(/*windowInfosUpdate=*/
1933                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
1934 
1935     pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
1936     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1937 }
1938 
TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,DoesNotUpdateControllerForUnchangedPrivacySensitiveWindows)1939 TEST_P(SkipPointerScreenshotForPrivacySensitiveDisplaysTestFixture,
1940        DoesNotUpdateControllerForUnchangedPrivacySensitiveWindows) {
1941     const auto& [name, source, controllerType, pointerBuilder, onControllerInit, action] =
1942             GetParam();
1943     initializePointerDevice(pointerBuilder, source, onControllerInit, action);
1944 
1945     auto pc = assertPointerControllerCreated(controllerType);
1946     gui::WindowInfo windowInfo;
1947     windowInfo.displayId = DISPLAY_ID;
1948     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
1949     gui::DisplayInfo displayInfo;
1950     displayInfo.displayId = DISPLAY_ID;
1951     assertWindowInfosListenerRegistered();
1952     mRegisteredWindowInfoListener
1953             ->onWindowInfosChanged(/*windowInfosUpdate=*/
1954                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
1955 
1956     gui::WindowInfo windowInfo2 = windowInfo;
1957     windowInfo2.inputConfig.clear();
1958     pc->assertSkipScreenshotFlagChanged();
1959 
1960     // controller should not be updated if there are no changes in privacy sensitive windows
1961     mRegisteredWindowInfoListener->onWindowInfosChanged(/*windowInfosUpdate=*/
1962                                                         {{windowInfo, windowInfo2},
1963                                                          {displayInfo},
1964                                                          /*vsyncId=*/0,
1965                                                          /*timestamp=*/0});
1966     pc->assertSkipScreenshotFlagNotChanged();
1967 }
1968 
TEST_F_WITH_FLAGS(PointerChoreographerTest,HidesPointerScreenshotForExistingPrivacySensitiveWindows,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::input::flags,hide_pointer_indicators_for_secure_windows)))1969 TEST_F_WITH_FLAGS(
1970         PointerChoreographerTest, HidesPointerScreenshotForExistingPrivacySensitiveWindows,
1971         REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
1972                                             hide_pointer_indicators_for_secure_windows))) {
1973     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
1974 
1975     // Add a first mouse device
1976     mChoreographer.notifyInputDevicesChanged(
1977             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, DISPLAY_ID)}});
1978 
1979     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
1980                                         .pointer(MOUSE_POINTER)
1981                                         .deviceId(DEVICE_ID)
1982                                         .displayId(DISPLAY_ID)
1983                                         .build());
1984 
1985     gui::WindowInfo windowInfo;
1986     windowInfo.displayId = DISPLAY_ID;
1987     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
1988     gui::DisplayInfo displayInfo;
1989     displayInfo.displayId = DISPLAY_ID;
1990     assertWindowInfosListenerRegistered();
1991     mRegisteredWindowInfoListener
1992             ->onWindowInfosChanged(/*windowInfosUpdate=*/
1993                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
1994 
1995     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
1996     pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID);
1997     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
1998 
1999     // Add a second touch device and controller
2000     mChoreographer.notifyInputDevicesChanged(
2001             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID)}});
2002     mChoreographer.setShowTouchesEnabled(true);
2003     mChoreographer.notifyMotion(
2004             MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
2005                     .pointer(FIRST_TOUCH_POINTER)
2006                     .deviceId(DEVICE_ID)
2007                     .displayId(DISPLAY_ID)
2008                     .build());
2009 
2010     // Pointer indicators should be hidden for this controller by default
2011     auto pc2 = assertPointerControllerCreated(ControllerType::TOUCH);
2012     pc->assertIsSkipScreenshotFlagSet(DISPLAY_ID);
2013     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
2014 
2015     // un-marking the privacy sensitive display should reset the state
2016     windowInfo.inputConfig.clear();
2017     mRegisteredWindowInfoListener
2018             ->onWindowInfosChanged(/*windowInfosUpdate=*/
2019                                    {{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
2020 
2021     pc->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
2022     pc->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
2023     pc2->assertIsSkipScreenshotFlagNotSet(DISPLAY_ID);
2024     pc2->assertIsSkipScreenshotFlagNotSet(ANOTHER_DISPLAY_ID);
2025 }
2026 
TEST_P(StylusTestFixture,SetsPointerIconForStylus)2027 TEST_P(StylusTestFixture, SetsPointerIconForStylus) {
2028     const auto& [name, source, controllerType] = GetParam();
2029 
2030     // Make sure there is a PointerController.
2031     mChoreographer.notifyInputDevicesChanged(
2032             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
2033     mChoreographer.setStylusPointerIconEnabled(true);
2034     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2035     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
2036                                         .pointer(STYLUS_POINTER)
2037                                         .deviceId(DEVICE_ID)
2038                                         .displayId(DISPLAY_ID)
2039                                         .build());
2040     auto pc = assertPointerControllerCreated(controllerType);
2041     pc->assertPointerIconNotSet();
2042 
2043     // Set pointer icon for the device.
2044     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
2045     pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2046 
2047     // Set pointer icon for wrong device id. This should be ignored.
2048     ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
2049                                                SECOND_DEVICE_ID));
2050     pc->assertPointerIconNotSet();
2051 
2052     // The stylus stops hovering. This should cause the icon to be reset.
2053     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, source)
2054                                         .pointer(STYLUS_POINTER)
2055                                         .deviceId(DEVICE_ID)
2056                                         .displayId(DISPLAY_ID)
2057                                         .build());
2058     pc->assertPointerIconSet(PointerIconStyle::TYPE_NOT_SPECIFIED);
2059 }
2060 
TEST_P(StylusTestFixture,SetsCustomPointerIconForStylus)2061 TEST_P(StylusTestFixture, SetsCustomPointerIconForStylus) {
2062     const auto& [name, source, controllerType] = GetParam();
2063 
2064     // Make sure there is a PointerController.
2065     mChoreographer.notifyInputDevicesChanged(
2066             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
2067     mChoreographer.setStylusPointerIconEnabled(true);
2068     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2069     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
2070                                         .pointer(STYLUS_POINTER)
2071                                         .deviceId(DEVICE_ID)
2072                                         .displayId(DISPLAY_ID)
2073                                         .build());
2074     auto pc = assertPointerControllerCreated(controllerType);
2075     pc->assertCustomPointerIconNotSet();
2076 
2077     // Set custom pointer icon for the device.
2078     ASSERT_TRUE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
2079                                                       PointerIconStyle::TYPE_CUSTOM),
2080                                               DISPLAY_ID, DEVICE_ID));
2081     pc->assertCustomPointerIconSet(PointerIconStyle::TYPE_CUSTOM);
2082 
2083     // Set custom pointer icon for wrong device id. This should be ignored.
2084     ASSERT_FALSE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
2085                                                        PointerIconStyle::TYPE_CUSTOM),
2086                                                DISPLAY_ID, SECOND_DEVICE_ID));
2087     pc->assertCustomPointerIconNotSet();
2088 }
2089 
TEST_P(StylusTestFixture,SetsPointerIconForTwoStyluses)2090 TEST_P(StylusTestFixture, SetsPointerIconForTwoStyluses) {
2091     const auto& [name, source, controllerType] = GetParam();
2092 
2093     // Make sure there are two StylusPointerControllers. They can be on a same display.
2094     mChoreographer.setStylusPointerIconEnabled(true);
2095     mChoreographer.notifyInputDevicesChanged(
2096             {/*id=*/0,
2097              {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID),
2098               generateTestDeviceInfo(SECOND_DEVICE_ID, source, DISPLAY_ID)}});
2099     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2100     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
2101                                         .pointer(STYLUS_POINTER)
2102                                         .deviceId(DEVICE_ID)
2103                                         .displayId(DISPLAY_ID)
2104                                         .build());
2105     auto firstStylusPc = assertPointerControllerCreated(controllerType);
2106     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
2107                                         .pointer(STYLUS_POINTER)
2108                                         .deviceId(SECOND_DEVICE_ID)
2109                                         .displayId(DISPLAY_ID)
2110                                         .build());
2111     auto secondStylusPc = assertPointerControllerCreated(controllerType);
2112 
2113     // Set pointer icon for one stylus.
2114     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
2115     firstStylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2116     secondStylusPc->assertPointerIconNotSet();
2117 
2118     // Set pointer icon for another stylus.
2119     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
2120                                               SECOND_DEVICE_ID));
2121     secondStylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2122     firstStylusPc->assertPointerIconNotSet();
2123 }
2124 
TEST_P(StylusTestFixture,SetsPointerIconForMouseAndStylus)2125 TEST_P(StylusTestFixture, SetsPointerIconForMouseAndStylus) {
2126     const auto& [name, source, controllerType] = GetParam();
2127 
2128     // Make sure there are PointerControllers for a mouse and a stylus.
2129     mChoreographer.setStylusPointerIconEnabled(true);
2130     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2131     mChoreographer.notifyInputDevicesChanged(
2132             {/*id=*/0,
2133              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
2134               generateTestDeviceInfo(SECOND_DEVICE_ID, source, DISPLAY_ID)}});
2135     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2136     mChoreographer.notifyMotion(
2137             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
2138                     .pointer(MOUSE_POINTER)
2139                     .deviceId(DEVICE_ID)
2140                     .displayId(ui::LogicalDisplayId::INVALID)
2141                     .build());
2142     auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
2143     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
2144                                         .pointer(STYLUS_POINTER)
2145                                         .deviceId(SECOND_DEVICE_ID)
2146                                         .displayId(DISPLAY_ID)
2147                                         .build());
2148     auto stylusPc = assertPointerControllerCreated(controllerType);
2149 
2150     // Set pointer icon for the mouse.
2151     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
2152     mousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2153     stylusPc->assertPointerIconNotSet();
2154 
2155     // Set pointer icon for the stylus.
2156     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
2157                                               SECOND_DEVICE_ID));
2158     stylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2159     mousePc->assertPointerIconNotSet();
2160 }
2161 
TEST_F(PointerChoreographerTest,SetPointerIconVisibilityHidesPointerOnDisplay)2162 TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) {
2163     // Make sure there are two PointerControllers on different displays.
2164     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
2165     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2166     mChoreographer.notifyInputDevicesChanged(
2167             {/*id=*/0,
2168              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
2169               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
2170     auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
2171     ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
2172     auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
2173     ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());
2174 
2175     // Both pointers should be visible.
2176     ASSERT_TRUE(firstMousePc->isPointerShown());
2177     ASSERT_TRUE(secondMousePc->isPointerShown());
2178 
2179     // Hide the icon on the second display.
2180     mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false);
2181     ASSERT_TRUE(firstMousePc->isPointerShown());
2182     ASSERT_FALSE(secondMousePc->isPointerShown());
2183 
2184     // Move and set pointer icons for both mice. The second pointer should still be hidden.
2185     mChoreographer.notifyMotion(
2186             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2187                     .pointer(MOUSE_POINTER)
2188                     .deviceId(DEVICE_ID)
2189                     .displayId(DISPLAY_ID)
2190                     .build());
2191     mChoreographer.notifyMotion(
2192             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2193                     .pointer(MOUSE_POINTER)
2194                     .deviceId(SECOND_DEVICE_ID)
2195                     .displayId(ANOTHER_DISPLAY_ID)
2196                     .build());
2197     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
2198     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
2199                                               SECOND_DEVICE_ID));
2200     firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2201     secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2202     ASSERT_TRUE(firstMousePc->isPointerShown());
2203     ASSERT_FALSE(secondMousePc->isPointerShown());
2204 
2205     // Allow the icon to be visible on the second display, and move the mouse.
2206     mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true);
2207     mChoreographer.notifyMotion(
2208             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2209                     .pointer(MOUSE_POINTER)
2210                     .deviceId(SECOND_DEVICE_ID)
2211                     .displayId(ANOTHER_DISPLAY_ID)
2212                     .build());
2213     ASSERT_TRUE(firstMousePc->isPointerShown());
2214     ASSERT_TRUE(secondMousePc->isPointerShown());
2215 }
2216 
TEST_F(PointerChoreographerTest,SetPointerIconVisibilityHidesPointerWhenDeviceConnected)2217 TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) {
2218     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2219     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2220 
2221     // Hide the pointer on the display, and then connect the mouse.
2222     mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
2223     mChoreographer.notifyInputDevicesChanged(
2224             {/*id=*/0,
2225              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
2226                                      ui::LogicalDisplayId::INVALID)}});
2227     auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
2228     ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId());
2229 
2230     // The pointer should not be visible.
2231     ASSERT_FALSE(mousePc->isPointerShown());
2232 }
2233 
TEST_F(PointerChoreographerTest,SetPointerIconVisibilityHidesPointerForTouchpad)2234 TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) {
2235     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2236     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2237 
2238     // Hide the pointer on the display.
2239     mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
2240 
2241     mChoreographer.notifyInputDevicesChanged(
2242             {/*id=*/0,
2243              {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
2244                                      ui::LogicalDisplayId::INVALID)}});
2245     auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE);
2246     ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId());
2247 
2248     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
2249                                                   AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)
2250                                         .pointer(TOUCHPAD_POINTER)
2251                                         .deviceId(DEVICE_ID)
2252                                         .displayId(DISPLAY_ID)
2253                                         .build());
2254 
2255     // The pointer should not be visible.
2256     ASSERT_FALSE(touchpadPc->isPointerShown());
2257 }
2258 
TEST_P(StylusTestFixture,SetPointerIconVisibilityHidesPointerForStylus)2259 TEST_P(StylusTestFixture, SetPointerIconVisibilityHidesPointerForStylus) {
2260     const auto& [name, source, controllerType] = GetParam();
2261 
2262     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2263     mChoreographer.setStylusPointerIconEnabled(true);
2264 
2265     // Hide the pointer on the display.
2266     mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
2267 
2268     mChoreographer.notifyInputDevicesChanged(
2269             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
2270     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, source)
2271                                         .pointer(STYLUS_POINTER)
2272                                         .deviceId(DEVICE_ID)
2273                                         .displayId(DISPLAY_ID)
2274                                         .build());
2275     ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
2276     auto pc = assertPointerControllerCreated(controllerType);
2277     pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
2278 
2279     // The pointer should not be visible.
2280     ASSERT_FALSE(pc->isPointerShown());
2281 }
2282 
TEST_F(PointerChoreographerTest,DrawingTabletCanReportMouseEvent)2283 TEST_F(PointerChoreographerTest, DrawingTabletCanReportMouseEvent) {
2284     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2285     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2286 
2287     mChoreographer.notifyInputDevicesChanged(
2288             {/*id=*/0,
2289              {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE,
2290                                      ui::LogicalDisplayId::INVALID)}});
2291     // There should be no controller created when a drawing tablet is connected
2292     assertPointerControllerNotCreated();
2293 
2294     // But if it ends up reporting a mouse event, then the mouse controller will be created
2295     // dynamically.
2296     mChoreographer.notifyMotion(
2297             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2298                     .pointer(MOUSE_POINTER)
2299                     .deviceId(DEVICE_ID)
2300                     .displayId(DISPLAY_ID)
2301                     .build());
2302     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2303     ASSERT_TRUE(pc->isPointerShown());
2304 
2305     // The controller is removed when the drawing tablet is removed
2306     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
2307     assertPointerControllerRemoved(pc);
2308 }
2309 
TEST_F(PointerChoreographerTest,MultipleDrawingTabletsReportMouseEvents)2310 TEST_F(PointerChoreographerTest, MultipleDrawingTabletsReportMouseEvents) {
2311     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2312     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2313 
2314     // First drawing tablet is added
2315     mChoreographer.notifyInputDevicesChanged(
2316             {/*id=*/0,
2317              {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE,
2318                                      ui::LogicalDisplayId::INVALID)}});
2319     assertPointerControllerNotCreated();
2320 
2321     mChoreographer.notifyMotion(
2322             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2323                     .pointer(MOUSE_POINTER)
2324                     .deviceId(DEVICE_ID)
2325                     .displayId(DISPLAY_ID)
2326                     .build());
2327     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2328     ASSERT_TRUE(pc->isPointerShown());
2329 
2330     // Second drawing tablet is added
2331     mChoreographer.notifyInputDevicesChanged(
2332             {/*id=*/0,
2333              {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE,
2334                                      ui::LogicalDisplayId::INVALID),
2335               generateTestDeviceInfo(SECOND_DEVICE_ID, DRAWING_TABLET_SOURCE,
2336                                      ui::LogicalDisplayId::INVALID)}});
2337     assertPointerControllerNotRemoved(pc);
2338 
2339     mChoreographer.notifyMotion(
2340             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2341                     .pointer(MOUSE_POINTER)
2342                     .deviceId(SECOND_DEVICE_ID)
2343                     .displayId(DISPLAY_ID)
2344                     .build());
2345 
2346     // First drawing tablet is removed
2347     mChoreographer.notifyInputDevicesChanged(
2348             {/*id=*/0,
2349              {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE,
2350                                      ui::LogicalDisplayId::INVALID)}});
2351     assertPointerControllerNotRemoved(pc);
2352 
2353     // Second drawing tablet is removed
2354     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
2355     assertPointerControllerRemoved(pc);
2356 }
2357 
TEST_F(PointerChoreographerTest,MouseAndDrawingTabletReportMouseEvents)2358 TEST_F(PointerChoreographerTest, MouseAndDrawingTabletReportMouseEvents) {
2359     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2360     mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
2361 
2362     // Mouse and drawing tablet connected
2363     mChoreographer.notifyInputDevicesChanged(
2364             {/*id=*/0,
2365              {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE,
2366                                      ui::LogicalDisplayId::INVALID),
2367               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE,
2368                                      ui::LogicalDisplayId::INVALID)}});
2369     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2370     ASSERT_TRUE(pc->isPointerShown());
2371 
2372     // Drawing tablet reports a mouse event
2373     mChoreographer.notifyMotion(
2374             MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, DRAWING_TABLET_SOURCE)
2375                     .pointer(MOUSE_POINTER)
2376                     .deviceId(DEVICE_ID)
2377                     .displayId(DISPLAY_ID)
2378                     .build());
2379 
2380     // Remove the mouse device
2381     mChoreographer.notifyInputDevicesChanged(
2382             {/*id=*/0,
2383              {generateTestDeviceInfo(DEVICE_ID, DRAWING_TABLET_SOURCE,
2384                                      ui::LogicalDisplayId::INVALID)}});
2385 
2386     // The mouse controller should not be removed, because the drawing tablet has produced a
2387     // mouse event, so we are treating it as a mouse too.
2388     assertPointerControllerNotRemoved(pc);
2389 
2390     mChoreographer.notifyInputDevicesChanged({/*id=*/0, {}});
2391     assertPointerControllerRemoved(pc);
2392 }
2393 
2394 using PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixtureParam =
2395         std::tuple<std::string_view /*name*/, uint32_t /*source*/>;
2396 
2397 class PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture
2398       : public PointerChoreographerTest,
2399         public testing::WithParamInterface<
2400                 PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixtureParam> {
2401 protected:
2402     const std::unordered_map<int32_t, int32_t>
2403             mMetaKeyStates{{AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON},
2404                            {AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON},
2405                            {AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON},
2406                            {AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON},
2407                            {AKEYCODE_SYM, AMETA_SYM_ON},
2408                            {AKEYCODE_FUNCTION, AMETA_FUNCTION_ON},
2409                            {AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON},
2410                            {AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON},
2411                            {AKEYCODE_META_LEFT, AMETA_META_LEFT_ON},
2412                            {AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON},
2413                            {AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON},
2414                            {AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON},
2415                            {AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON}};
2416 
notifyKey(ui::LogicalDisplayId targetDisplay,int32_t keyCode,int32_t metaState=AMETA_NONE)2417     void notifyKey(ui::LogicalDisplayId targetDisplay, int32_t keyCode,
2418                    int32_t metaState = AMETA_NONE) {
2419         if (metaState == AMETA_NONE && mMetaKeyStates.contains(keyCode)) {
2420             // For simplicity, we always set the corresponding meta state when sending a meta
2421             // keycode. This does not take into consideration when the meta state is updated in
2422             // reality.
2423             metaState = mMetaKeyStates.at(keyCode);
2424         }
2425         mChoreographer.notifyKey(KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
2426                                          .displayId(targetDisplay)
2427                                          .keyCode(keyCode)
2428                                          .metaState(metaState)
2429                                          .build());
2430         mChoreographer.notifyKey(KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
2431                                          .displayId(targetDisplay)
2432                                          .keyCode(keyCode)
2433                                          .metaState(metaState)
2434                                          .build());
2435     }
2436 
metaKeyCombinationHidesPointer(FakePointerController & pc,int32_t keyCode,int32_t metaKeyCode)2437     void metaKeyCombinationHidesPointer(FakePointerController& pc, int32_t keyCode,
2438                                         int32_t metaKeyCode) {
2439         ASSERT_TRUE(pc.isPointerShown());
2440         notifyKey(DISPLAY_ID, keyCode, mMetaKeyStates.at(metaKeyCode));
2441         ASSERT_FALSE(pc.isPointerShown());
2442 
2443         unfadePointer();
2444     }
2445 
metaKeyCombinationDoesNotHidePointer(FakePointerController & pc,int32_t keyCode,int32_t metaKeyCode)2446     void metaKeyCombinationDoesNotHidePointer(FakePointerController& pc, int32_t keyCode,
2447                                               int32_t metaKeyCode) {
2448         ASSERT_TRUE(pc.isPointerShown());
2449         notifyKey(DISPLAY_ID, keyCode, mMetaKeyStates.at(metaKeyCode));
2450         ASSERT_TRUE(pc.isPointerShown());
2451     }
2452 
unfadePointer()2453     void unfadePointer() {
2454         // unfade pointer by injecting mose hover event
2455         mChoreographer.notifyMotion(
2456                 MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
2457                         .pointer(MOUSE_POINTER)
2458                         .deviceId(DEVICE_ID)
2459                         .displayId(DISPLAY_ID)
2460                         .build());
2461     }
2462 };
2463 
2464 INSTANTIATE_TEST_SUITE_P(
2465         PointerChoreographerTest, PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,
2466         testing::Values(std::make_tuple("Mouse", AINPUT_SOURCE_MOUSE),
2467                         std::make_tuple("Touchpad", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)),
2468         [](const testing::TestParamInfo<
__anon062b71b01402(const testing::TestParamInfo< PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixtureParam>& p) 2469                 PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixtureParam>& p) {
2470             return std::string{std::get<0>(p.param)};
2471         });
2472 
TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,KeystrokesWithoutImeConnectionDoesNotHidePointerOrDisablesTouchpadTap)2473 TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,
2474        KeystrokesWithoutImeConnectionDoesNotHidePointerOrDisablesTouchpadTap) {
2475     const auto& [_, source] = GetParam();
2476     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2477 
2478     // Mouse connected
2479     mChoreographer.notifyInputDevicesChanged(
2480             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
2481     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2482     ASSERT_TRUE(pc->isPointerShown());
2483 
2484     EXPECT_CALL(mMockPolicy, notifyMouseCursorFadedOnTyping).Times(0);
2485 
2486     notifyKey(ui::LogicalDisplayId::INVALID, AKEYCODE_0);
2487     notifyKey(ui::LogicalDisplayId::INVALID, AKEYCODE_A);
2488     notifyKey(ui::LogicalDisplayId::INVALID, AKEYCODE_CTRL_LEFT);
2489 
2490     ASSERT_TRUE(pc->isPointerShown());
2491 }
2492 
TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,AlphanumericKeystrokesWithImeConnectionHidePointerAndDisablesTouchpadTap)2493 TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,
2494        AlphanumericKeystrokesWithImeConnectionHidePointerAndDisablesTouchpadTap) {
2495     const auto& [_, source] = GetParam();
2496     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2497 
2498     // Mouse connected
2499     mChoreographer.notifyInputDevicesChanged(
2500             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
2501     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2502     ASSERT_TRUE(pc->isPointerShown());
2503 
2504     EXPECT_CALL(mMockPolicy, isInputMethodConnectionActive).WillRepeatedly(testing::Return(true));
2505     EXPECT_CALL(mMockPolicy, notifyMouseCursorFadedOnTyping).Times(2);
2506 
2507     notifyKey(DISPLAY_ID, AKEYCODE_0);
2508     ASSERT_FALSE(pc->isPointerShown());
2509 
2510     unfadePointer();
2511 
2512     notifyKey(DISPLAY_ID, AKEYCODE_A);
2513     ASSERT_FALSE(pc->isPointerShown());
2514 }
2515 
TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,MetaKeystrokesDoNotHidePointerOrDisablesTouchpadTap)2516 TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,
2517        MetaKeystrokesDoNotHidePointerOrDisablesTouchpadTap) {
2518     const auto& [_, source] = GetParam();
2519     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2520 
2521     // Mouse connected
2522     mChoreographer.notifyInputDevicesChanged(
2523             {/*id=*/0, {generateTestDeviceInfo(SECOND_DEVICE_ID, source, DISPLAY_ID)}});
2524     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2525     ASSERT_TRUE(pc->isPointerShown());
2526 
2527     EXPECT_CALL(mMockPolicy, isInputMethodConnectionActive).WillRepeatedly(testing::Return(true));
2528     EXPECT_CALL(mMockPolicy, notifyMouseCursorFadedOnTyping).Times(0);
2529 
2530     const std::vector<int32_t> metaKeyCodes{AKEYCODE_ALT_LEFT,   AKEYCODE_ALT_RIGHT,
2531                                             AKEYCODE_SHIFT_LEFT, AKEYCODE_SHIFT_RIGHT,
2532                                             AKEYCODE_SYM,        AKEYCODE_FUNCTION,
2533                                             AKEYCODE_CTRL_LEFT,  AKEYCODE_CTRL_RIGHT,
2534                                             AKEYCODE_META_LEFT,  AKEYCODE_META_RIGHT,
2535                                             AKEYCODE_CAPS_LOCK,  AKEYCODE_NUM_LOCK,
2536                                             AKEYCODE_SCROLL_LOCK};
2537     for (int32_t keyCode : metaKeyCodes) {
2538         notifyKey(ui::LogicalDisplayId::INVALID, keyCode);
2539     }
2540 
2541     ASSERT_TRUE(pc->isPointerShown());
2542 }
2543 
TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,KeystrokesWithoutTargetHidePointerOnlyOnFocusedDisplayAndDisablesTouchpadTap)2544 TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,
2545        KeystrokesWithoutTargetHidePointerOnlyOnFocusedDisplayAndDisablesTouchpadTap) {
2546     const auto& [_, source] = GetParam();
2547     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
2548     mChoreographer.setFocusedDisplay(DISPLAY_ID);
2549 
2550     // Mouse connected
2551     mChoreographer.notifyInputDevicesChanged(
2552             {/*id=*/0,
2553              {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID),
2554               generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
2555     auto pc1 = assertPointerControllerCreated(ControllerType::MOUSE);
2556     auto pc2 = assertPointerControllerCreated(ControllerType::MOUSE);
2557     ASSERT_TRUE(pc1->isPointerShown());
2558     ASSERT_TRUE(pc2->isPointerShown());
2559 
2560     EXPECT_CALL(mMockPolicy, isInputMethodConnectionActive).WillRepeatedly(testing::Return(true));
2561     EXPECT_CALL(mMockPolicy, notifyMouseCursorFadedOnTyping).Times(2);
2562 
2563     notifyKey(ui::LogicalDisplayId::INVALID, AKEYCODE_0);
2564     ASSERT_FALSE(pc1->isPointerShown());
2565     ASSERT_TRUE(pc2->isPointerShown());
2566     unfadePointer();
2567 
2568     notifyKey(ui::LogicalDisplayId::INVALID, AKEYCODE_A);
2569     ASSERT_FALSE(pc1->isPointerShown());
2570     ASSERT_TRUE(pc2->isPointerShown());
2571 }
2572 
TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture,TestMetaKeyCombinations)2573 TEST_P(PointerVisibilityAndTouchpadTapStateOnKeyPressTestFixture, TestMetaKeyCombinations) {
2574     const auto& [_, source] = GetParam();
2575     mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2576 
2577     // Mouse connected
2578     mChoreographer.notifyInputDevicesChanged(
2579             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, source, DISPLAY_ID)}});
2580     auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
2581 
2582     EXPECT_CALL(mMockPolicy, isInputMethodConnectionActive).WillRepeatedly(testing::Return(true));
2583 
2584     // meta key combinations that should hide pointer and disable touchpad taps
2585     EXPECT_CALL(mMockPolicy, notifyMouseCursorFadedOnTyping).Times(5);
2586     metaKeyCombinationHidesPointer(*pc, AKEYCODE_A, AKEYCODE_SHIFT_LEFT);
2587     metaKeyCombinationHidesPointer(*pc, AKEYCODE_A, AKEYCODE_SHIFT_RIGHT);
2588     metaKeyCombinationHidesPointer(*pc, AKEYCODE_A, AKEYCODE_CAPS_LOCK);
2589     metaKeyCombinationHidesPointer(*pc, AKEYCODE_0, AKEYCODE_NUM_LOCK);
2590     metaKeyCombinationHidesPointer(*pc, AKEYCODE_A, AKEYCODE_SCROLL_LOCK);
2591 
2592     // meta key combinations that should not hide pointer
2593     EXPECT_CALL(mMockPolicy, notifyMouseCursorFadedOnTyping).Times(0);
2594     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_ALT_LEFT);
2595     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_ALT_RIGHT);
2596     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_CTRL_LEFT);
2597     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_CTRL_RIGHT);
2598     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_SYM);
2599     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_FUNCTION);
2600     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_META_LEFT);
2601     metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_META_RIGHT);
2602 }
2603 
2604 using PointerChoreographerDisplayTopologyTestFixtureParam =
2605         std::tuple<std::string_view /*name*/, int32_t /*source device*/,
2606                    ControllerType /*PointerController*/, ToolType /*pointer tool type*/,
2607                    vec2 /*source position*/, vec2 /*hover move X/Y*/,
2608                    ui::LogicalDisplayId /*destination display*/, vec2 /*destination position*/>;
2609 
2610 class PointerChoreographerDisplayTopologyTestFixture
2611       : public PointerChoreographerTest,
2612         public testing::WithParamInterface<PointerChoreographerDisplayTopologyTestFixtureParam> {
2613 public:
2614     static constexpr ui::LogicalDisplayId DISPLAY_CENTER_ID = ui::LogicalDisplayId{10};
2615     static constexpr ui::LogicalDisplayId DISPLAY_TOP_ID = ui::LogicalDisplayId{20};
2616     static constexpr ui::LogicalDisplayId DISPLAY_RIGHT_ID = ui::LogicalDisplayId{30};
2617     static constexpr ui::LogicalDisplayId DISPLAY_BOTTOM_ID = ui::LogicalDisplayId{40};
2618     static constexpr ui::LogicalDisplayId DISPLAY_LEFT_ID = ui::LogicalDisplayId{50};
2619     static constexpr ui::LogicalDisplayId DISPLAY_TOP_RIGHT_CORNER_ID = ui::LogicalDisplayId{60};
2620 
PointerChoreographerDisplayTopologyTestFixture()2621     PointerChoreographerDisplayTopologyTestFixture() {
2622         com::android::input::flags::connected_displays_cursor(true);
2623     }
2624 
2625 protected:
2626     std::vector<DisplayViewport> mViewports{
2627             createViewport(DISPLAY_CENTER_ID, /*width*/ 100, /*height*/ 100, ui::ROTATION_0),
2628             createViewport(DISPLAY_TOP_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_0),
2629             createViewport(DISPLAY_RIGHT_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_90),
2630             createViewport(DISPLAY_BOTTOM_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_180),
2631             createViewport(DISPLAY_LEFT_ID, /*width*/ 90, /*height*/ 90, ui::ROTATION_270),
2632             createViewport(DISPLAY_TOP_RIGHT_CORNER_ID, /*width*/ 90, /*height*/ 90,
2633                            ui::ROTATION_0),
2634     };
2635 
2636     std::unordered_map<ui::LogicalDisplayId, std::vector<PointerChoreographer::AdjacentDisplay>>
2637             mTopology{
2638                     {DISPLAY_CENTER_ID,
2639                      {{DISPLAY_TOP_ID, PointerChoreographer::DisplayPosition::TOP, 10.0f},
2640                       {DISPLAY_RIGHT_ID, PointerChoreographer::DisplayPosition::RIGHT, 10.0f},
2641                       {DISPLAY_BOTTOM_ID, PointerChoreographer::DisplayPosition::BOTTOM, 10.0f},
2642                       {DISPLAY_LEFT_ID, PointerChoreographer::DisplayPosition::LEFT, 10.0f},
2643                       {DISPLAY_TOP_RIGHT_CORNER_ID, PointerChoreographer::DisplayPosition::RIGHT,
2644                        -90.0f}}},
2645             };
2646 
2647 private:
createViewport(ui::LogicalDisplayId displayId,int32_t width,int32_t height,ui::Rotation orientation)2648     DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height,
2649                                    ui::Rotation orientation) {
2650         DisplayViewport viewport;
2651         viewport.displayId = displayId;
2652         viewport.logicalRight = width;
2653         viewport.logicalBottom = height;
2654         viewport.orientation = orientation;
2655         return viewport;
2656     }
2657 };
2658 
TEST_P(PointerChoreographerDisplayTopologyTestFixture,PointerChoreographerDisplayTopologyTest)2659 TEST_P(PointerChoreographerDisplayTopologyTestFixture, PointerChoreographerDisplayTopologyTest) {
2660     const auto& [_, device, pointerControllerType, pointerToolType, initialPosition, hoverMove,
2661                  destinationDisplay, destinationPosition] = GetParam();
2662 
2663     mChoreographer.setDisplayViewports(mViewports);
2664     mChoreographer.setDefaultMouseDisplayId(
2665             PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID);
2666     mChoreographer.setDisplayTopology(mTopology);
2667 
2668     mChoreographer.notifyInputDevicesChanged(
2669             {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, device, ui::LogicalDisplayId::INVALID)}});
2670 
2671     auto pc = assertPointerControllerCreated(pointerControllerType);
2672     ASSERT_EQ(PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
2673               pc->getDisplayId());
2674 
2675     // Set initial position of the PointerController.
2676     pc->setPosition(initialPosition.x, initialPosition.y);
2677     ASSERT_TRUE(pc->isPointerShown());
2678 
2679     // Make NotifyMotionArgs and notify Choreographer.
2680     auto pointerBuilder = PointerBuilder(/*id=*/0, pointerToolType)
2681                                   .axis(AMOTION_EVENT_AXIS_RELATIVE_X, hoverMove.x)
2682                                   .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, hoverMove.y);
2683 
2684     mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, device)
2685                                         .pointer(pointerBuilder)
2686                                         .deviceId(DEVICE_ID)
2687                                         .displayId(ui::LogicalDisplayId::INVALID)
2688                                         .build());
2689 
2690     // Check that the PointerController updated the position and the pointer is shown.
2691     ASSERT_TRUE(pc->isPointerShown());
2692     ASSERT_EQ(pc->getDisplayId(), destinationDisplay);
2693     auto position = pc->getPosition();
2694     ASSERT_EQ(position.x, destinationPosition.x);
2695     ASSERT_EQ(position.y, destinationPosition.y);
2696 
2697     // Check that x-y coordinates, displayId and cursor position are correctly updated.
2698     mTestListener.assertNotifyMotionWasCalled(
2699             AllOf(WithCoords(destinationPosition.x, destinationPosition.y),
2700                   WithDisplayId(destinationDisplay),
2701                   WithCursorPosition(destinationPosition.x, destinationPosition.y)));
2702 }
2703 
2704 INSTANTIATE_TEST_SUITE_P(
2705         PointerChoreographerTest, PointerChoreographerDisplayTopologyTestFixture,
2706         testing::Values(
2707                 // Note: Upon viewport transition cursor will be positioned at the boundary of the
2708                 // destination, as we drop any unconsumed delta.
2709                 std::make_tuple("UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
2710                                 ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
2711                                 vec2(25, 25) /* delta x/y */,
2712                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
2713                                 vec2(75, 75) /* destination x/y */),
2714                 std::make_tuple("TransitionToRightDisplay", AINPUT_SOURCE_MOUSE,
2715                                 ControllerType::MOUSE, ToolType::MOUSE,
2716                                 vec2(50, 50) /* initial x/y */, vec2(100, 25) /* delta x/y */,
2717                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_RIGHT_ID,
2718                                 vec2(0,
2719                                      50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
2720                 std::make_tuple(
2721                         "TransitionToLeftDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
2722                         ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
2723                         vec2(-100, 25) /* delta x/y */,
2724                         PointerChoreographerDisplayTopologyTestFixture::DISPLAY_LEFT_ID,
2725                         vec2(90, 50 + 25 - 10) /* Right edge: (width, source + delta - offset*/),
2726                 std::make_tuple("TransitionToTopDisplay",
2727                                 AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
2728                                 ToolType::FINGER, vec2(50, 50) /* initial x/y */,
2729                                 vec2(25, -100) /* delta x/y */,
2730                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID,
2731                                 vec2(50 + 25 - 10,
2732                                      90) /* Bottom edge: (source + delta - offset, height) */),
2733                 std::make_tuple("TransitionToBottomDisplay",
2734                                 AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
2735                                 ToolType::FINGER, vec2(50, 50) /* initial x/y */,
2736                                 vec2(25, 100) /* delta x/y */,
2737                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID,
2738                                 vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
2739                 std::make_tuple("NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE,
2740                                 ControllerType::MOUSE, ToolType::MOUSE,
2741                                 vec2(5, 50) /* initial x/y */, vec2(0, -100) /* Move Up */,
2742                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
2743                                 vec2(5, 0) /* Top edge */),
2744                 std::make_tuple("NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE,
2745                                 ControllerType::MOUSE, ToolType::MOUSE,
2746                                 vec2(95, 5) /* initial x/y */, vec2(100, 0) /* Move Right */,
2747                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
2748                                 vec2(99, 5) /* Top edge */),
2749                 std::make_tuple("NoTransitionAtBottomOffset",
2750                                 AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
2751                                 ToolType::FINGER, vec2(5, 95) /* initial x/y */,
2752                                 vec2(0, 100) /* Move Down */,
2753                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
2754                                 vec2(5, 99) /* Bottom edge */),
2755                 std::make_tuple("NoTransitionAtLeftOffset",
2756                                 AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
2757                                 ToolType::FINGER, vec2(5, 5) /* initial x/y */,
2758                                 vec2(-100, 0) /* Move Left */,
2759                                 PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
2760                                 vec2(0, 5) /* Left edge */),
2761                 std::make_tuple(
2762                         "TransitionAtTopRightCorner", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
2763                         ControllerType::MOUSE, ToolType::FINGER, vec2(95, 5) /* initial x/y */,
2764                         vec2(10, -10) /* Move dignally to top right corner */,
2765                         PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_RIGHT_CORNER_ID,
2766                         vec2(0, 90) /* bottom left corner */)),
__anon062b71b01502(const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) 2767         [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) {
2768             return std::string{std::get<0>(p.param)};
2769         });
2770 
2771 class PointerChoreographerWindowInfoListenerTest : public testing::Test {};
2772 
TEST_F_WITH_FLAGS(PointerChoreographerWindowInfoListenerTest,doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::input::flags,hide_pointer_indicators_for_secure_windows)))2773 TEST_F_WITH_FLAGS(
2774         PointerChoreographerWindowInfoListenerTest,
2775         doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed,
2776         REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
2777                                             hide_pointer_indicators_for_secure_windows))) {
2778     sp<android::gui::WindowInfosListener> registeredListener;
2779     sp<android::gui::WindowInfosListener> localListenerCopy;
2780     {
2781         testing::NiceMock<MockPointerChoreographerPolicyInterface> mockPolicy;
2782         EXPECT_CALL(mockPolicy, createPointerController(ControllerType::MOUSE))
2783                 .WillOnce(testing::Return(std::make_shared<FakePointerController>()));
2784         TestInputListener testListener;
2785         std::vector<gui::WindowInfo> injectedInitialWindowInfos;
2786         TestPointerChoreographer testChoreographer{testListener, mockPolicy, registeredListener,
2787                                                    injectedInitialWindowInfos};
2788         testChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
2789 
2790         // Add mouse to create controller and listener
2791         testChoreographer.notifyInputDevicesChanged(
2792                 {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, DISPLAY_ID)}});
2793 
2794         ASSERT_NE(nullptr, registeredListener) << "WindowInfosListener was not registered";
2795         localListenerCopy = registeredListener;
2796     }
2797     ASSERT_EQ(nullptr, registeredListener) << "WindowInfosListener was not unregistered";
2798 
2799     gui::WindowInfo windowInfo;
2800     windowInfo.displayId = DISPLAY_ID;
2801     windowInfo.inputConfig |= gui::WindowInfo::InputConfig::SENSITIVE_FOR_PRIVACY;
2802     gui::DisplayInfo displayInfo;
2803     displayInfo.displayId = DISPLAY_ID;
2804     localListenerCopy->onWindowInfosChanged(
2805             /*windowInfosUpdate=*/{{windowInfo}, {displayInfo}, /*vsyncId=*/0, /*timestamp=*/0});
2806 }
2807 
2808 } // namespace android
2809