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