PointerController.cpp revision c0c0ac37abe6f0b1ab780765b4a48beada7d3444
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.requestedPointerShape = mPolicy->getDefaultPointerIconId(); 88 89 mLocked.buttonState = 0; 90 91 loadResources(); 92} 93 94PointerController::~PointerController() { 95 mLooper->removeMessages(mHandler); 96 97 AutoMutex _l(mLock); 98 99 mLocked.pointerSprite.clear(); 100 101 for (size_t i = 0; i < mLocked.spots.size(); i++) { 102 delete mLocked.spots.itemAt(i); 103 } 104 mLocked.spots.clear(); 105 mLocked.recycledSprites.clear(); 106} 107 108bool PointerController::getBounds(float* outMinX, float* outMinY, 109 float* outMaxX, float* outMaxY) const { 110 AutoMutex _l(mLock); 111 112 return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); 113} 114 115bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, 116 float* outMaxX, float* outMaxY) const { 117 if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { 118 return false; 119 } 120 121 *outMinX = 0; 122 *outMinY = 0; 123 switch (mLocked.displayOrientation) { 124 case DISPLAY_ORIENTATION_90: 125 case DISPLAY_ORIENTATION_270: 126 *outMaxX = mLocked.displayHeight - 1; 127 *outMaxY = mLocked.displayWidth - 1; 128 break; 129 default: 130 *outMaxX = mLocked.displayWidth - 1; 131 *outMaxY = mLocked.displayHeight - 1; 132 break; 133 } 134 return true; 135} 136 137void PointerController::move(float deltaX, float deltaY) { 138#if DEBUG_POINTER_UPDATES 139 ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); 140#endif 141 if (deltaX == 0.0f && deltaY == 0.0f) { 142 return; 143 } 144 145 AutoMutex _l(mLock); 146 147 setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); 148} 149 150void PointerController::setButtonState(int32_t buttonState) { 151#if DEBUG_POINTER_UPDATES 152 ALOGD("Set button state 0x%08x", buttonState); 153#endif 154 AutoMutex _l(mLock); 155 156 if (mLocked.buttonState != buttonState) { 157 mLocked.buttonState = buttonState; 158 } 159} 160 161int32_t PointerController::getButtonState() const { 162 AutoMutex _l(mLock); 163 164 return mLocked.buttonState; 165} 166 167void PointerController::setPosition(float x, float y) { 168#if DEBUG_POINTER_UPDATES 169 ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); 170#endif 171 AutoMutex _l(mLock); 172 173 setPositionLocked(x, y); 174} 175 176void PointerController::setPositionLocked(float x, float y) { 177 float minX, minY, maxX, maxY; 178 if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { 179 if (x <= minX) { 180 mLocked.pointerX = minX; 181 } else if (x >= maxX) { 182 mLocked.pointerX = maxX; 183 } else { 184 mLocked.pointerX = x; 185 } 186 if (y <= minY) { 187 mLocked.pointerY = minY; 188 } else if (y >= maxY) { 189 mLocked.pointerY = maxY; 190 } else { 191 mLocked.pointerY = y; 192 } 193 updatePointerLocked(); 194 } 195} 196 197void PointerController::getPosition(float* outX, float* outY) const { 198 AutoMutex _l(mLock); 199 200 *outX = mLocked.pointerX; 201 *outY = mLocked.pointerY; 202} 203 204void PointerController::fade(Transition transition) { 205 AutoMutex _l(mLock); 206 207 // Remove the inactivity timeout, since we are fading now. 208 removeInactivityTimeoutLocked(); 209 210 // Start fading. 211 if (transition == TRANSITION_IMMEDIATE) { 212 mLocked.pointerFadeDirection = 0; 213 mLocked.pointerAlpha = 0.0f; 214 updatePointerLocked(); 215 } else { 216 mLocked.pointerFadeDirection = -1; 217 startAnimationLocked(); 218 } 219} 220 221void PointerController::unfade(Transition transition) { 222 AutoMutex _l(mLock); 223 224 // Always reset the inactivity timer. 225 resetInactivityTimeoutLocked(); 226 227 // Start unfading. 228 if (transition == TRANSITION_IMMEDIATE) { 229 mLocked.pointerFadeDirection = 0; 230 mLocked.pointerAlpha = 1.0f; 231 updatePointerLocked(); 232 } else { 233 mLocked.pointerFadeDirection = 1; 234 startAnimationLocked(); 235 } 236} 237 238void PointerController::setPresentation(Presentation presentation) { 239 AutoMutex _l(mLock); 240 241 if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) { 242 mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources); 243 } 244 245 if (mLocked.presentation != presentation) { 246 mLocked.presentation = presentation; 247 mLocked.presentationChanged = true; 248 249 if (presentation != PRESENTATION_SPOT) { 250 fadeOutAndReleaseAllSpotsLocked(); 251 } 252 253 updatePointerLocked(); 254 } 255} 256 257void PointerController::setSpots(const PointerCoords* spotCoords, 258 const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { 259#if DEBUG_POINTER_UPDATES 260 ALOGD("setSpots: idBits=%08x", spotIdBits.value); 261 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { 262 uint32_t id = idBits.firstMarkedBit(); 263 idBits.clearBit(id); 264 const PointerCoords& c = spotCoords[spotIdToIndex[id]]; 265 ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, 266 c.getAxisValue(AMOTION_EVENT_AXIS_X), 267 c.getAxisValue(AMOTION_EVENT_AXIS_Y), 268 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); 269 } 270#endif 271 272 AutoMutex _l(mLock); 273 274 mSpriteController->openTransaction(); 275 276 // Add or move spots for fingers that are down. 277 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { 278 uint32_t id = idBits.clearFirstMarkedBit(); 279 const PointerCoords& c = spotCoords[spotIdToIndex[id]]; 280 const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 281 ? mResources.spotTouch : mResources.spotHover; 282 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); 283 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); 284 285 Spot* spot = getSpotLocked(id); 286 if (!spot) { 287 spot = createAndAddSpotLocked(id); 288 } 289 290 spot->updateSprite(&icon, x, y); 291 } 292 293 // Remove spots for fingers that went up. 294 for (size_t i = 0; i < mLocked.spots.size(); i++) { 295 Spot* spot = mLocked.spots.itemAt(i); 296 if (spot->id != Spot::INVALID_ID 297 && !spotIdBits.hasBit(spot->id)) { 298 fadeOutAndReleaseSpotLocked(spot); 299 } 300 } 301 302 mSpriteController->closeTransaction(); 303} 304 305void PointerController::clearSpots() { 306#if DEBUG_POINTER_UPDATES 307 ALOGD("clearSpots"); 308#endif 309 310 AutoMutex _l(mLock); 311 312 fadeOutAndReleaseAllSpotsLocked(); 313} 314 315void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { 316 AutoMutex _l(mLock); 317 318 if (mLocked.inactivityTimeout != inactivityTimeout) { 319 mLocked.inactivityTimeout = inactivityTimeout; 320 resetInactivityTimeoutLocked(); 321 } 322} 323 324void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) { 325 AutoMutex _l(mLock); 326 327 // Adjust to use the display's unrotated coordinate frame. 328 if (orientation == DISPLAY_ORIENTATION_90 329 || orientation == DISPLAY_ORIENTATION_270) { 330 int32_t temp = height; 331 height = width; 332 width = temp; 333 } 334 335 if (mLocked.displayWidth != width || mLocked.displayHeight != height) { 336 mLocked.displayWidth = width; 337 mLocked.displayHeight = height; 338 339 float minX, minY, maxX, maxY; 340 if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { 341 mLocked.pointerX = (minX + maxX) * 0.5f; 342 mLocked.pointerY = (minY + maxY) * 0.5f; 343 } else { 344 mLocked.pointerX = 0; 345 mLocked.pointerY = 0; 346 } 347 348 fadeOutAndReleaseAllSpotsLocked(); 349 } 350 351 if (mLocked.displayOrientation != orientation) { 352 // Apply offsets to convert from the pixel top-left corner position to the pixel center. 353 // This creates an invariant frame of reference that we can easily rotate when 354 // taking into account that the pointer may be located at fractional pixel offsets. 355 float x = mLocked.pointerX + 0.5f; 356 float y = mLocked.pointerY + 0.5f; 357 float temp; 358 359 // Undo the previous rotation. 360 switch (mLocked.displayOrientation) { 361 case DISPLAY_ORIENTATION_90: 362 temp = x; 363 x = mLocked.displayWidth - y; 364 y = temp; 365 break; 366 case DISPLAY_ORIENTATION_180: 367 x = mLocked.displayWidth - x; 368 y = mLocked.displayHeight - y; 369 break; 370 case DISPLAY_ORIENTATION_270: 371 temp = x; 372 x = y; 373 y = mLocked.displayHeight - temp; 374 break; 375 } 376 377 // Perform the new rotation. 378 switch (orientation) { 379 case DISPLAY_ORIENTATION_90: 380 temp = x; 381 x = y; 382 y = mLocked.displayWidth - temp; 383 break; 384 case DISPLAY_ORIENTATION_180: 385 x = mLocked.displayWidth - x; 386 y = mLocked.displayHeight - y; 387 break; 388 case DISPLAY_ORIENTATION_270: 389 temp = x; 390 x = mLocked.displayHeight - y; 391 y = temp; 392 break; 393 } 394 395 // Apply offsets to convert from the pixel center to the pixel top-left corner position 396 // and save the results. 397 mLocked.pointerX = x - 0.5f; 398 mLocked.pointerY = y - 0.5f; 399 mLocked.displayOrientation = orientation; 400 } 401 402 updatePointerLocked(); 403} 404 405void PointerController::updatePointerShape(int iconId) { 406 AutoMutex _l(mLock); 407 if (mLocked.requestedPointerShape != iconId) { 408 mLocked.requestedPointerShape = iconId; 409 mLocked.presentationChanged = true; 410 updatePointerLocked(); 411 } 412} 413 414void PointerController::setPointerIcon(const SpriteIcon& icon) { 415 AutoMutex _l(mLock); 416 417 mLocked.pointerIcon = icon.copy(); 418 mLocked.pointerIconChanged = true; 419 420 updatePointerLocked(); 421} 422 423void PointerController::handleMessage(const Message& message) { 424 switch (message.what) { 425 case MSG_INACTIVITY_TIMEOUT: 426 doInactivityTimeout(); 427 break; 428 } 429} 430 431int PointerController::handleEvent(int /* fd */, int events, void* /* data */) { 432 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { 433 ALOGE("Display event receiver pipe was closed or an error occurred. " 434 "events=0x%x", events); 435 return 0; // remove the callback 436 } 437 438 if (!(events & Looper::EVENT_INPUT)) { 439 ALOGW("Received spurious callback for unhandled poll event. " 440 "events=0x%x", events); 441 return 1; // keep the callback 442 } 443 444 bool gotVsync = false; 445 ssize_t n; 446 nsecs_t timestamp; 447 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; 448 while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { 449 for (size_t i = 0; i < static_cast<size_t>(n); ++i) { 450 if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { 451 timestamp = buf[i].header.timestamp; 452 gotVsync = true; 453 } 454 } 455 } 456 if (gotVsync) { 457 doAnimate(timestamp); 458 } 459 return 1; // keep the callback 460} 461 462void PointerController::doAnimate(nsecs_t timestamp) { 463 AutoMutex _l(mLock); 464 465 bool keepAnimating = false; 466 mLocked.animationPending = false; 467 nsecs_t frameDelay = timestamp - mLocked.animationTime; 468 469 // Animate pointer fade. 470 if (mLocked.pointerFadeDirection < 0) { 471 mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; 472 if (mLocked.pointerAlpha <= 0.0f) { 473 mLocked.pointerAlpha = 0.0f; 474 mLocked.pointerFadeDirection = 0; 475 } else { 476 keepAnimating = true; 477 } 478 updatePointerLocked(); 479 } else if (mLocked.pointerFadeDirection > 0) { 480 mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; 481 if (mLocked.pointerAlpha >= 1.0f) { 482 mLocked.pointerAlpha = 1.0f; 483 mLocked.pointerFadeDirection = 0; 484 } else { 485 keepAnimating = true; 486 } 487 updatePointerLocked(); 488 } 489 490 // Animate spots that are fading out and being removed. 491 for (size_t i = 0; i < mLocked.spots.size(); i++) { 492 Spot* spot = mLocked.spots.itemAt(i); 493 if (spot->id == Spot::INVALID_ID) { 494 spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; 495 if (spot->alpha <= 0) { 496 mLocked.spots.removeAt(i--); 497 releaseSpotLocked(spot); 498 } else { 499 spot->sprite->setAlpha(spot->alpha); 500 keepAnimating = true; 501 } 502 } 503 } 504 505 if (keepAnimating) { 506 startAnimationLocked(); 507 } 508} 509 510void PointerController::doInactivityTimeout() { 511 fade(TRANSITION_GRADUAL); 512} 513 514void PointerController::startAnimationLocked() { 515 if (!mLocked.animationPending) { 516 mLocked.animationPending = true; 517 mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); 518 mDisplayEventReceiver.requestNextVsync(); 519 } 520} 521 522void PointerController::resetInactivityTimeoutLocked() { 523 mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); 524 525 nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT 526 ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; 527 mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); 528} 529 530void PointerController::removeInactivityTimeoutLocked() { 531 mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); 532} 533 534void PointerController::updatePointerLocked() { 535 mSpriteController->openTransaction(); 536 537 mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); 538 mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); 539 540 if (mLocked.pointerAlpha > 0) { 541 mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); 542 mLocked.pointerSprite->setVisible(true); 543 } else { 544 mLocked.pointerSprite->setVisible(false); 545 } 546 547 if (mLocked.pointerIconChanged || mLocked.presentationChanged) { 548 if (mLocked.presentation == PRESENTATION_POINTER) { 549 if (mLocked.requestedPointerShape == mPolicy->getDefaultPointerIconId()) { 550 mLocked.pointerSprite->setIcon(mLocked.pointerIcon); 551 } else { 552 std::map<int, SpriteIcon>::const_iterator iter = 553 mLocked.additionalMouseResources.find(mLocked.requestedPointerShape); 554 if (iter != mLocked.additionalMouseResources.end()) { 555 mLocked.pointerSprite->setIcon(iter->second); 556 } else { 557 ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerShape); 558 mLocked.pointerSprite->setIcon(mLocked.pointerIcon); 559 } 560 } 561 } else { 562 mLocked.pointerSprite->setIcon(mResources.spotAnchor); 563 } 564 mLocked.pointerIconChanged = false; 565 mLocked.presentationChanged = false; 566 } 567 568 mSpriteController->closeTransaction(); 569} 570 571PointerController::Spot* PointerController::getSpotLocked(uint32_t id) { 572 for (size_t i = 0; i < mLocked.spots.size(); i++) { 573 Spot* spot = mLocked.spots.itemAt(i); 574 if (spot->id == id) { 575 return spot; 576 } 577 } 578 return NULL; 579} 580 581PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) { 582 // Remove spots until we have fewer than MAX_SPOTS remaining. 583 while (mLocked.spots.size() >= MAX_SPOTS) { 584 Spot* spot = removeFirstFadingSpotLocked(); 585 if (!spot) { 586 spot = mLocked.spots.itemAt(0); 587 mLocked.spots.removeAt(0); 588 } 589 releaseSpotLocked(spot); 590 } 591 592 // Obtain a sprite from the recycled pool. 593 sp<Sprite> sprite; 594 if (! mLocked.recycledSprites.isEmpty()) { 595 sprite = mLocked.recycledSprites.top(); 596 mLocked.recycledSprites.pop(); 597 } else { 598 sprite = mSpriteController->createSprite(); 599 } 600 601 // Return the new spot. 602 Spot* spot = new Spot(id, sprite); 603 mLocked.spots.push(spot); 604 return spot; 605} 606 607PointerController::Spot* PointerController::removeFirstFadingSpotLocked() { 608 for (size_t i = 0; i < mLocked.spots.size(); i++) { 609 Spot* spot = mLocked.spots.itemAt(i); 610 if (spot->id == Spot::INVALID_ID) { 611 mLocked.spots.removeAt(i); 612 return spot; 613 } 614 } 615 return NULL; 616} 617 618void PointerController::releaseSpotLocked(Spot* spot) { 619 spot->sprite->clearIcon(); 620 621 if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { 622 mLocked.recycledSprites.push(spot->sprite); 623 } 624 625 delete spot; 626} 627 628void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { 629 if (spot->id != Spot::INVALID_ID) { 630 spot->id = Spot::INVALID_ID; 631 startAnimationLocked(); 632 } 633} 634 635void PointerController::fadeOutAndReleaseAllSpotsLocked() { 636 for (size_t i = 0; i < mLocked.spots.size(); i++) { 637 Spot* spot = mLocked.spots.itemAt(i); 638 fadeOutAndReleaseSpotLocked(spot); 639 } 640} 641 642void PointerController::loadResources() { 643 mPolicy->loadPointerResources(&mResources); 644} 645 646 647// --- PointerController::Spot --- 648 649void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) { 650 sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); 651 sprite->setAlpha(alpha); 652 sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); 653 sprite->setPosition(x, y); 654 655 this->x = x; 656 this->y = y; 657 658 if (icon != lastIcon) { 659 lastIcon = icon; 660 if (icon) { 661 sprite->setIcon(*icon); 662 sprite->setVisible(true); 663 } else { 664 sprite->setVisible(false); 665 } 666 } 667} 668 669} // namespace android 670