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