xref: /aosp_15_r20/frameworks/base/libs/input/tests/PointerController_test.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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                     [&registeredListener](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                     [&registeredListener](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