PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/input/PointerController.cpp

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