1 /*
2 * Copyright (C) 2019 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 <flag_macros.h>
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <input/PointerController.h>
21 #include <input/SpriteController.h>
22
23 #include <atomic>
24 #include <thread>
25
26 #include "input/Input.h"
27 #include "mocks/MockSprite.h"
28 #include "mocks/MockSpriteController.h"
29
30 namespace android {
31
32 enum TestCursorType {
33 CURSOR_TYPE_DEFAULT = 0,
34 CURSOR_TYPE_HOVER,
35 CURSOR_TYPE_TOUCH,
36 CURSOR_TYPE_ANCHOR,
37 CURSOR_TYPE_ADDITIONAL,
38 CURSOR_TYPE_ADDITIONAL_ANIM,
39 CURSOR_TYPE_STYLUS,
40 CURSOR_TYPE_CUSTOM = -1,
41 };
42
43 static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;
44
45 using ::testing::AllOf;
46 using ::testing::Field;
47 using ::testing::NiceMock;
48 using ::testing::Return;
49 using ::testing::Test;
50
getHotSpotCoordinatesForType(int32_t type)51 std::pair<float, float> getHotSpotCoordinatesForType(int32_t type) {
52 return std::make_pair(type * 10, type * 10 + 5);
53 }
54
55 class MockPointerControllerPolicyInterface : public PointerControllerPolicyInterface {
56 public:
57 virtual void loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId displayId) override;
58 virtual void loadPointerResources(PointerResources* outResources,
59 ui::LogicalDisplayId displayId) override;
60 virtual void loadAdditionalMouseResources(
61 std::map<PointerIconStyle, SpriteIcon>* outResources,
62 std::map<PointerIconStyle, PointerAnimation>* outAnimationResources,
63 ui::LogicalDisplayId displayId) override;
64 virtual PointerIconStyle getDefaultPointerIconId() override;
65 virtual PointerIconStyle getDefaultStylusIconId() override;
66 virtual PointerIconStyle getCustomPointerIconId() override;
67
68 bool allResourcesAreLoaded();
69 bool noResourcesAreLoaded();
70
71 private:
72 void loadPointerIconForType(SpriteIcon* icon, int32_t cursorType);
73
74 bool pointerIconLoaded{false};
75 bool pointerResourcesLoaded{false};
76 bool additionalMouseResourcesLoaded{false};
77 };
78
loadPointerIcon(SpriteIcon * icon,ui::LogicalDisplayId)79 void MockPointerControllerPolicyInterface::loadPointerIcon(SpriteIcon* icon, ui::LogicalDisplayId) {
80 loadPointerIconForType(icon, CURSOR_TYPE_DEFAULT);
81 pointerIconLoaded = true;
82 }
83
loadPointerResources(PointerResources * outResources,ui::LogicalDisplayId)84 void MockPointerControllerPolicyInterface::loadPointerResources(PointerResources* outResources,
85 ui::LogicalDisplayId) {
86 loadPointerIconForType(&outResources->spotHover, CURSOR_TYPE_HOVER);
87 loadPointerIconForType(&outResources->spotTouch, CURSOR_TYPE_TOUCH);
88 loadPointerIconForType(&outResources->spotAnchor, CURSOR_TYPE_ANCHOR);
89 pointerResourcesLoaded = true;
90 }
91
loadAdditionalMouseResources(std::map<PointerIconStyle,SpriteIcon> * outResources,std::map<PointerIconStyle,PointerAnimation> * outAnimationResources,ui::LogicalDisplayId)92 void MockPointerControllerPolicyInterface::loadAdditionalMouseResources(
93 std::map<PointerIconStyle, SpriteIcon>* outResources,
94 std::map<PointerIconStyle, PointerAnimation>* outAnimationResources, ui::LogicalDisplayId) {
95 SpriteIcon icon;
96 PointerAnimation anim;
97
98 // CURSOR_TYPE_ADDITIONAL doesn't have animation resource.
99 int32_t cursorType = CURSOR_TYPE_ADDITIONAL;
100 loadPointerIconForType(&icon, cursorType);
101 (*outResources)[static_cast<PointerIconStyle>(cursorType)] = icon;
102
103 // CURSOR_TYPE_ADDITIONAL_ANIM has animation resource.
104 cursorType = CURSOR_TYPE_ADDITIONAL_ANIM;
105 loadPointerIconForType(&icon, cursorType);
106 anim.animationFrames.push_back(icon);
107 anim.durationPerFrame = 10;
108 (*outResources)[static_cast<PointerIconStyle>(cursorType)] = icon;
109 (*outAnimationResources)[static_cast<PointerIconStyle>(cursorType)] = anim;
110
111 // CURSOR_TYPE_STYLUS doesn't have animation resource.
112 cursorType = CURSOR_TYPE_STYLUS;
113 loadPointerIconForType(&icon, cursorType);
114 (*outResources)[static_cast<PointerIconStyle>(cursorType)] = icon;
115
116 additionalMouseResourcesLoaded = true;
117 }
118
getDefaultPointerIconId()119 PointerIconStyle MockPointerControllerPolicyInterface::getDefaultPointerIconId() {
120 return static_cast<PointerIconStyle>(CURSOR_TYPE_DEFAULT);
121 }
122
getDefaultStylusIconId()123 PointerIconStyle MockPointerControllerPolicyInterface::getDefaultStylusIconId() {
124 return static_cast<PointerIconStyle>(CURSOR_TYPE_STYLUS);
125 }
126
getCustomPointerIconId()127 PointerIconStyle MockPointerControllerPolicyInterface::getCustomPointerIconId() {
128 return static_cast<PointerIconStyle>(CURSOR_TYPE_CUSTOM);
129 }
130
allResourcesAreLoaded()131 bool MockPointerControllerPolicyInterface::allResourcesAreLoaded() {
132 return pointerIconLoaded && pointerResourcesLoaded && additionalMouseResourcesLoaded;
133 }
134
noResourcesAreLoaded()135 bool MockPointerControllerPolicyInterface::noResourcesAreLoaded() {
136 return !(pointerIconLoaded || pointerResourcesLoaded || additionalMouseResourcesLoaded);
137 }
138
loadPointerIconForType(SpriteIcon * icon,int32_t type)139 void MockPointerControllerPolicyInterface::loadPointerIconForType(SpriteIcon* icon, int32_t type) {
140 icon->style = static_cast<PointerIconStyle>(type);
141 std::pair<float, float> hotSpot = getHotSpotCoordinatesForType(type);
142 icon->hotSpotX = hotSpot.first;
143 icon->hotSpotY = hotSpot.second;
144 }
145
146 class TestPointerController : public PointerController {
147 public:
TestPointerController(sp<android::gui::WindowInfosListener> & registeredListener,sp<PointerControllerPolicyInterface> policy,const sp<Looper> & looper,SpriteController & spriteController)148 TestPointerController(sp<android::gui::WindowInfosListener>& registeredListener,
149 sp<PointerControllerPolicyInterface> policy, const sp<Looper>& looper,
150 SpriteController& spriteController)
151 : PointerController(
152 policy, looper, spriteController,
153 [®isteredListener](const sp<android::gui::WindowInfosListener>& listener)
154 -> std::vector<gui::DisplayInfo> {
155 // Register listener
156 registeredListener = listener;
157 return {};
158 },
__anon8638197e0202(const sp<android::gui::WindowInfosListener>& listener) 159 [®isteredListener](const sp<android::gui::WindowInfosListener>& listener) {
160 // Unregister listener
161 if (registeredListener == listener) registeredListener = nullptr;
162 }) {}
~TestPointerController()163 ~TestPointerController() override {}
164 };
165
166 class PointerControllerTest : public Test {
167 private:
168 void loopThread();
169
170 std::atomic<bool> mRunning = true;
171 class MyLooper : public Looper {
172 public:
MyLooper()173 MyLooper() : Looper(false) {}
174 ~MyLooper() = default;
175 };
176
177 protected:
178 PointerControllerTest();
179 ~PointerControllerTest();
180
181 void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT);
182
183 sp<MockSprite> mPointerSprite;
184 sp<MockPointerControllerPolicyInterface> mPolicy;
185 std::unique_ptr<MockSpriteController> mSpriteController;
186 std::shared_ptr<PointerController> mPointerController;
187 sp<android::gui::WindowInfosListener> mRegisteredListener;
188 sp<MyLooper> mLooper;
189
190 private:
191 std::thread mThread;
192 };
193
PointerControllerTest()194 PointerControllerTest::PointerControllerTest()
195 : mPointerSprite(new NiceMock<MockSprite>),
196 mLooper(new MyLooper),
197 mThread(&PointerControllerTest::loopThread, this) {
198 mSpriteController.reset(new NiceMock<MockSpriteController>(mLooper));
199 mPolicy = new MockPointerControllerPolicyInterface();
200
201 EXPECT_CALL(*mSpriteController, createSprite())
202 .WillOnce(Return(mPointerSprite));
203
204 mPointerController = std::make_unique<TestPointerController>(mRegisteredListener, mPolicy,
205 mLooper, *mSpriteController);
206 }
207
~PointerControllerTest()208 PointerControllerTest::~PointerControllerTest() {
209 mPointerController.reset();
210 mRunning.store(false, std::memory_order_relaxed);
211 mThread.join();
212 }
213
ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId)214 void PointerControllerTest::ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId) {
215 DisplayViewport viewport;
216 viewport.displayId = displayId;
217 viewport.logicalRight = 1600;
218 viewport.logicalBottom = 1200;
219 viewport.physicalRight = 800;
220 viewport.physicalBottom = 600;
221 viewport.deviceWidth = 400;
222 viewport.deviceHeight = 300;
223 mPointerController->setDisplayViewport(viewport);
224 }
225
loopThread()226 void PointerControllerTest::loopThread() {
227 Looper::setForThread(mLooper);
228
229 while (mRunning.load(std::memory_order_relaxed)) {
230 mLooper->pollOnce(100);
231 }
232 }
233
TEST_F(PointerControllerTest,useDefaultCursorTypeByDefault)234 TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) {
235 ensureDisplayViewportIsSet();
236 mPointerController->unfade(PointerController::Transition::IMMEDIATE);
237
238 std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_DEFAULT);
239 EXPECT_CALL(*mPointerSprite, setVisible(true));
240 EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
241 EXPECT_CALL(*mPointerSprite,
242 setIcon(AllOf(Field(&SpriteIcon::style,
243 static_cast<PointerIconStyle>(CURSOR_TYPE_DEFAULT)),
244 Field(&SpriteIcon::hotSpotX, hotspot.first),
245 Field(&SpriteIcon::hotSpotY, hotspot.second))));
246 mPointerController->reloadPointerResources();
247 }
248
TEST_F(PointerControllerTest,useStylusTypeForStylusHover)249 TEST_F(PointerControllerTest, useStylusTypeForStylusHover) {
250 ensureDisplayViewportIsSet();
251 mPointerController->setPresentation(PointerController::Presentation::STYLUS_HOVER);
252 mPointerController->unfade(PointerController::Transition::IMMEDIATE);
253 std::pair<float, float> hotspot = getHotSpotCoordinatesForType(CURSOR_TYPE_STYLUS);
254 EXPECT_CALL(*mPointerSprite, setVisible(true));
255 EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
256 EXPECT_CALL(*mPointerSprite,
257 setIcon(AllOf(Field(&SpriteIcon::style,
258 static_cast<PointerIconStyle>(CURSOR_TYPE_STYLUS)),
259 Field(&SpriteIcon::hotSpotX, hotspot.first),
260 Field(&SpriteIcon::hotSpotY, hotspot.second))));
261 mPointerController->reloadPointerResources();
262 }
263
TEST_F(PointerControllerTest,setPresentationBeforeDisplayViewportDoesNotLoadResources)264 TEST_F(PointerControllerTest, setPresentationBeforeDisplayViewportDoesNotLoadResources) {
265 // Setting the presentation mode before a display viewport is set will not load any resources.
266 mPointerController->setPresentation(PointerController::Presentation::POINTER);
267 ASSERT_TRUE(mPolicy->noResourcesAreLoaded());
268
269 // When the display is set, then the resources are loaded.
270 ensureDisplayViewportIsSet();
271 ASSERT_TRUE(mPolicy->allResourcesAreLoaded());
272 }
273
TEST_F(PointerControllerTest,updatePointerIconWithChoreographer)274 TEST_F(PointerControllerTest, updatePointerIconWithChoreographer) {
275 // When PointerChoreographer is enabled, the presentation mode is set before the viewport.
276 mPointerController->setPresentation(PointerController::Presentation::POINTER);
277 ensureDisplayViewportIsSet();
278 mPointerController->unfade(PointerController::Transition::IMMEDIATE);
279
280 int32_t type = CURSOR_TYPE_ADDITIONAL;
281 std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type);
282 EXPECT_CALL(*mPointerSprite, setVisible(true));
283 EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
284 EXPECT_CALL(*mPointerSprite,
285 setIcon(AllOf(Field(&SpriteIcon::style, static_cast<PointerIconStyle>(type)),
286 Field(&SpriteIcon::hotSpotX, hotspot.first),
287 Field(&SpriteIcon::hotSpotY, hotspot.second))));
288 mPointerController->updatePointerIcon(static_cast<PointerIconStyle>(type));
289 }
290
TEST_F(PointerControllerTest,setCustomPointerIcon)291 TEST_F(PointerControllerTest, setCustomPointerIcon) {
292 ensureDisplayViewportIsSet();
293 mPointerController->unfade(PointerController::Transition::IMMEDIATE);
294
295 int32_t style = CURSOR_TYPE_CUSTOM;
296 float hotSpotX = 15;
297 float hotSpotY = 20;
298
299 SpriteIcon icon;
300 icon.style = static_cast<PointerIconStyle>(style);
301 icon.hotSpotX = hotSpotX;
302 icon.hotSpotY = hotSpotY;
303
304 EXPECT_CALL(*mPointerSprite, setVisible(true));
305 EXPECT_CALL(*mPointerSprite, setAlpha(1.0f));
306 EXPECT_CALL(*mPointerSprite,
307 setIcon(AllOf(Field(&SpriteIcon::style, static_cast<PointerIconStyle>(style)),
308 Field(&SpriteIcon::hotSpotX, hotSpotX),
309 Field(&SpriteIcon::hotSpotY, hotSpotY))));
310 mPointerController->setCustomPointerIcon(icon);
311 }
312
TEST_F(PointerControllerTest,doesNotGetResourcesBeforeSettingViewport)313 TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) {
314 mPointerController->setPresentation(PointerController::Presentation::POINTER);
315 mPointerController->setPosition(1.0f, 1.0f);
316 mPointerController->move(1.0f, 1.0f);
317 mPointerController->unfade(PointerController::Transition::IMMEDIATE);
318 mPointerController->fade(PointerController::Transition::IMMEDIATE);
319
320 EXPECT_TRUE(mPolicy->noResourcesAreLoaded());
321
322 ensureDisplayViewportIsSet();
323 }
324
TEST_F(PointerControllerTest,updatesSkipScreenshotFlagForTouchSpots)325 TEST_F(PointerControllerTest, updatesSkipScreenshotFlagForTouchSpots) {
326 ensureDisplayViewportIsSet();
327
328 PointerCoords testSpotCoords;
329 testSpotCoords.clear();
330 testSpotCoords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
331 testSpotCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
332 BitSet32 testIdBits;
333 testIdBits.markBit(0);
334 std::array<uint32_t, MAX_POINTER_ID + 1> testIdToIndex;
335
336 sp<MockSprite> testSpotSprite(new NiceMock<MockSprite>);
337
338 // By default sprite is not marked secure
339 EXPECT_CALL(*mSpriteController, createSprite).WillOnce(Return(testSpotSprite));
340 EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
341
342 // Update spots to sync state with sprite
343 mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
344 ui::LogicalDisplayId::DEFAULT);
345 testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
346
347 // Marking the display to skip screenshot should update sprite as well
348 mPointerController->setSkipScreenshotFlagForDisplay(ui::LogicalDisplayId::DEFAULT);
349 EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(true));
350
351 // Update spots to sync state with sprite
352 mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
353 ui::LogicalDisplayId::DEFAULT);
354 testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
355
356 // Reset flag and verify again
357 mPointerController->clearSkipScreenshotFlags();
358 EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false));
359 mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits,
360 ui::LogicalDisplayId::DEFAULT);
361 testing::Mock::VerifyAndClearExpectations(testSpotSprite.get());
362 }
363
364 class PointerControllerSkipScreenshotFlagTest
365 : public PointerControllerTest,
366 public testing::WithParamInterface<PointerControllerInterface::ControllerType> {};
367
TEST_P(PointerControllerSkipScreenshotFlagTest,updatesSkipScreenshotFlag)368 TEST_P(PointerControllerSkipScreenshotFlagTest, updatesSkipScreenshotFlag) {
369 sp<MockSprite> testPointerSprite(new NiceMock<MockSprite>);
370 EXPECT_CALL(*mSpriteController, createSprite).WillOnce(Return(testPointerSprite));
371
372 // Create a pointer controller
373 mPointerController =
374 PointerController::create(mPolicy, mLooper, *mSpriteController, GetParam());
375 ensureDisplayViewportIsSet(ui::LogicalDisplayId::DEFAULT);
376
377 // By default skip screenshot flag is not set for the sprite
378 EXPECT_CALL(*testPointerSprite, setSkipScreenshot).With(testing::Args<0>(false));
379
380 // Update pointer to sync state with sprite
381 mPointerController->setPosition(100, 100);
382 testing::Mock::VerifyAndClearExpectations(testPointerSprite.get());
383
384 // Marking the controller to skip screenshot should update pointer sprite
385 mPointerController->setSkipScreenshotFlagForDisplay(ui::LogicalDisplayId::DEFAULT);
386 EXPECT_CALL(*testPointerSprite, setSkipScreenshot).With(testing::Args<0>(true));
387
388 // Update pointer to sync state with sprite
389 mPointerController->move(10, 10);
390 testing::Mock::VerifyAndClearExpectations(testPointerSprite.get());
391
392 // Reset flag and verify again
393 mPointerController->clearSkipScreenshotFlags();
394 EXPECT_CALL(*testPointerSprite, setSkipScreenshot).With(testing::Args<0>(false));
395 mPointerController->move(10, 10);
396 testing::Mock::VerifyAndClearExpectations(testPointerSprite.get());
397 }
398
399 INSTANTIATE_TEST_SUITE_P(PointerControllerSkipScreenshotFlagTest,
400 PointerControllerSkipScreenshotFlagTest,
401 testing::Values(PointerControllerInterface::ControllerType::MOUSE,
402 PointerControllerInterface::ControllerType::STYLUS));
403
404 class MousePointerControllerTest : public PointerControllerTest {
405 protected:
MousePointerControllerTest()406 MousePointerControllerTest() {
407 sp<MockSprite> testPointerSprite(new NiceMock<MockSprite>);
408 EXPECT_CALL(*mSpriteController, createSprite).WillOnce(Return(testPointerSprite));
409
410 // create a mouse pointer controller
411 mPointerController =
412 PointerController::create(mPolicy, mLooper, *mSpriteController,
413 PointerControllerInterface::ControllerType::MOUSE);
414
415 // set display viewport
416 DisplayViewport viewport;
417 viewport.displayId = ui::LogicalDisplayId::DEFAULT;
418 viewport.logicalRight = 5;
419 viewport.logicalBottom = 5;
420 viewport.physicalRight = 5;
421 viewport.physicalBottom = 5;
422 viewport.deviceWidth = 5;
423 viewport.deviceHeight = 5;
424 mPointerController->setDisplayViewport(viewport);
425 }
426 };
427
428 struct MousePointerControllerTestParam {
429 vec2 startPosition;
430 vec2 delta;
431 vec2 endPosition;
432 vec2 unconsumedDelta;
433 };
434
435 class PointerControllerViewportTransitionTest
436 : public MousePointerControllerTest,
437 public testing::WithParamInterface<MousePointerControllerTestParam> {};
438
TEST_P(PointerControllerViewportTransitionTest,testPointerViewportTransition)439 TEST_P(PointerControllerViewportTransitionTest, testPointerViewportTransition) {
440 const auto& params = GetParam();
441
442 mPointerController->setPosition(params.startPosition.x, params.startPosition.y);
443 auto unconsumedDelta = mPointerController->move(params.delta.x, params.delta.y);
444
445 auto position = mPointerController->getPosition();
446 EXPECT_NEAR(position.x, params.endPosition.x, EPSILON);
447 EXPECT_NEAR(position.y, params.endPosition.y, EPSILON);
448 EXPECT_NEAR(unconsumedDelta.x, params.unconsumedDelta.x, EPSILON);
449 EXPECT_NEAR(unconsumedDelta.y, params.unconsumedDelta.y, EPSILON);
450 }
451
452 INSTANTIATE_TEST_SUITE_P(PointerControllerViewportTransitionTest,
453 PointerControllerViewportTransitionTest,
454 testing::Values(
455 // no transition
456 MousePointerControllerTestParam{{2.0f, 2.0f},
457 {2.0f, 2.0f},
458 {4.0f, 4.0f},
459 {0.0f, 0.0f}},
460 // right boundary
461 MousePointerControllerTestParam{{2.0f, 2.0f},
462 {3.0f, 0.0f},
463 {4.0f, 2.0f},
464 {1.0f, 0.0f}},
465 MousePointerControllerTestParam{{2.0f, 2.0f},
466 {3.0f, -1.0f},
467 {4.0f, 1.0f},
468 {1.0f, 0.0f}},
469 MousePointerControllerTestParam{{2.0f, 2.0f},
470 {3.0f, 1.0f},
471 {4.0f, 3.0f},
472 {1.0f, 0.0f}},
473 // left boundary
474 MousePointerControllerTestParam{{2.0f, 2.0f},
475 {-3.0f, 0.0f},
476 {0.0f, 2.0f},
477 {-1.0f, 0.0f}},
478 MousePointerControllerTestParam{{2.0f, 2.0f},
479 {-3.0f, -1.0f},
480 {0.0f, 1.0f},
481 {-1.0f, 0.0f}},
482 MousePointerControllerTestParam{{2.0f, 2.0f},
483 {-3.0f, 1.0f},
484 {0.0f, 3.0f},
485 {-1.0f, 0.0f}},
486 // bottom boundary
487 MousePointerControllerTestParam{{2.0f, 2.0f},
488 {0.0f, 3.0f},
489 {2.0f, 4.0f},
490 {0.0f, 1.0f}},
491 MousePointerControllerTestParam{{2.0f, 2.0f},
492 {-1.0f, 3.0f},
493 {1.0f, 4.0f},
494 {0.0f, 1.0f}},
495 MousePointerControllerTestParam{{2.0f, 2.0f},
496 {1.0f, 3.0f},
497 {3.0f, 4.0f},
498 {0.0f, 1.0f}},
499 // top boundary
500 MousePointerControllerTestParam{{2.0f, 2.0f},
501 {0.0f, -3.0f},
502 {2.0f, 0.0f},
503 {0.0f, -1.0f}},
504 MousePointerControllerTestParam{{2.0f, 2.0f},
505 {-1.0f, -3.0f},
506 {1.0f, 0.0f},
507 {0.0f, -1.0f}},
508 MousePointerControllerTestParam{{2.0f, 2.0f},
509 {1.0f, -3.0f},
510 {3.0f, 0.0f},
511 {0.0f, -1.0f}},
512 // top-left corner
513 MousePointerControllerTestParam{{2.0f, 2.0f},
514 {-3.0f, -3.0f},
515 {0.0f, 0.0f},
516 {-1.0f, -1.0f}},
517 // top-right corner
518 MousePointerControllerTestParam{{2.0f, 2.0f},
519 {3.0f, -3.0f},
520 {4.0f, 0.0f},
521 {1.0f, -1.0f}},
522 // bottom-right corner
523 MousePointerControllerTestParam{{2.0f, 2.0f},
524 {3.0f, 3.0f},
525 {4.0f, 4.0f},
526 {1.0f, 1.0f}},
527 // bottom-left corner
528 MousePointerControllerTestParam{{2.0f, 2.0f},
529 {-3.0f, 3.0f},
530 {0.0f, 4.0f},
531 {-1.0f, 1.0f}}));
532
533 class PointerControllerWindowInfoListenerTest : public Test {};
534
TEST_F(PointerControllerWindowInfoListenerTest,doesNotCrashIfListenerCalledAfterPointerControllerDestroyed)535 TEST_F(PointerControllerWindowInfoListenerTest,
536 doesNotCrashIfListenerCalledAfterPointerControllerDestroyed) {
537 sp<Looper> looper = new Looper(false);
538 auto spriteController = NiceMock<MockSpriteController>(looper);
539 sp<android::gui::WindowInfosListener> registeredListener;
540 sp<android::gui::WindowInfosListener> localListenerCopy;
541 sp<MockPointerControllerPolicyInterface> policy = new MockPointerControllerPolicyInterface();
542 {
543 TestPointerController pointerController(registeredListener, policy, looper,
544 spriteController);
545 ASSERT_NE(nullptr, registeredListener) << "WindowInfosListener was not registered";
546 localListenerCopy = registeredListener;
547 }
548 EXPECT_EQ(nullptr, registeredListener) << "WindowInfosListener was not unregistered";
549 localListenerCopy->onWindowInfosChanged({{}, {}, 0, 0});
550 }
551
552 } // namespace android
553