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 // Log debug messages about pointer updates
21 #define DEBUG_POINTER_UPDATES 0
22 
23 #include "PointerController.h"
24 
25 #include <log/log.h>
26 
27 #include <memory>
28 
29 namespace android {
30 
31 // --- PointerController ---
32 
33 // Time to wait before starting the fade when the pointer is inactive.
34 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
35 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
36 
37 // Time to spend fading out the spot completely.
38 static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
39 
40 // Time to spend fading out the pointer completely.
41 static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
42 
43 // The number of events to be read at once for DisplayEventReceiver.
44 static const int EVENT_BUFFER_SIZE = 100;
45 
create(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,const sp<SpriteController> & spriteController)46 std::shared_ptr<PointerController> PointerController::create(
47         const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
48         const sp<SpriteController>& spriteController) {
49     std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>(
50             new PointerController(policy, looper, spriteController));
51 
52     /*
53      * Now we need to hook up the constructed PointerController object to its callbacks.
54      *
55      * This must be executed after the constructor but before any other methods on PointerController
56      * in order to ensure that the fully constructed object is visible on the Looper thread, since
57      * that may be a different thread than where the PointerController is initially constructed.
58      *
59      * Unfortunately, this cannot be done as part of the constructor since we need to hand out
60      * weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr.
61      */
62 
63     controller->mHandler->pointerController = controller;
64     controller->mCallback->pointerController = controller;
65     if (controller->mDisplayEventReceiver.initCheck() == NO_ERROR) {
66         controller->mLooper->addFd(controller->mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
67                                    Looper::EVENT_INPUT, controller->mCallback, nullptr);
68     } else {
69         ALOGE("Failed to initialize DisplayEventReceiver.");
70     }
71     return controller;
72 }
73 
PointerController(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,const sp<SpriteController> & spriteController)74 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
75                                      const sp<Looper>& looper,
76                                      const sp<SpriteController>& spriteController)
77       : mPolicy(policy),
78         mLooper(looper),
79         mSpriteController(spriteController),
80         mHandler(new MessageHandler()),
81         mCallback(new LooperCallback()) {
82     AutoMutex _l(mLock);
83 
84     mLocked.animationPending = false;
85 
86     mLocked.presentation = Presentation::POINTER;
87     mLocked.presentationChanged = false;
88 
89     mLocked.inactivityTimeout = InactivityTimeout::NORMAL;
90 
91     mLocked.pointerFadeDirection = 0;
92     mLocked.pointerX = 0;
93     mLocked.pointerY = 0;
94     mLocked.pointerAlpha = 0.0f; // pointer is initially faded
95     mLocked.pointerSprite = mSpriteController->createSprite();
96     mLocked.pointerIconChanged = false;
97     mLocked.requestedPointerType = mPolicy->getDefaultPointerIconId();
98 
99     mLocked.animationFrameIndex = 0;
100     mLocked.lastFrameUpdatedTime = 0;
101 
102     mLocked.buttonState = 0;
103 }
104 
~PointerController()105 PointerController::~PointerController() {
106     mLooper->removeMessages(mHandler);
107 
108     AutoMutex _l(mLock);
109 
110     mLocked.pointerSprite.clear();
111 
112     for (auto& it : mLocked.spotsByDisplay) {
113         const std::vector<Spot*>& spots = it.second;
114         size_t numSpots = spots.size();
115         for (size_t i = 0; i < numSpots; i++) {
116             delete spots[i];
117         }
118     }
119     mLocked.spotsByDisplay.clear();
120     mLocked.recycledSprites.clear();
121 }
122 
getBounds(float * outMinX,float * outMinY,float * outMaxX,float * outMaxY) const123 bool PointerController::getBounds(float* outMinX, float* outMinY,
124         float* outMaxX, float* outMaxY) const {
125     AutoMutex _l(mLock);
126 
127     return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
128 }
129 
getBoundsLocked(float * outMinX,float * outMinY,float * outMaxX,float * outMaxY) const130 bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
131         float* outMaxX, float* outMaxY) const {
132 
133     if (!mLocked.viewport.isValid()) {
134         return false;
135     }
136 
137     *outMinX = mLocked.viewport.logicalLeft;
138     *outMinY = mLocked.viewport.logicalTop;
139     *outMaxX = mLocked.viewport.logicalRight - 1;
140     *outMaxY = mLocked.viewport.logicalBottom - 1;
141     return true;
142 }
143 
move(float deltaX,float deltaY)144 void PointerController::move(float deltaX, float deltaY) {
145 #if DEBUG_POINTER_UPDATES
146     ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
147 #endif
148     if (deltaX == 0.0f && deltaY == 0.0f) {
149         return;
150     }
151 
152     AutoMutex _l(mLock);
153 
154     setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
155 }
156 
setButtonState(int32_t buttonState)157 void PointerController::setButtonState(int32_t buttonState) {
158 #if DEBUG_POINTER_UPDATES
159     ALOGD("Set button state 0x%08x", buttonState);
160 #endif
161     AutoMutex _l(mLock);
162 
163     if (mLocked.buttonState != buttonState) {
164         mLocked.buttonState = buttonState;
165     }
166 }
167 
getButtonState() const168 int32_t PointerController::getButtonState() const {
169     AutoMutex _l(mLock);
170 
171     return mLocked.buttonState;
172 }
173 
setPosition(float x,float y)174 void PointerController::setPosition(float x, float y) {
175 #if DEBUG_POINTER_UPDATES
176     ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
177 #endif
178     AutoMutex _l(mLock);
179 
180     setPositionLocked(x, y);
181 }
182 
setPositionLocked(float x,float y)183 void PointerController::setPositionLocked(float x, float y) {
184     float minX, minY, maxX, maxY;
185     if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
186         if (x <= minX) {
187             mLocked.pointerX = minX;
188         } else if (x >= maxX) {
189             mLocked.pointerX = maxX;
190         } else {
191             mLocked.pointerX = x;
192         }
193         if (y <= minY) {
194             mLocked.pointerY = minY;
195         } else if (y >= maxY) {
196             mLocked.pointerY = maxY;
197         } else {
198             mLocked.pointerY = y;
199         }
200         updatePointerLocked();
201     }
202 }
203 
getPosition(float * outX,float * outY) const204 void PointerController::getPosition(float* outX, float* outY) const {
205     AutoMutex _l(mLock);
206 
207     *outX = mLocked.pointerX;
208     *outY = mLocked.pointerY;
209 }
210 
getDisplayId() const211 int32_t PointerController::getDisplayId() const {
212     AutoMutex _l(mLock);
213 
214     return mLocked.viewport.displayId;
215 }
216 
fade(Transition transition)217 void PointerController::fade(Transition transition) {
218     AutoMutex _l(mLock);
219 
220     // Remove the inactivity timeout, since we are fading now.
221     removeInactivityTimeoutLocked();
222 
223     // Start fading.
224     if (transition == Transition::IMMEDIATE) {
225         mLocked.pointerFadeDirection = 0;
226         mLocked.pointerAlpha = 0.0f;
227         updatePointerLocked();
228     } else {
229         mLocked.pointerFadeDirection = -1;
230         startAnimationLocked();
231     }
232 }
233 
unfade(Transition transition)234 void PointerController::unfade(Transition transition) {
235     AutoMutex _l(mLock);
236 
237     // Always reset the inactivity timer.
238     resetInactivityTimeoutLocked();
239 
240     // Start unfading.
241     if (transition == Transition::IMMEDIATE) {
242         mLocked.pointerFadeDirection = 0;
243         mLocked.pointerAlpha = 1.0f;
244         updatePointerLocked();
245     } else {
246         mLocked.pointerFadeDirection = 1;
247         startAnimationLocked();
248     }
249 }
250 
setPresentation(Presentation presentation)251 void PointerController::setPresentation(Presentation presentation) {
252     AutoMutex _l(mLock);
253 
254     if (mLocked.presentation == presentation) {
255         return;
256     }
257 
258     mLocked.presentation = presentation;
259     mLocked.presentationChanged = true;
260 
261     if (!mLocked.viewport.isValid()) {
262         return;
263     }
264 
265     if (presentation == Presentation::POINTER) {
266         if (mLocked.additionalMouseResources.empty()) {
267             mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
268                                                   &mLocked.animationResources,
269                                                   mLocked.viewport.displayId);
270         }
271         fadeOutAndReleaseAllSpotsLocked();
272         updatePointerLocked();
273     }
274 }
275 
setSpots(const PointerCoords * spotCoords,const uint32_t * spotIdToIndex,BitSet32 spotIdBits,int32_t displayId)276 void PointerController::setSpots(const PointerCoords* spotCoords,
277         const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId) {
278 #if DEBUG_POINTER_UPDATES
279     ALOGD("setSpots: idBits=%08x", spotIdBits.value);
280     for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
281         uint32_t id = idBits.firstMarkedBit();
282         idBits.clearBit(id);
283         const PointerCoords& c = spotCoords[spotIdToIndex[id]];
284         ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
285                 c.getAxisValue(AMOTION_EVENT_AXIS_X),
286                 c.getAxisValue(AMOTION_EVENT_AXIS_Y),
287                 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
288                 displayId);
289     }
290 #endif
291 
292     AutoMutex _l(mLock);
293     if (!mLocked.viewport.isValid()) {
294         return;
295     }
296 
297     std::vector<Spot*> newSpots;
298     std::map<int32_t, std::vector<Spot*>>::const_iterator iter =
299             mLocked.spotsByDisplay.find(displayId);
300     if (iter != mLocked.spotsByDisplay.end()) {
301         newSpots = iter->second;
302     }
303 
304     mSpriteController->openTransaction();
305 
306     // Add or move spots for fingers that are down.
307     for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
308         uint32_t id = idBits.clearFirstMarkedBit();
309         const PointerCoords& c = spotCoords[spotIdToIndex[id]];
310         const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
311                 ? mResources.spotTouch : mResources.spotHover;
312         float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
313         float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
314 
315         Spot* spot = getSpot(id, newSpots);
316         if (!spot) {
317             spot = createAndAddSpotLocked(id, newSpots);
318         }
319 
320         spot->updateSprite(&icon, x, y, displayId);
321     }
322 
323     // Remove spots for fingers that went up.
324     for (size_t i = 0; i < newSpots.size(); i++) {
325         Spot* spot = newSpots[i];
326         if (spot->id != Spot::INVALID_ID
327                 && !spotIdBits.hasBit(spot->id)) {
328             fadeOutAndReleaseSpotLocked(spot);
329         }
330     }
331 
332     mSpriteController->closeTransaction();
333     mLocked.spotsByDisplay[displayId] = newSpots;
334 }
335 
clearSpots()336 void PointerController::clearSpots() {
337 #if DEBUG_POINTER_UPDATES
338     ALOGD("clearSpots");
339 #endif
340 
341     AutoMutex _l(mLock);
342     if (!mLocked.viewport.isValid()) {
343         return;
344     }
345 
346     fadeOutAndReleaseAllSpotsLocked();
347 }
348 
setInactivityTimeout(InactivityTimeout inactivityTimeout)349 void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
350     AutoMutex _l(mLock);
351 
352     if (mLocked.inactivityTimeout != inactivityTimeout) {
353         mLocked.inactivityTimeout = inactivityTimeout;
354         resetInactivityTimeoutLocked();
355     }
356 }
357 
reloadPointerResources()358 void PointerController::reloadPointerResources() {
359     AutoMutex _l(mLock);
360 
361     loadResourcesLocked();
362     updatePointerLocked();
363 }
364 
365 /**
366  * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation,
367  * so here we are getting the dimensions in the original, unrotated orientation (orientation 0).
368  */
getNonRotatedSize(const DisplayViewport & viewport,int32_t & width,int32_t & height)369 static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) {
370     width = viewport.deviceWidth;
371     height = viewport.deviceHeight;
372 
373     if (viewport.orientation == DISPLAY_ORIENTATION_90
374             || viewport.orientation == DISPLAY_ORIENTATION_270) {
375         std::swap(width, height);
376     }
377 }
378 
setDisplayViewport(const DisplayViewport & viewport)379 void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
380     AutoMutex _l(mLock);
381     if (viewport == mLocked.viewport) {
382         return;
383     }
384 
385     const DisplayViewport oldViewport = mLocked.viewport;
386     mLocked.viewport = viewport;
387 
388     int32_t oldDisplayWidth, oldDisplayHeight;
389     getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight);
390     int32_t newDisplayWidth, newDisplayHeight;
391     getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight);
392 
393     // Reset cursor position to center if size or display changed.
394     if (oldViewport.displayId != viewport.displayId
395             || oldDisplayWidth != newDisplayWidth
396             || oldDisplayHeight != newDisplayHeight) {
397 
398         float minX, minY, maxX, maxY;
399         if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
400             mLocked.pointerX = (minX + maxX) * 0.5f;
401             mLocked.pointerY = (minY + maxY) * 0.5f;
402             // Reload icon resources for density may be changed.
403             loadResourcesLocked();
404         } else {
405             mLocked.pointerX = 0;
406             mLocked.pointerY = 0;
407         }
408 
409         fadeOutAndReleaseAllSpotsLocked();
410     } else if (oldViewport.orientation != viewport.orientation) {
411         // Apply offsets to convert from the pixel top-left corner position to the pixel center.
412         // This creates an invariant frame of reference that we can easily rotate when
413         // taking into account that the pointer may be located at fractional pixel offsets.
414         float x = mLocked.pointerX + 0.5f;
415         float y = mLocked.pointerY + 0.5f;
416         float temp;
417 
418         // Undo the previous rotation.
419         switch (oldViewport.orientation) {
420         case DISPLAY_ORIENTATION_90:
421             temp = x;
422             x =  oldViewport.deviceHeight - y;
423             y = temp;
424             break;
425         case DISPLAY_ORIENTATION_180:
426             x = oldViewport.deviceWidth - x;
427             y = oldViewport.deviceHeight - y;
428             break;
429         case DISPLAY_ORIENTATION_270:
430             temp = x;
431             x = y;
432             y = oldViewport.deviceWidth - temp;
433             break;
434         }
435 
436         // Perform the new rotation.
437         switch (viewport.orientation) {
438         case DISPLAY_ORIENTATION_90:
439             temp = x;
440             x = y;
441             y = viewport.deviceHeight - temp;
442             break;
443         case DISPLAY_ORIENTATION_180:
444             x = viewport.deviceWidth - x;
445             y = viewport.deviceHeight - y;
446             break;
447         case DISPLAY_ORIENTATION_270:
448             temp = x;
449             x = viewport.deviceWidth - y;
450             y = temp;
451             break;
452         }
453 
454         // Apply offsets to convert from the pixel center to the pixel top-left corner position
455         // and save the results.
456         mLocked.pointerX = x - 0.5f;
457         mLocked.pointerY = y - 0.5f;
458     }
459 
460     updatePointerLocked();
461 }
462 
updatePointerIcon(int32_t iconId)463 void PointerController::updatePointerIcon(int32_t iconId) {
464     AutoMutex _l(mLock);
465     if (mLocked.requestedPointerType != iconId) {
466         mLocked.requestedPointerType = iconId;
467         mLocked.presentationChanged = true;
468         updatePointerLocked();
469     }
470 }
471 
setCustomPointerIcon(const SpriteIcon & icon)472 void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
473     AutoMutex _l(mLock);
474 
475     const int32_t iconId = mPolicy->getCustomPointerIconId();
476     mLocked.additionalMouseResources[iconId] = icon;
477     mLocked.requestedPointerType = iconId;
478     mLocked.presentationChanged = true;
479 
480     updatePointerLocked();
481 }
482 
handleMessage(const Message & message)483 void PointerController::MessageHandler::handleMessage(const Message& message) {
484     std::shared_ptr<PointerController> controller = pointerController.lock();
485 
486     if (controller == nullptr) {
487         ALOGE("PointerController instance was released before processing message: what=%d",
488               message.what);
489         return;
490     }
491     switch (message.what) {
492     case MSG_INACTIVITY_TIMEOUT:
493         controller->doInactivityTimeout();
494         break;
495     }
496 }
497 
handleEvent(int,int events,void *)498 int PointerController::LooperCallback::handleEvent(int /* fd */, int events, void* /* data */) {
499     std::shared_ptr<PointerController> controller = pointerController.lock();
500     if (controller == nullptr) {
501         ALOGW("PointerController instance was released with pending callbacks.  events=0x%x",
502               events);
503         return 0; // Remove the callback, the PointerController is gone anyways
504     }
505     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
506         ALOGE("Display event receiver pipe was closed or an error occurred.  events=0x%x", events);
507         return 0; // remove the callback
508     }
509 
510     if (!(events & Looper::EVENT_INPUT)) {
511         ALOGW("Received spurious callback for unhandled poll event.  events=0x%x", events);
512         return 1; // keep the callback
513     }
514 
515     bool gotVsync = false;
516     ssize_t n;
517     nsecs_t timestamp;
518     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
519     while ((n = controller->mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
520         for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
521             if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
522                 timestamp = buf[i].header.timestamp;
523                 gotVsync = true;
524             }
525         }
526     }
527     if (gotVsync) {
528         controller->doAnimate(timestamp);
529     }
530     return 1;  // keep the callback
531 }
532 
doAnimate(nsecs_t timestamp)533 void PointerController::doAnimate(nsecs_t timestamp) {
534     AutoMutex _l(mLock);
535 
536     mLocked.animationPending = false;
537 
538     bool keepFading = doFadingAnimationLocked(timestamp);
539     bool keepBitmapFlipping = doBitmapAnimationLocked(timestamp);
540     if (keepFading || keepBitmapFlipping) {
541         startAnimationLocked();
542     }
543 }
544 
doFadingAnimationLocked(nsecs_t timestamp)545 bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) {
546     bool keepAnimating = false;
547     nsecs_t frameDelay = timestamp - mLocked.animationTime;
548 
549     // Animate pointer fade.
550     if (mLocked.pointerFadeDirection < 0) {
551         mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
552         if (mLocked.pointerAlpha <= 0.0f) {
553             mLocked.pointerAlpha = 0.0f;
554             mLocked.pointerFadeDirection = 0;
555         } else {
556             keepAnimating = true;
557         }
558         updatePointerLocked();
559     } else if (mLocked.pointerFadeDirection > 0) {
560         mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
561         if (mLocked.pointerAlpha >= 1.0f) {
562             mLocked.pointerAlpha = 1.0f;
563             mLocked.pointerFadeDirection = 0;
564         } else {
565             keepAnimating = true;
566         }
567         updatePointerLocked();
568     }
569 
570     // Animate spots that are fading out and being removed.
571     for(auto it = mLocked.spotsByDisplay.begin(); it != mLocked.spotsByDisplay.end();) {
572         std::vector<Spot*>& spots = it->second;
573         size_t numSpots = spots.size();
574         for (size_t i = 0; i < numSpots;) {
575             Spot* spot = spots[i];
576             if (spot->id == Spot::INVALID_ID) {
577                 spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
578                 if (spot->alpha <= 0) {
579                     spots.erase(spots.begin() + i);
580                     releaseSpotLocked(spot);
581                     numSpots--;
582                     continue;
583                 } else {
584                     spot->sprite->setAlpha(spot->alpha);
585                     keepAnimating = true;
586                 }
587             }
588             ++i;
589         }
590 
591         if (spots.size() == 0) {
592             it = mLocked.spotsByDisplay.erase(it);
593         } else {
594             ++it;
595         }
596     }
597 
598     return keepAnimating;
599 }
600 
doBitmapAnimationLocked(nsecs_t timestamp)601 bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) {
602     std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find(
603             mLocked.requestedPointerType);
604     if (iter == mLocked.animationResources.end()) {
605         return false;
606     }
607 
608     if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
609         mSpriteController->openTransaction();
610 
611         int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
612         mLocked.animationFrameIndex += incr;
613         mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr;
614         while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) {
615             mLocked.animationFrameIndex -= iter->second.animationFrames.size();
616         }
617         mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);
618 
619         mSpriteController->closeTransaction();
620     }
621 
622     // Keep animating.
623     return true;
624 }
625 
doInactivityTimeout()626 void PointerController::doInactivityTimeout() {
627     fade(Transition::GRADUAL);
628 }
629 
startAnimationLocked()630 void PointerController::startAnimationLocked() {
631     if (!mLocked.animationPending) {
632         mLocked.animationPending = true;
633         mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
634         mDisplayEventReceiver.requestNextVsync();
635     }
636 }
637 
resetInactivityTimeoutLocked()638 void PointerController::resetInactivityTimeoutLocked() {
639     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
640 
641     nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT
642             ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT
643             : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
644     mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
645 }
646 
removeInactivityTimeoutLocked()647 void PointerController::removeInactivityTimeoutLocked() {
648     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
649 }
650 
updatePointerLocked()651 void PointerController::updatePointerLocked() REQUIRES(mLock) {
652     if (!mLocked.viewport.isValid()) {
653         return;
654     }
655 
656     mSpriteController->openTransaction();
657 
658     mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
659     mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
660     mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
661 
662     if (mLocked.pointerAlpha > 0) {
663         mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
664         mLocked.pointerSprite->setVisible(true);
665     } else {
666         mLocked.pointerSprite->setVisible(false);
667     }
668 
669     if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
670         if (mLocked.presentation == Presentation::POINTER) {
671             if (mLocked.requestedPointerType == mPolicy->getDefaultPointerIconId()) {
672                 mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
673             } else {
674                 std::map<int32_t, SpriteIcon>::const_iterator iter =
675                     mLocked.additionalMouseResources.find(mLocked.requestedPointerType);
676                 if (iter != mLocked.additionalMouseResources.end()) {
677                     std::map<int32_t, PointerAnimation>::const_iterator anim_iter =
678                             mLocked.animationResources.find(mLocked.requestedPointerType);
679                     if (anim_iter != mLocked.animationResources.end()) {
680                         mLocked.animationFrameIndex = 0;
681                         mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
682                         startAnimationLocked();
683                     }
684                     mLocked.pointerSprite->setIcon(iter->second);
685                 } else {
686                     ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType);
687                     mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
688                 }
689             }
690         } else {
691             mLocked.pointerSprite->setIcon(mResources.spotAnchor);
692         }
693         mLocked.pointerIconChanged = false;
694         mLocked.presentationChanged = false;
695     }
696 
697     mSpriteController->closeTransaction();
698 }
699 
getSpot(uint32_t id,const std::vector<Spot * > & spots)700 PointerController::Spot* PointerController::getSpot(uint32_t id, const std::vector<Spot*>& spots) {
701     for (size_t i = 0; i < spots.size(); i++) {
702         Spot* spot = spots[i];
703         if (spot->id == id) {
704             return spot;
705         }
706     }
707 
708     return nullptr;
709 }
710 
createAndAddSpotLocked(uint32_t id,std::vector<Spot * > & spots)711 PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id,
712         std::vector<Spot*>& spots) {
713     // Remove spots until we have fewer than MAX_SPOTS remaining.
714     while (spots.size() >= MAX_SPOTS) {
715         Spot* spot = removeFirstFadingSpotLocked(spots);
716         if (!spot) {
717             spot = spots[0];
718             spots.erase(spots.begin());
719         }
720         releaseSpotLocked(spot);
721     }
722 
723     // Obtain a sprite from the recycled pool.
724     sp<Sprite> sprite;
725     if (! mLocked.recycledSprites.empty()) {
726         sprite = mLocked.recycledSprites.back();
727         mLocked.recycledSprites.pop_back();
728     } else {
729         sprite = mSpriteController->createSprite();
730     }
731 
732     // Return the new spot.
733     Spot* spot = new Spot(id, sprite);
734     spots.push_back(spot);
735     return spot;
736 }
737 
removeFirstFadingSpotLocked(std::vector<Spot * > & spots)738 PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vector<Spot*>& spots) {
739     for (size_t i = 0; i < spots.size(); i++) {
740         Spot* spot = spots[i];
741         if (spot->id == Spot::INVALID_ID) {
742             spots.erase(spots.begin() + i);
743             return spot;
744         }
745     }
746     return nullptr;
747 }
748 
releaseSpotLocked(Spot * spot)749 void PointerController::releaseSpotLocked(Spot* spot) {
750     spot->sprite->clearIcon();
751 
752     if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
753         mLocked.recycledSprites.push_back(spot->sprite);
754     }
755 
756     delete spot;
757 }
758 
fadeOutAndReleaseSpotLocked(Spot * spot)759 void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
760     if (spot->id != Spot::INVALID_ID) {
761         spot->id = Spot::INVALID_ID;
762         startAnimationLocked();
763     }
764 }
765 
fadeOutAndReleaseAllSpotsLocked()766 void PointerController::fadeOutAndReleaseAllSpotsLocked() {
767     for (auto& it : mLocked.spotsByDisplay) {
768         const std::vector<Spot*>& spots = it.second;
769         size_t numSpots = spots.size();
770         for (size_t i = 0; i < numSpots; i++) {
771             Spot* spot = spots[i];
772             fadeOutAndReleaseSpotLocked(spot);
773         }
774     }
775 }
776 
loadResourcesLocked()777 void PointerController::loadResourcesLocked() REQUIRES(mLock) {
778     if (!mLocked.viewport.isValid()) {
779         return;
780     }
781 
782     mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
783     mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
784 
785     mLocked.additionalMouseResources.clear();
786     mLocked.animationResources.clear();
787     if (mLocked.presentation == Presentation::POINTER) {
788         mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
789                 &mLocked.animationResources, mLocked.viewport.displayId);
790     }
791 
792     mLocked.pointerIconChanged = true;
793 }
794 
795 
796 // --- PointerController::Spot ---
797 
updateSprite(const SpriteIcon * icon,float x,float y,int32_t displayId)798 void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
799         int32_t displayId) {
800     sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
801     sprite->setAlpha(alpha);
802     sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
803     sprite->setPosition(x, y);
804     sprite->setDisplayId(displayId);
805     this->x = x;
806     this->y = y;
807 
808     if (icon != lastIcon) {
809         lastIcon = icon;
810         if (icon) {
811             sprite->setIcon(*icon);
812             sprite->setVisible(true);
813         } else {
814             sprite->setVisible(false);
815         }
816     }
817 }
818 
819 } // namespace android
820