• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 #define LOG_TAG "PointerController"
18 //#define LOG_NDEBUG 0
19 
20 #include "PointerController.h"
21 
22 #include <SkBlendMode.h>
23 #include <SkCanvas.h>
24 #include <SkColor.h>
25 #include <android-base/stringprintf.h>
26 #include <android-base/thread_annotations.h>
27 #include <ftl/enum.h>
28 
29 #include <mutex>
30 
31 #include "PointerControllerContext.h"
32 
33 #define INDENT "  "
34 #define INDENT2 "    "
35 #define INDENT3 "      "
36 
37 namespace android {
38 
39 namespace {
40 
41 const ui::Transform kIdentityTransform;
42 
43 } // namespace
44 
45 // --- PointerController::DisplayInfoListener ---
46 
onWindowInfosChanged(const gui::WindowInfosUpdate & update)47 void PointerController::DisplayInfoListener::onWindowInfosChanged(
48         const gui::WindowInfosUpdate& update) {
49     std::scoped_lock lock(mLock);
50     if (mPointerController == nullptr) return;
51 
52     // PointerController uses DisplayInfoListener's lock.
53     base::ScopedLockAssertion assumeLocked(mPointerController->getLock());
54     mPointerController->onDisplayInfosChangedLocked(update.displayInfos);
55 }
56 
onPointerControllerDestroyed()57 void PointerController::DisplayInfoListener::onPointerControllerDestroyed() {
58     std::scoped_lock lock(mLock);
59     mPointerController = nullptr;
60 }
61 
62 // --- PointerController ---
63 
create(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,const sp<SpriteController> & spriteController)64 std::shared_ptr<PointerController> PointerController::create(
65         const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
66         const sp<SpriteController>& spriteController) {
67     // using 'new' to access non-public constructor
68     std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
69             new PointerController(policy, looper, spriteController));
70 
71     /*
72      * Now we need to hook up the constructed PointerController object to its callbacks.
73      *
74      * This must be executed after the constructor but before any other methods on PointerController
75      * in order to ensure that the fully constructed object is visible on the Looper thread, since
76      * that may be a different thread than where the PointerController is initially constructed.
77      *
78      * Unfortunately, this cannot be done as part of the constructor since we need to hand out
79      * weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr.
80      */
81 
82     controller->mContext.setHandlerController(controller);
83     controller->mContext.setCallbackController(controller);
84     return controller;
85 }
86 
PointerController(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,const sp<SpriteController> & spriteController)87 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
88                                      const sp<Looper>& looper,
89                                      const sp<SpriteController>& spriteController)
90       : PointerController(
91                 policy, looper, spriteController,
92                 [](const sp<android::gui::WindowInfosListener>& listener) {
93                     SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
94                 },
__anona0ccf76c0302(const sp<android::gui::WindowInfosListener>& listener) 95                 [](const sp<android::gui::WindowInfosListener>& listener) {
96                     SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
97                 }) {}
98 
PointerController(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,const sp<SpriteController> & spriteController,WindowListenerConsumer registerListener,WindowListenerConsumer unregisterListener)99 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
100                                      const sp<Looper>& looper,
101                                      const sp<SpriteController>& spriteController,
102                                      WindowListenerConsumer registerListener,
103                                      WindowListenerConsumer unregisterListener)
104       : mContext(policy, looper, spriteController, *this),
105         mCursorController(mContext),
106         mDisplayInfoListener(new DisplayInfoListener(this)),
107         mUnregisterWindowInfosListener(std::move(unregisterListener)) {
108     std::scoped_lock lock(getLock());
109     mLocked.presentation = Presentation::SPOT;
110     registerListener(mDisplayInfoListener);
111 }
112 
~PointerController()113 PointerController::~PointerController() {
114     mDisplayInfoListener->onPointerControllerDestroyed();
115     mUnregisterWindowInfosListener(mDisplayInfoListener);
116     mContext.getPolicy()->onPointerDisplayIdChanged(ADISPLAY_ID_NONE, FloatPoint{0, 0});
117 }
118 
getLock() const119 std::mutex& PointerController::getLock() const {
120     return mDisplayInfoListener->mLock;
121 }
122 
getBounds() const123 std::optional<FloatRect> PointerController::getBounds() const {
124     return mCursorController.getBounds();
125 }
126 
move(float deltaX,float deltaY)127 void PointerController::move(float deltaX, float deltaY) {
128     const int32_t displayId = mCursorController.getDisplayId();
129     vec2 transformed;
130     {
131         std::scoped_lock lock(getLock());
132         const auto& transform = getTransformForDisplayLocked(displayId);
133         transformed = transformWithoutTranslation(transform, {deltaX, deltaY});
134     }
135     mCursorController.move(transformed.x, transformed.y);
136 }
137 
setPosition(float x,float y)138 void PointerController::setPosition(float x, float y) {
139     const int32_t displayId = mCursorController.getDisplayId();
140     vec2 transformed;
141     {
142         std::scoped_lock lock(getLock());
143         const auto& transform = getTransformForDisplayLocked(displayId);
144         transformed = transform.transform(x, y);
145     }
146     mCursorController.setPosition(transformed.x, transformed.y);
147 }
148 
getPosition() const149 FloatPoint PointerController::getPosition() const {
150     const int32_t displayId = mCursorController.getDisplayId();
151     const auto p = mCursorController.getPosition();
152     {
153         std::scoped_lock lock(getLock());
154         const auto& transform = getTransformForDisplayLocked(displayId);
155         return FloatPoint{transform.inverse().transform(p.x, p.y)};
156     }
157 }
158 
getDisplayId() const159 int32_t PointerController::getDisplayId() const {
160     return mCursorController.getDisplayId();
161 }
162 
fade(Transition transition)163 void PointerController::fade(Transition transition) {
164     std::scoped_lock lock(getLock());
165     mCursorController.fade(transition);
166 }
167 
unfade(Transition transition)168 void PointerController::unfade(Transition transition) {
169     std::scoped_lock lock(getLock());
170     mCursorController.unfade(transition);
171 }
172 
setPresentation(Presentation presentation)173 void PointerController::setPresentation(Presentation presentation) {
174     std::scoped_lock lock(getLock());
175 
176     if (mLocked.presentation == presentation) {
177         return;
178     }
179 
180     mLocked.presentation = presentation;
181 
182     if (!mCursorController.isViewportValid()) {
183         return;
184     }
185 
186     if (presentation == Presentation::POINTER || presentation == Presentation::STYLUS_HOVER) {
187         // For now, we support stylus hover using the mouse cursor implementation.
188         // TODO: Add proper support for stylus hover icons.
189         mCursorController.setStylusHoverMode(presentation == Presentation::STYLUS_HOVER);
190 
191         mCursorController.getAdditionalMouseResources();
192         clearSpotsLocked();
193     }
194 }
195 
setSpots(const PointerCoords * spotCoords,const uint32_t * spotIdToIndex,BitSet32 spotIdBits,int32_t displayId)196 void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
197                                  BitSet32 spotIdBits, int32_t displayId) {
198     std::scoped_lock lock(getLock());
199     std::array<PointerCoords, MAX_POINTERS> outSpotCoords{};
200     const ui::Transform& transform = getTransformForDisplayLocked(displayId);
201 
202     for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
203         const uint32_t index = spotIdToIndex[idBits.clearFirstMarkedBit()];
204 
205         const vec2 xy = transform.transform(spotCoords[index].getXYValue());
206         outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_X, xy.x);
207         outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_Y, xy.y);
208 
209         float pressure = spotCoords[index].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
210         outSpotCoords[index].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure);
211     }
212 
213     auto it = mLocked.spotControllers.find(displayId);
214     if (it == mLocked.spotControllers.end()) {
215         mLocked.spotControllers.try_emplace(displayId, displayId, mContext);
216     }
217     mLocked.spotControllers.at(displayId).setSpots(outSpotCoords.data(), spotIdToIndex, spotIdBits);
218 }
219 
clearSpots()220 void PointerController::clearSpots() {
221     std::scoped_lock lock(getLock());
222     clearSpotsLocked();
223 }
224 
clearSpotsLocked()225 void PointerController::clearSpotsLocked() {
226     for (auto& [displayId, spotController] : mLocked.spotControllers) {
227         spotController.clearSpots();
228     }
229 }
230 
setInactivityTimeout(InactivityTimeout inactivityTimeout)231 void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
232     mContext.setInactivityTimeout(inactivityTimeout);
233 }
234 
reloadPointerResources()235 void PointerController::reloadPointerResources() {
236     std::scoped_lock lock(getLock());
237 
238     for (auto& [displayId, spotController] : mLocked.spotControllers) {
239         spotController.reloadSpotResources();
240     }
241 
242     if (mCursorController.resourcesLoaded()) {
243         bool getAdditionalMouseResources = false;
244         if (mLocked.presentation == PointerController::Presentation::POINTER ||
245             mLocked.presentation == PointerController::Presentation::STYLUS_HOVER) {
246             getAdditionalMouseResources = true;
247         }
248         mCursorController.reloadPointerResources(getAdditionalMouseResources);
249     }
250 }
251 
setDisplayViewport(const DisplayViewport & viewport)252 void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
253     struct PointerDisplayChangeArgs {
254         int32_t displayId;
255         FloatPoint cursorPosition;
256     };
257     std::optional<PointerDisplayChangeArgs> pointerDisplayChanged;
258 
259     { // acquire lock
260         std::scoped_lock lock(getLock());
261 
262         bool getAdditionalMouseResources = false;
263         if (mLocked.presentation == PointerController::Presentation::POINTER ||
264             mLocked.presentation == PointerController::Presentation::STYLUS_HOVER) {
265             getAdditionalMouseResources = true;
266         }
267         mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources);
268         if (viewport.displayId != mLocked.pointerDisplayId) {
269             mLocked.pointerDisplayId = viewport.displayId;
270             pointerDisplayChanged = {viewport.displayId, mCursorController.getPosition()};
271         }
272     } // release lock
273 
274     if (pointerDisplayChanged) {
275         // Notify the policy without holding the pointer controller lock.
276         mContext.getPolicy()->onPointerDisplayIdChanged(pointerDisplayChanged->displayId,
277                                                         pointerDisplayChanged->cursorPosition);
278     }
279 }
280 
updatePointerIcon(PointerIconStyle iconId)281 void PointerController::updatePointerIcon(PointerIconStyle iconId) {
282     std::scoped_lock lock(getLock());
283     mCursorController.updatePointerIcon(iconId);
284 }
285 
setCustomPointerIcon(const SpriteIcon & icon)286 void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
287     std::scoped_lock lock(getLock());
288     mCursorController.setCustomPointerIcon(icon);
289 }
290 
doInactivityTimeout()291 void PointerController::doInactivityTimeout() {
292     fade(Transition::GRADUAL);
293 }
294 
onDisplayViewportsUpdated(std::vector<DisplayViewport> & viewports)295 void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports) {
296     std::unordered_set<int32_t> displayIdSet;
297     for (const DisplayViewport& viewport : viewports) {
298         displayIdSet.insert(viewport.displayId);
299     }
300 
301     std::scoped_lock lock(getLock());
302     for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
303         int32_t displayId = it->first;
304         if (!displayIdSet.count(displayId)) {
305             /*
306              * Ensures that an in-progress animation won't dereference
307              * a null pointer to TouchSpotController.
308              */
309             mContext.removeAnimationCallback(displayId);
310             it = mLocked.spotControllers.erase(it);
311         } else {
312             ++it;
313         }
314     }
315 }
316 
onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo> & displayInfo)317 void PointerController::onDisplayInfosChangedLocked(
318         const std::vector<gui::DisplayInfo>& displayInfo) {
319     mLocked.mDisplayInfos = displayInfo;
320 }
321 
getTransformForDisplayLocked(int displayId) const322 const ui::Transform& PointerController::getTransformForDisplayLocked(int displayId) const {
323     const auto& di = mLocked.mDisplayInfos;
324     auto it = std::find_if(di.begin(), di.end(), [displayId](const gui::DisplayInfo& info) {
325         return info.displayId == displayId;
326     });
327     return it != di.end() ? it->transform : kIdentityTransform;
328 }
329 
dump(std::string & dump)330 void PointerController::dump(std::string& dump) {
331     dump += INDENT "PointerController:\n";
332     std::scoped_lock lock(getLock());
333     dump += StringPrintf(INDENT2 "Presentation: %s\n",
334                          ftl::enum_string(mLocked.presentation).c_str());
335     dump += StringPrintf(INDENT2 "Pointer Display ID: %" PRIu32 "\n", mLocked.pointerDisplayId);
336     dump += StringPrintf(INDENT2 "Viewports:\n");
337     for (const auto& info : mLocked.mDisplayInfos) {
338         info.dump(dump, INDENT3);
339     }
340     dump += INDENT2 "Spot Controllers:\n";
341     for (const auto& [_, spotController] : mLocked.spotControllers) {
342         spotController.dump(dump, INDENT3);
343     }
344 }
345 
346 } // namespace android
347