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