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