1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/gonk/libui/PointerController.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,604 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +#define LOG_TAG "PointerController" 1.21 + 1.22 +//#define LOG_NDEBUG 0 1.23 + 1.24 +// Log debug messages about pointer updates 1.25 +#define DEBUG_POINTER_UPDATES 0 1.26 + 1.27 +#include "PointerController.h" 1.28 + 1.29 +#include "cutils_log.h" 1.30 + 1.31 +#include <SkBitmap.h> 1.32 +#include <SkCanvas.h> 1.33 +#include <SkColor.h> 1.34 +#include <SkPaint.h> 1.35 +#include <SkXfermode.h> 1.36 + 1.37 +namespace android { 1.38 + 1.39 +// --- PointerController --- 1.40 + 1.41 +// Time to wait before starting the fade when the pointer is inactive. 1.42 +static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds 1.43 +static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds 1.44 + 1.45 +// Time to wait between animation frames. 1.46 +static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60; 1.47 + 1.48 +// Time to spend fading out the spot completely. 1.49 +static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms 1.50 + 1.51 +// Time to spend fading out the pointer completely. 1.52 +static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms 1.53 + 1.54 + 1.55 +// --- PointerController --- 1.56 + 1.57 +PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy, 1.58 + const sp<Looper>& looper, const sp<SpriteController>& spriteController) : 1.59 + mPolicy(policy), mLooper(looper), mSpriteController(spriteController) { 1.60 + mHandler = new WeakMessageHandler(this); 1.61 + 1.62 + AutoMutex _l(mLock); 1.63 + 1.64 + mLocked.animationPending = false; 1.65 + 1.66 + mLocked.displayWidth = -1; 1.67 + mLocked.displayHeight = -1; 1.68 + mLocked.displayOrientation = DISPLAY_ORIENTATION_0; 1.69 + 1.70 + mLocked.presentation = PRESENTATION_POINTER; 1.71 + mLocked.presentationChanged = false; 1.72 + 1.73 + mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL; 1.74 + 1.75 + mLocked.pointerFadeDirection = 0; 1.76 + mLocked.pointerX = 0; 1.77 + mLocked.pointerY = 0; 1.78 + mLocked.pointerAlpha = 0.0f; // pointer is initially faded 1.79 + mLocked.pointerSprite = mSpriteController->createSprite(); 1.80 + mLocked.pointerIconChanged = false; 1.81 + 1.82 + mLocked.buttonState = 0; 1.83 + 1.84 + loadResources(); 1.85 +} 1.86 + 1.87 +PointerController::~PointerController() { 1.88 + mLooper->removeMessages(mHandler); 1.89 + 1.90 + AutoMutex _l(mLock); 1.91 + 1.92 + mLocked.pointerSprite.clear(); 1.93 + 1.94 + for (size_t i = 0; i < mLocked.spots.size(); i++) { 1.95 + delete mLocked.spots.itemAt(i); 1.96 + } 1.97 + mLocked.spots.clear(); 1.98 + mLocked.recycledSprites.clear(); 1.99 +} 1.100 + 1.101 +bool PointerController::getBounds(float* outMinX, float* outMinY, 1.102 + float* outMaxX, float* outMaxY) const { 1.103 + AutoMutex _l(mLock); 1.104 + 1.105 + return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); 1.106 +} 1.107 + 1.108 +bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, 1.109 + float* outMaxX, float* outMaxY) const { 1.110 + if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { 1.111 + return false; 1.112 + } 1.113 + 1.114 + *outMinX = 0; 1.115 + *outMinY = 0; 1.116 + switch (mLocked.displayOrientation) { 1.117 + case DISPLAY_ORIENTATION_90: 1.118 + case DISPLAY_ORIENTATION_270: 1.119 + *outMaxX = mLocked.displayHeight - 1; 1.120 + *outMaxY = mLocked.displayWidth - 1; 1.121 + break; 1.122 + default: 1.123 + *outMaxX = mLocked.displayWidth - 1; 1.124 + *outMaxY = mLocked.displayHeight - 1; 1.125 + break; 1.126 + } 1.127 + return true; 1.128 +} 1.129 + 1.130 +void PointerController::move(float deltaX, float deltaY) { 1.131 +#if DEBUG_POINTER_UPDATES 1.132 + ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); 1.133 +#endif 1.134 + if (deltaX == 0.0f && deltaY == 0.0f) { 1.135 + return; 1.136 + } 1.137 + 1.138 + AutoMutex _l(mLock); 1.139 + 1.140 + setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); 1.141 +} 1.142 + 1.143 +void PointerController::setButtonState(int32_t buttonState) { 1.144 +#if DEBUG_POINTER_UPDATES 1.145 + ALOGD("Set button state 0x%08x", buttonState); 1.146 +#endif 1.147 + AutoMutex _l(mLock); 1.148 + 1.149 + if (mLocked.buttonState != buttonState) { 1.150 + mLocked.buttonState = buttonState; 1.151 + } 1.152 +} 1.153 + 1.154 +int32_t PointerController::getButtonState() const { 1.155 + AutoMutex _l(mLock); 1.156 + 1.157 + return mLocked.buttonState; 1.158 +} 1.159 + 1.160 +void PointerController::setPosition(float x, float y) { 1.161 +#if DEBUG_POINTER_UPDATES 1.162 + ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); 1.163 +#endif 1.164 + AutoMutex _l(mLock); 1.165 + 1.166 + setPositionLocked(x, y); 1.167 +} 1.168 + 1.169 +void PointerController::setPositionLocked(float x, float y) { 1.170 + float minX, minY, maxX, maxY; 1.171 + if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { 1.172 + if (x <= minX) { 1.173 + mLocked.pointerX = minX; 1.174 + } else if (x >= maxX) { 1.175 + mLocked.pointerX = maxX; 1.176 + } else { 1.177 + mLocked.pointerX = x; 1.178 + } 1.179 + if (y <= minY) { 1.180 + mLocked.pointerY = minY; 1.181 + } else if (y >= maxY) { 1.182 + mLocked.pointerY = maxY; 1.183 + } else { 1.184 + mLocked.pointerY = y; 1.185 + } 1.186 + updatePointerLocked(); 1.187 + } 1.188 +} 1.189 + 1.190 +void PointerController::getPosition(float* outX, float* outY) const { 1.191 + AutoMutex _l(mLock); 1.192 + 1.193 + *outX = mLocked.pointerX; 1.194 + *outY = mLocked.pointerY; 1.195 +} 1.196 + 1.197 +void PointerController::fade(Transition transition) { 1.198 + AutoMutex _l(mLock); 1.199 + 1.200 + // Remove the inactivity timeout, since we are fading now. 1.201 + removeInactivityTimeoutLocked(); 1.202 + 1.203 + // Start fading. 1.204 + if (transition == TRANSITION_IMMEDIATE) { 1.205 + mLocked.pointerFadeDirection = 0; 1.206 + mLocked.pointerAlpha = 0.0f; 1.207 + updatePointerLocked(); 1.208 + } else { 1.209 + mLocked.pointerFadeDirection = -1; 1.210 + startAnimationLocked(); 1.211 + } 1.212 +} 1.213 + 1.214 +void PointerController::unfade(Transition transition) { 1.215 + AutoMutex _l(mLock); 1.216 + 1.217 + // Always reset the inactivity timer. 1.218 + resetInactivityTimeoutLocked(); 1.219 + 1.220 + // Start unfading. 1.221 + if (transition == TRANSITION_IMMEDIATE) { 1.222 + mLocked.pointerFadeDirection = 0; 1.223 + mLocked.pointerAlpha = 1.0f; 1.224 + updatePointerLocked(); 1.225 + } else { 1.226 + mLocked.pointerFadeDirection = 1; 1.227 + startAnimationLocked(); 1.228 + } 1.229 +} 1.230 + 1.231 +void PointerController::setPresentation(Presentation presentation) { 1.232 + AutoMutex _l(mLock); 1.233 + 1.234 + if (mLocked.presentation != presentation) { 1.235 + mLocked.presentation = presentation; 1.236 + mLocked.presentationChanged = true; 1.237 + 1.238 + if (presentation != PRESENTATION_SPOT) { 1.239 + fadeOutAndReleaseAllSpotsLocked(); 1.240 + } 1.241 + 1.242 + updatePointerLocked(); 1.243 + } 1.244 +} 1.245 + 1.246 +void PointerController::setSpots(const PointerCoords* spotCoords, 1.247 + const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { 1.248 +#if DEBUG_POINTER_UPDATES 1.249 + ALOGD("setSpots: idBits=%08x", spotIdBits.value); 1.250 + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { 1.251 + uint32_t id = idBits.firstMarkedBit(); 1.252 + idBits.clearBit(id); 1.253 + const PointerCoords& c = spotCoords[spotIdToIndex[id]]; 1.254 + ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, 1.255 + c.getAxisValue(AMOTION_EVENT_AXIS_X), 1.256 + c.getAxisValue(AMOTION_EVENT_AXIS_Y), 1.257 + c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); 1.258 + } 1.259 +#endif 1.260 + 1.261 + AutoMutex _l(mLock); 1.262 + 1.263 + mSpriteController->openTransaction(); 1.264 + 1.265 + // Add or move spots for fingers that are down. 1.266 + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { 1.267 + uint32_t id = idBits.clearFirstMarkedBit(); 1.268 + const PointerCoords& c = spotCoords[spotIdToIndex[id]]; 1.269 + const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 1.270 + ? mResources.spotTouch : mResources.spotHover; 1.271 + float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); 1.272 + float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); 1.273 + 1.274 + Spot* spot = getSpotLocked(id); 1.275 + if (!spot) { 1.276 + spot = createAndAddSpotLocked(id); 1.277 + } 1.278 + 1.279 + spot->updateSprite(&icon, x, y); 1.280 + } 1.281 + 1.282 + // Remove spots for fingers that went up. 1.283 + for (size_t i = 0; i < mLocked.spots.size(); i++) { 1.284 + Spot* spot = mLocked.spots.itemAt(i); 1.285 + if (spot->id != Spot::INVALID_ID 1.286 + && !spotIdBits.hasBit(spot->id)) { 1.287 + fadeOutAndReleaseSpotLocked(spot); 1.288 + } 1.289 + } 1.290 + 1.291 + mSpriteController->closeTransaction(); 1.292 +} 1.293 + 1.294 +void PointerController::clearSpots() { 1.295 +#if DEBUG_POINTER_UPDATES 1.296 + ALOGD("clearSpots"); 1.297 +#endif 1.298 + 1.299 + AutoMutex _l(mLock); 1.300 + 1.301 + fadeOutAndReleaseAllSpotsLocked(); 1.302 +} 1.303 + 1.304 +void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { 1.305 + AutoMutex _l(mLock); 1.306 + 1.307 + if (mLocked.inactivityTimeout != inactivityTimeout) { 1.308 + mLocked.inactivityTimeout = inactivityTimeout; 1.309 + resetInactivityTimeoutLocked(); 1.310 + } 1.311 +} 1.312 + 1.313 +void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) { 1.314 + AutoMutex _l(mLock); 1.315 + 1.316 + // Adjust to use the display's unrotated coordinate frame. 1.317 + if (orientation == DISPLAY_ORIENTATION_90 1.318 + || orientation == DISPLAY_ORIENTATION_270) { 1.319 + int32_t temp = height; 1.320 + height = width; 1.321 + width = temp; 1.322 + } 1.323 + 1.324 + if (mLocked.displayWidth != width || mLocked.displayHeight != height) { 1.325 + mLocked.displayWidth = width; 1.326 + mLocked.displayHeight = height; 1.327 + 1.328 + float minX, minY, maxX, maxY; 1.329 + if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { 1.330 + mLocked.pointerX = (minX + maxX) * 0.5f; 1.331 + mLocked.pointerY = (minY + maxY) * 0.5f; 1.332 + } else { 1.333 + mLocked.pointerX = 0; 1.334 + mLocked.pointerY = 0; 1.335 + } 1.336 + 1.337 + fadeOutAndReleaseAllSpotsLocked(); 1.338 + } 1.339 + 1.340 + if (mLocked.displayOrientation != orientation) { 1.341 + // Apply offsets to convert from the pixel top-left corner position to the pixel center. 1.342 + // This creates an invariant frame of reference that we can easily rotate when 1.343 + // taking into account that the pointer may be located at fractional pixel offsets. 1.344 + float x = mLocked.pointerX + 0.5f; 1.345 + float y = mLocked.pointerY + 0.5f; 1.346 + float temp; 1.347 + 1.348 + // Undo the previous rotation. 1.349 + switch (mLocked.displayOrientation) { 1.350 + case DISPLAY_ORIENTATION_90: 1.351 + temp = x; 1.352 + x = mLocked.displayWidth - y; 1.353 + y = temp; 1.354 + break; 1.355 + case DISPLAY_ORIENTATION_180: 1.356 + x = mLocked.displayWidth - x; 1.357 + y = mLocked.displayHeight - y; 1.358 + break; 1.359 + case DISPLAY_ORIENTATION_270: 1.360 + temp = x; 1.361 + x = y; 1.362 + y = mLocked.displayHeight - temp; 1.363 + break; 1.364 + } 1.365 + 1.366 + // Perform the new rotation. 1.367 + switch (orientation) { 1.368 + case DISPLAY_ORIENTATION_90: 1.369 + temp = x; 1.370 + x = y; 1.371 + y = mLocked.displayWidth - temp; 1.372 + break; 1.373 + case DISPLAY_ORIENTATION_180: 1.374 + x = mLocked.displayWidth - x; 1.375 + y = mLocked.displayHeight - y; 1.376 + break; 1.377 + case DISPLAY_ORIENTATION_270: 1.378 + temp = x; 1.379 + x = mLocked.displayHeight - y; 1.380 + y = temp; 1.381 + break; 1.382 + } 1.383 + 1.384 + // Apply offsets to convert from the pixel center to the pixel top-left corner position 1.385 + // and save the results. 1.386 + mLocked.pointerX = x - 0.5f; 1.387 + mLocked.pointerY = y - 0.5f; 1.388 + mLocked.displayOrientation = orientation; 1.389 + } 1.390 + 1.391 + updatePointerLocked(); 1.392 +} 1.393 + 1.394 +void PointerController::setPointerIcon(const SpriteIcon& icon) { 1.395 + AutoMutex _l(mLock); 1.396 + 1.397 + mLocked.pointerIcon = icon.copy(); 1.398 + mLocked.pointerIconChanged = true; 1.399 + 1.400 + updatePointerLocked(); 1.401 +} 1.402 + 1.403 +void PointerController::handleMessage(const Message& message) { 1.404 + switch (message.what) { 1.405 + case MSG_ANIMATE: 1.406 + doAnimate(); 1.407 + break; 1.408 + case MSG_INACTIVITY_TIMEOUT: 1.409 + doInactivityTimeout(); 1.410 + break; 1.411 + } 1.412 +} 1.413 + 1.414 +void PointerController::doAnimate() { 1.415 + AutoMutex _l(mLock); 1.416 + 1.417 + bool keepAnimating = false; 1.418 + mLocked.animationPending = false; 1.419 + nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime; 1.420 + 1.421 + // Animate pointer fade. 1.422 + if (mLocked.pointerFadeDirection < 0) { 1.423 + mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; 1.424 + if (mLocked.pointerAlpha <= 0.0f) { 1.425 + mLocked.pointerAlpha = 0.0f; 1.426 + mLocked.pointerFadeDirection = 0; 1.427 + } else { 1.428 + keepAnimating = true; 1.429 + } 1.430 + updatePointerLocked(); 1.431 + } else if (mLocked.pointerFadeDirection > 0) { 1.432 + mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; 1.433 + if (mLocked.pointerAlpha >= 1.0f) { 1.434 + mLocked.pointerAlpha = 1.0f; 1.435 + mLocked.pointerFadeDirection = 0; 1.436 + } else { 1.437 + keepAnimating = true; 1.438 + } 1.439 + updatePointerLocked(); 1.440 + } 1.441 + 1.442 + // Animate spots that are fading out and being removed. 1.443 + for (size_t i = 0; i < mLocked.spots.size(); i++) { 1.444 + Spot* spot = mLocked.spots.itemAt(i); 1.445 + if (spot->id == Spot::INVALID_ID) { 1.446 + spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; 1.447 + if (spot->alpha <= 0) { 1.448 + mLocked.spots.removeAt(i--); 1.449 + releaseSpotLocked(spot); 1.450 + } else { 1.451 + spot->sprite->setAlpha(spot->alpha); 1.452 + keepAnimating = true; 1.453 + } 1.454 + } 1.455 + } 1.456 + 1.457 + if (keepAnimating) { 1.458 + startAnimationLocked(); 1.459 + } 1.460 +} 1.461 + 1.462 +void PointerController::doInactivityTimeout() { 1.463 + fade(TRANSITION_GRADUAL); 1.464 +} 1.465 + 1.466 +void PointerController::startAnimationLocked() { 1.467 + if (!mLocked.animationPending) { 1.468 + mLocked.animationPending = true; 1.469 + mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); 1.470 + mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE)); 1.471 + } 1.472 +} 1.473 + 1.474 +void PointerController::resetInactivityTimeoutLocked() { 1.475 + mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); 1.476 + 1.477 + nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT 1.478 + ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; 1.479 + mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); 1.480 +} 1.481 + 1.482 +void PointerController::removeInactivityTimeoutLocked() { 1.483 + mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); 1.484 +} 1.485 + 1.486 +void PointerController::updatePointerLocked() { 1.487 + mSpriteController->openTransaction(); 1.488 + 1.489 + mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); 1.490 + mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); 1.491 + 1.492 + if (mLocked.pointerAlpha > 0) { 1.493 + mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); 1.494 + mLocked.pointerSprite->setVisible(true); 1.495 + } else { 1.496 + mLocked.pointerSprite->setVisible(false); 1.497 + } 1.498 + 1.499 + if (mLocked.pointerIconChanged || mLocked.presentationChanged) { 1.500 + mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER 1.501 + ? mLocked.pointerIcon : mResources.spotAnchor); 1.502 + mLocked.pointerIconChanged = false; 1.503 + mLocked.presentationChanged = false; 1.504 + } 1.505 + 1.506 + mSpriteController->closeTransaction(); 1.507 +} 1.508 + 1.509 +PointerController::Spot* PointerController::getSpotLocked(uint32_t id) { 1.510 + for (size_t i = 0; i < mLocked.spots.size(); i++) { 1.511 + Spot* spot = mLocked.spots.itemAt(i); 1.512 + if (spot->id == id) { 1.513 + return spot; 1.514 + } 1.515 + } 1.516 + return NULL; 1.517 +} 1.518 + 1.519 +PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) { 1.520 + // Remove spots until we have fewer than MAX_SPOTS remaining. 1.521 + while (mLocked.spots.size() >= MAX_SPOTS) { 1.522 + Spot* spot = removeFirstFadingSpotLocked(); 1.523 + if (!spot) { 1.524 + spot = mLocked.spots.itemAt(0); 1.525 + mLocked.spots.removeAt(0); 1.526 + } 1.527 + releaseSpotLocked(spot); 1.528 + } 1.529 + 1.530 + // Obtain a sprite from the recycled pool. 1.531 + sp<Sprite> sprite; 1.532 + if (! mLocked.recycledSprites.isEmpty()) { 1.533 + sprite = mLocked.recycledSprites.top(); 1.534 + mLocked.recycledSprites.pop(); 1.535 + } else { 1.536 + sprite = mSpriteController->createSprite(); 1.537 + } 1.538 + 1.539 + // Return the new spot. 1.540 + Spot* spot = new Spot(id, sprite); 1.541 + mLocked.spots.push(spot); 1.542 + return spot; 1.543 +} 1.544 + 1.545 +PointerController::Spot* PointerController::removeFirstFadingSpotLocked() { 1.546 + for (size_t i = 0; i < mLocked.spots.size(); i++) { 1.547 + Spot* spot = mLocked.spots.itemAt(i); 1.548 + if (spot->id == Spot::INVALID_ID) { 1.549 + mLocked.spots.removeAt(i); 1.550 + return spot; 1.551 + } 1.552 + } 1.553 + return NULL; 1.554 +} 1.555 + 1.556 +void PointerController::releaseSpotLocked(Spot* spot) { 1.557 + spot->sprite->clearIcon(); 1.558 + 1.559 + if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { 1.560 + mLocked.recycledSprites.push(spot->sprite); 1.561 + } 1.562 + 1.563 + delete spot; 1.564 +} 1.565 + 1.566 +void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { 1.567 + if (spot->id != Spot::INVALID_ID) { 1.568 + spot->id = Spot::INVALID_ID; 1.569 + startAnimationLocked(); 1.570 + } 1.571 +} 1.572 + 1.573 +void PointerController::fadeOutAndReleaseAllSpotsLocked() { 1.574 + for (size_t i = 0; i < mLocked.spots.size(); i++) { 1.575 + Spot* spot = mLocked.spots.itemAt(i); 1.576 + fadeOutAndReleaseSpotLocked(spot); 1.577 + } 1.578 +} 1.579 + 1.580 +void PointerController::loadResources() { 1.581 + mPolicy->loadPointerResources(&mResources); 1.582 +} 1.583 + 1.584 + 1.585 +// --- PointerController::Spot --- 1.586 + 1.587 +void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) { 1.588 + sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); 1.589 + sprite->setAlpha(alpha); 1.590 + sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); 1.591 + sprite->setPosition(x, y); 1.592 + 1.593 + this->x = x; 1.594 + this->y = y; 1.595 + 1.596 + if (icon != lastIcon) { 1.597 + lastIcon = icon; 1.598 + if (icon) { 1.599 + sprite->setIcon(*icon); 1.600 + sprite->setVisible(true); 1.601 + } else { 1.602 + sprite->setVisible(false); 1.603 + } 1.604 + } 1.605 +} 1.606 + 1.607 +} // namespace android