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