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