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