Home | History | Annotate | Download | only in input
      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:
     43     virtual ~WeakLooperCallback() { }
     44 
     45 public:
     46     WeakLooperCallback(const wp<LooperCallback>& callback) :
     47         mCallback(callback) {
     48     }
     49 
     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 
     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 
    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 
    142 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 
    149 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 
    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 
    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 
    195 int32_t PointerController::getButtonState() const {
    196     AutoMutex _l(mLock);
    197 
    198     return mLocked.buttonState;
    199 }
    200 
    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 
    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 
    231 void PointerController::getPosition(float* outX, float* outY) const {
    232     AutoMutex _l(mLock);
    233 
    234     *outX = mLocked.pointerX;
    235     *outY = mLocked.pointerY;
    236 }
    237 
    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 
    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 
    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 
    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 
    340 void PointerController::clearSpots() {
    341 #if DEBUG_POINTER_UPDATES
    342     ALOGD("clearSpots");
    343 #endif
    344 
    345     AutoMutex _l(mLock);
    346 
    347     fadeOutAndReleaseAllSpotsLocked();
    348 }
    349 
    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 
    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 
    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 
    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 
    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 
    477 void PointerController::handleMessage(const Message& message) {
    478     switch (message.what) {
    479     case MSG_INACTIVITY_TIMEOUT:
    480         doInactivityTimeout();
    481         break;
    482     }
    483 }
    484 
    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 
    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 
    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 
    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 
    595 void PointerController::doInactivityTimeout() {
    596     fade(TRANSITION_GRADUAL);
    597 }
    598 
    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 
    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 
    615 void PointerController::removeInactivityTimeoutLocked() {
    616     mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
    617 }
    618 
    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 
    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 
    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 
    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 
    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 
    720 void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
    721     if (spot->id != Spot::INVALID_ID) {
    722         spot->id = Spot::INVALID_ID;
    723         startAnimationLocked();
    724     }
    725 }
    726 
    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 
    734 void PointerController::loadResources() {
    735     mPolicy->loadPointerResources(&mResources);
    736 }
    737 
    738 
    739 // --- PointerController::Spot ---
    740 
    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