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