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