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 namespace android {
28 
29 // --- WeakLooperCallback ---
30 
31 class WeakLooperCallback: public LooperCallback {
32 protected:
~WeakLooperCallback()33     virtual ~WeakLooperCallback() { }
34 
35 public:
WeakLooperCallback(const wp<LooperCallback> & callback)36     explicit WeakLooperCallback(const wp<LooperCallback>& callback) :
37         mCallback(callback) {
38     }
39 
handleEvent(int fd,int events,void * data)40     virtual int handleEvent(int fd, int events, void* data) {
41         sp<LooperCallback> callback = mCallback.promote();
42         if (callback != NULL) {
43             return callback->handleEvent(fd, events, data);
44         }
45         return 0; // the client is gone, remove the callback
46     }
47 
48 private:
49     wp<LooperCallback> mCallback;
50 };
51 
52 // --- PointerController ---
53 
54 // Time to wait before starting the fade when the pointer is inactive.
55 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
56 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
57 
58 // Time to spend fading out the spot completely.
59 static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
60 
61 // Time to spend fading out the pointer completely.
62 static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
63 
64 // The number of events to be read at once for DisplayEventReceiver.
65 static const int EVENT_BUFFER_SIZE = 100;
66 
67 // --- PointerController ---
68 
PointerController(const sp<PointerControllerPolicyInterface> & policy,const sp<Looper> & looper,const sp<SpriteController> & spriteController)69 PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
70         const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
71         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
72     mHandler = new WeakMessageHandler(this);
73     mCallback = new WeakLooperCallback(this);
74 
75     if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
76         mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
77                        Looper::EVENT_INPUT, mCallback, nullptr);
78     } else {
79         ALOGE("Failed to initialize DisplayEventReceiver.");
80     }
81 
82     AutoMutex _l(mLock);
83 
84     mLocked.animationPending = false;
85 
86     mLocked.presentation = PRESENTATION_POINTER;
87     mLocked.presentationChanged = false;
88 
89     mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_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::handleMessage(const Message& message) {
484     switch (message.what) {
485     case MSG_INACTIVITY_TIMEOUT:
486         doInactivityTimeout();
487         break;
488     }
489 }
490 
handleEvent(int,int events,void *)491 int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
492     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
493         ALOGE("Display event receiver pipe was closed or an error occurred.  "
494               "events=0x%x", events);
495         return 0; // remove the callback
496     }
497 
498     if (!(events & Looper::EVENT_INPUT)) {
499         ALOGW("Received spurious callback for unhandled poll event.  "
500               "events=0x%x", events);
501         return 1; // keep the callback
502     }
503 
504     bool gotVsync = false;
505     ssize_t n;
506     nsecs_t timestamp;
507     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
508     while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
509         for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
510             if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
511                 timestamp = buf[i].header.timestamp;
512                 gotVsync = true;
513             }
514         }
515     }
516     if (gotVsync) {
517         doAnimate(timestamp);
518     }
519     return 1;  // keep the callback
520 }
521 
doAnimate(nsecs_t timestamp)522 void PointerController::doAnimate(nsecs_t timestamp) {
523     AutoMutex _l(mLock);
524 
525     mLocked.animationPending = false;
526 
527     bool keepFading = doFadingAnimationLocked(timestamp);
528     bool keepBitmapFlipping = doBitmapAnimationLocked(timestamp);
529     if (keepFading || keepBitmapFlipping) {
530         startAnimationLocked();
531     }
532 }
533 
doFadingAnimationLocked(nsecs_t timestamp)534 bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) {
535     bool keepAnimating = false;
536     nsecs_t frameDelay = timestamp - mLocked.animationTime;
537 
538     // Animate pointer fade.
539     if (mLocked.pointerFadeDirection < 0) {
540         mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
541         if (mLocked.pointerAlpha <= 0.0f) {
542             mLocked.pointerAlpha = 0.0f;
543             mLocked.pointerFadeDirection = 0;
544         } else {
545             keepAnimating = true;
546         }
547         updatePointerLocked();
548     } else if (mLocked.pointerFadeDirection > 0) {
549         mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
550         if (mLocked.pointerAlpha >= 1.0f) {
551             mLocked.pointerAlpha = 1.0f;
552             mLocked.pointerFadeDirection = 0;
553         } else {
554             keepAnimating = true;
555         }
556         updatePointerLocked();
557     }
558 
559     // Animate spots that are fading out and being removed.
560     for(auto it = mLocked.spotsByDisplay.begin(); it != mLocked.spotsByDisplay.end();) {
561         std::vector<Spot*>& spots = it->second;
562         size_t numSpots = spots.size();
563         for (size_t i = 0; i < numSpots;) {
564             Spot* spot = spots[i];
565             if (spot->id == Spot::INVALID_ID) {
566                 spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
567                 if (spot->alpha <= 0) {
568                     spots.erase(spots.begin() + i);
569                     releaseSpotLocked(spot);
570                     numSpots--;
571                     continue;
572                 } else {
573                     spot->sprite->setAlpha(spot->alpha);
574                     keepAnimating = true;
575                 }
576             }
577             ++i;
578         }
579 
580         if (spots.size() == 0) {
581             it = mLocked.spotsByDisplay.erase(it);
582         } else {
583             ++it;
584         }
585     }
586 
587     return keepAnimating;
588 }
589 
doBitmapAnimationLocked(nsecs_t timestamp)590 bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) {
591     std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find(
592             mLocked.requestedPointerType);
593     if (iter == mLocked.animationResources.end()) {
594         return false;
595     }
596 
597     if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
598         mSpriteController->openTransaction();
599 
600         int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
601         mLocked.animationFrameIndex += incr;
602         mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr;
603         while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) {
604             mLocked.animationFrameIndex -= iter->second.animationFrames.size();
605         }
606         mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);
607 
608         mSpriteController->closeTransaction();
609     }
610 
611     // Keep animating.
612     return true;
613 }
614 
doInactivityTimeout()615 void PointerController::doInactivityTimeout() {
616     fade(TRANSITION_GRADUAL);
617 }
618 
startAnimationLocked()619 void PointerController::startAnimationLocked() {
620     if (!mLocked.animationPending) {
621         mLocked.animationPending = true;
622         mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
623         mDisplayEventReceiver.requestNextVsync();
624     }
625 }
626 
resetInactivityTimeoutLocked()627 void PointerController::resetInactivityTimeoutLocked() {
628     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
629 
630     nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
631             ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
632     mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
633 }
634 
removeInactivityTimeoutLocked()635 void PointerController::removeInactivityTimeoutLocked() {
636     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
637 }
638 
updatePointerLocked()639 void PointerController::updatePointerLocked() REQUIRES(mLock) {
640     if (!mLocked.viewport.isValid()) {
641         return;
642     }
643 
644     mSpriteController->openTransaction();
645 
646     mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
647     mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
648     mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId);
649 
650     if (mLocked.pointerAlpha > 0) {
651         mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
652         mLocked.pointerSprite->setVisible(true);
653     } else {
654         mLocked.pointerSprite->setVisible(false);
655     }
656 
657     if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
658         if (mLocked.presentation == PRESENTATION_POINTER) {
659             if (mLocked.requestedPointerType == mPolicy->getDefaultPointerIconId()) {
660                 mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
661             } else {
662                 std::map<int32_t, SpriteIcon>::const_iterator iter =
663                     mLocked.additionalMouseResources.find(mLocked.requestedPointerType);
664                 if (iter != mLocked.additionalMouseResources.end()) {
665                     std::map<int32_t, PointerAnimation>::const_iterator anim_iter =
666                             mLocked.animationResources.find(mLocked.requestedPointerType);
667                     if (anim_iter != mLocked.animationResources.end()) {
668                         mLocked.animationFrameIndex = 0;
669                         mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
670                         startAnimationLocked();
671                     }
672                     mLocked.pointerSprite->setIcon(iter->second);
673                 } else {
674                     ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType);
675                     mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
676                 }
677             }
678         } else {
679             mLocked.pointerSprite->setIcon(mResources.spotAnchor);
680         }
681         mLocked.pointerIconChanged = false;
682         mLocked.presentationChanged = false;
683     }
684 
685     mSpriteController->closeTransaction();
686 }
687 
getSpot(uint32_t id,const std::vector<Spot * > & spots)688 PointerController::Spot* PointerController::getSpot(uint32_t id, const std::vector<Spot*>& spots) {
689     for (size_t i = 0; i < spots.size(); i++) {
690         Spot* spot = spots[i];
691         if (spot->id == id) {
692             return spot;
693         }
694     }
695 
696     return nullptr;
697 }
698 
createAndAddSpotLocked(uint32_t id,std::vector<Spot * > & spots)699 PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id,
700         std::vector<Spot*>& spots) {
701     // Remove spots until we have fewer than MAX_SPOTS remaining.
702     while (spots.size() >= MAX_SPOTS) {
703         Spot* spot = removeFirstFadingSpotLocked(spots);
704         if (!spot) {
705             spot = spots[0];
706             spots.erase(spots.begin());
707         }
708         releaseSpotLocked(spot);
709     }
710 
711     // Obtain a sprite from the recycled pool.
712     sp<Sprite> sprite;
713     if (! mLocked.recycledSprites.empty()) {
714         sprite = mLocked.recycledSprites.back();
715         mLocked.recycledSprites.pop_back();
716     } else {
717         sprite = mSpriteController->createSprite();
718     }
719 
720     // Return the new spot.
721     Spot* spot = new Spot(id, sprite);
722     spots.push_back(spot);
723     return spot;
724 }
725 
removeFirstFadingSpotLocked(std::vector<Spot * > & spots)726 PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vector<Spot*>& spots) {
727     for (size_t i = 0; i < spots.size(); i++) {
728         Spot* spot = spots[i];
729         if (spot->id == Spot::INVALID_ID) {
730             spots.erase(spots.begin() + i);
731             return spot;
732         }
733     }
734     return NULL;
735 }
736 
releaseSpotLocked(Spot * spot)737 void PointerController::releaseSpotLocked(Spot* spot) {
738     spot->sprite->clearIcon();
739 
740     if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
741         mLocked.recycledSprites.push_back(spot->sprite);
742     }
743 
744     delete spot;
745 }
746 
fadeOutAndReleaseSpotLocked(Spot * spot)747 void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
748     if (spot->id != Spot::INVALID_ID) {
749         spot->id = Spot::INVALID_ID;
750         startAnimationLocked();
751     }
752 }
753 
fadeOutAndReleaseAllSpotsLocked()754 void PointerController::fadeOutAndReleaseAllSpotsLocked() {
755     for (auto& it : mLocked.spotsByDisplay) {
756         const std::vector<Spot*>& spots = it.second;
757         size_t numSpots = spots.size();
758         for (size_t i = 0; i < numSpots; i++) {
759             Spot* spot = spots[i];
760             fadeOutAndReleaseSpotLocked(spot);
761         }
762     }
763 }
764 
loadResourcesLocked()765 void PointerController::loadResourcesLocked() REQUIRES(mLock) {
766     if (!mLocked.viewport.isValid()) {
767         return;
768     }
769 
770     mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
771     mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
772 
773     mLocked.additionalMouseResources.clear();
774     mLocked.animationResources.clear();
775     if (mLocked.presentation == PRESENTATION_POINTER) {
776         mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
777                 &mLocked.animationResources, mLocked.viewport.displayId);
778     }
779 
780     mLocked.pointerIconChanged = true;
781 }
782 
783 
784 // --- PointerController::Spot ---
785 
updateSprite(const SpriteIcon * icon,float x,float y,int32_t displayId)786 void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
787         int32_t displayId) {
788     sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
789     sprite->setAlpha(alpha);
790     sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
791     sprite->setPosition(x, y);
792     sprite->setDisplayId(displayId);
793     this->x = x;
794     this->y = y;
795 
796     if (icon != lastIcon) {
797         lastIcon = icon;
798         if (icon) {
799             sprite->setIcon(*icon);
800             sprite->setVisible(true);
801         } else {
802             sprite->setVisible(false);
803         }
804     }
805 }
806 
807 } // namespace android
808