PageRenderTime 64ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/widget/gonk/libui/PointerController.cpp

https://bitbucket.org/soko/mozilla-central
C++ | 615 lines | 461 code | 112 blank | 42 comment | 87 complexity | 0dad1e7051805e7721602dc1078e1e76 MD5 | raw file
Possible License(s): GPL-2.0, JSON, 0BSD, LGPL-3.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.1, Apache-2.0
  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. #include <SkBitmap.h>
  23. #include <SkCanvas.h>
  24. #include <SkColor.h>
  25. #include <SkPaint.h>
  26. #include <SkXfermode.h>
  27. namespace android {
  28. // --- PointerController ---
  29. // Time to wait before starting the fade when the pointer is inactive.
  30. static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
  31. static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
  32. // Time to wait between animation frames.
  33. static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60;
  34. // Time to spend fading out the spot completely.
  35. static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
  36. // Time to spend fading out the pointer completely.
  37. static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
  38. // --- PointerController ---
  39. PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
  40. const sp<Looper>& looper, const sp<SpriteController>& spriteController) :
  41. mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
  42. #ifdef HAVE_ANDROID_OS
  43. mHandler = new WeakMessageHandler(this);
  44. #endif
  45. AutoMutex _l(mLock);
  46. mLocked.animationPending = false;
  47. mLocked.displayWidth = -1;
  48. mLocked.displayHeight = -1;
  49. mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
  50. mLocked.presentation = PRESENTATION_POINTER;
  51. mLocked.presentationChanged = false;
  52. mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL;
  53. mLocked.pointerFadeDirection = 0;
  54. mLocked.pointerX = 0;
  55. mLocked.pointerY = 0;
  56. mLocked.pointerAlpha = 0.0f; // pointer is initially faded
  57. mLocked.pointerSprite = mSpriteController->createSprite();
  58. mLocked.pointerIconChanged = false;
  59. mLocked.buttonState = 0;
  60. loadResources();
  61. }
  62. PointerController::~PointerController() {
  63. #ifdef HAVE_ANDROID_OS
  64. mLooper->removeMessages(mHandler);
  65. #endif
  66. AutoMutex _l(mLock);
  67. mLocked.pointerSprite.clear();
  68. for (size_t i = 0; i < mLocked.spots.size(); i++) {
  69. delete mLocked.spots.itemAt(i);
  70. }
  71. mLocked.spots.clear();
  72. mLocked.recycledSprites.clear();
  73. }
  74. bool PointerController::getBounds(float* outMinX, float* outMinY,
  75. float* outMaxX, float* outMaxY) const {
  76. AutoMutex _l(mLock);
  77. return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY);
  78. }
  79. bool PointerController::getBoundsLocked(float* outMinX, float* outMinY,
  80. float* outMaxX, float* outMaxY) const {
  81. if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) {
  82. return false;
  83. }
  84. *outMinX = 0;
  85. *outMinY = 0;
  86. switch (mLocked.displayOrientation) {
  87. case DISPLAY_ORIENTATION_90:
  88. case DISPLAY_ORIENTATION_270:
  89. *outMaxX = mLocked.displayHeight - 1;
  90. *outMaxY = mLocked.displayWidth - 1;
  91. break;
  92. default:
  93. *outMaxX = mLocked.displayWidth - 1;
  94. *outMaxY = mLocked.displayHeight - 1;
  95. break;
  96. }
  97. return true;
  98. }
  99. void PointerController::move(float deltaX, float deltaY) {
  100. #if DEBUG_POINTER_UPDATES
  101. ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
  102. #endif
  103. if (deltaX == 0.0f && deltaY == 0.0f) {
  104. return;
  105. }
  106. AutoMutex _l(mLock);
  107. setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
  108. }
  109. void PointerController::setButtonState(int32_t buttonState) {
  110. #if DEBUG_POINTER_UPDATES
  111. ALOGD("Set button state 0x%08x", buttonState);
  112. #endif
  113. AutoMutex _l(mLock);
  114. if (mLocked.buttonState != buttonState) {
  115. mLocked.buttonState = buttonState;
  116. }
  117. }
  118. int32_t PointerController::getButtonState() const {
  119. AutoMutex _l(mLock);
  120. return mLocked.buttonState;
  121. }
  122. void PointerController::setPosition(float x, float y) {
  123. #if DEBUG_POINTER_UPDATES
  124. ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y);
  125. #endif
  126. AutoMutex _l(mLock);
  127. setPositionLocked(x, y);
  128. }
  129. void PointerController::setPositionLocked(float x, float y) {
  130. float minX, minY, maxX, maxY;
  131. if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
  132. if (x <= minX) {
  133. mLocked.pointerX = minX;
  134. } else if (x >= maxX) {
  135. mLocked.pointerX = maxX;
  136. } else {
  137. mLocked.pointerX = x;
  138. }
  139. if (y <= minY) {
  140. mLocked.pointerY = minY;
  141. } else if (y >= maxY) {
  142. mLocked.pointerY = maxY;
  143. } else {
  144. mLocked.pointerY = y;
  145. }
  146. updatePointerLocked();
  147. }
  148. }
  149. void PointerController::getPosition(float* outX, float* outY) const {
  150. AutoMutex _l(mLock);
  151. *outX = mLocked.pointerX;
  152. *outY = mLocked.pointerY;
  153. }
  154. void PointerController::fade(Transition transition) {
  155. AutoMutex _l(mLock);
  156. // Remove the inactivity timeout, since we are fading now.
  157. removeInactivityTimeoutLocked();
  158. // Start fading.
  159. if (transition == TRANSITION_IMMEDIATE) {
  160. mLocked.pointerFadeDirection = 0;
  161. mLocked.pointerAlpha = 0.0f;
  162. updatePointerLocked();
  163. } else {
  164. mLocked.pointerFadeDirection = -1;
  165. startAnimationLocked();
  166. }
  167. }
  168. void PointerController::unfade(Transition transition) {
  169. AutoMutex _l(mLock);
  170. // Always reset the inactivity timer.
  171. resetInactivityTimeoutLocked();
  172. // Start unfading.
  173. if (transition == TRANSITION_IMMEDIATE) {
  174. mLocked.pointerFadeDirection = 0;
  175. mLocked.pointerAlpha = 1.0f;
  176. updatePointerLocked();
  177. } else {
  178. mLocked.pointerFadeDirection = 1;
  179. startAnimationLocked();
  180. }
  181. }
  182. void PointerController::setPresentation(Presentation presentation) {
  183. AutoMutex _l(mLock);
  184. if (mLocked.presentation != presentation) {
  185. mLocked.presentation = presentation;
  186. mLocked.presentationChanged = true;
  187. if (presentation != PRESENTATION_SPOT) {
  188. fadeOutAndReleaseAllSpotsLocked();
  189. }
  190. updatePointerLocked();
  191. }
  192. }
  193. void PointerController::setSpots(const PointerCoords* spotCoords,
  194. const uint32_t* spotIdToIndex, BitSet32 spotIdBits) {
  195. #if DEBUG_POINTER_UPDATES
  196. ALOGD("setSpots: idBits=%08x", spotIdBits.value);
  197. for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
  198. uint32_t id = idBits.firstMarkedBit();
  199. idBits.clearBit(id);
  200. const PointerCoords& c = spotCoords[spotIdToIndex[id]];
  201. ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id,
  202. c.getAxisValue(AMOTION_EVENT_AXIS_X),
  203. c.getAxisValue(AMOTION_EVENT_AXIS_Y),
  204. c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
  205. }
  206. #endif
  207. AutoMutex _l(mLock);
  208. mSpriteController->openTransaction();
  209. // Add or move spots for fingers that are down.
  210. for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
  211. uint32_t id = idBits.clearFirstMarkedBit();
  212. const PointerCoords& c = spotCoords[spotIdToIndex[id]];
  213. const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
  214. ? mResources.spotTouch : mResources.spotHover;
  215. float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
  216. float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
  217. Spot* spot = getSpotLocked(id);
  218. if (!spot) {
  219. spot = createAndAddSpotLocked(id);
  220. }
  221. spot->updateSprite(&icon, x, y);
  222. }
  223. // Remove spots for fingers that went up.
  224. for (size_t i = 0; i < mLocked.spots.size(); i++) {
  225. Spot* spot = mLocked.spots.itemAt(i);
  226. if (spot->id != Spot::INVALID_ID
  227. && !spotIdBits.hasBit(spot->id)) {
  228. fadeOutAndReleaseSpotLocked(spot);
  229. }
  230. }
  231. mSpriteController->closeTransaction();
  232. }
  233. void PointerController::clearSpots() {
  234. #if DEBUG_POINTER_UPDATES
  235. ALOGD("clearSpots");
  236. #endif
  237. AutoMutex _l(mLock);
  238. fadeOutAndReleaseAllSpotsLocked();
  239. }
  240. void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) {
  241. AutoMutex _l(mLock);
  242. if (mLocked.inactivityTimeout != inactivityTimeout) {
  243. mLocked.inactivityTimeout = inactivityTimeout;
  244. resetInactivityTimeoutLocked();
  245. }
  246. }
  247. void PointerController::setDisplaySize(int32_t width, int32_t height) {
  248. AutoMutex _l(mLock);
  249. if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
  250. mLocked.displayWidth = width;
  251. mLocked.displayHeight = height;
  252. float minX, minY, maxX, maxY;
  253. if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
  254. mLocked.pointerX = (minX + maxX) * 0.5f;
  255. mLocked.pointerY = (minY + maxY) * 0.5f;
  256. } else {
  257. mLocked.pointerX = 0;
  258. mLocked.pointerY = 0;
  259. }
  260. fadeOutAndReleaseAllSpotsLocked();
  261. updatePointerLocked();
  262. }
  263. }
  264. void PointerController::setDisplayOrientation(int32_t orientation) {
  265. AutoMutex _l(mLock);
  266. if (mLocked.displayOrientation != orientation) {
  267. // Apply offsets to convert from the pixel top-left corner position to the pixel center.
  268. // This creates an invariant frame of reference that we can easily rotate when
  269. // taking into account that the pointer may be located at fractional pixel offsets.
  270. float x = mLocked.pointerX + 0.5f;
  271. float y = mLocked.pointerY + 0.5f;
  272. float temp;
  273. // Undo the previous rotation.
  274. switch (mLocked.displayOrientation) {
  275. case DISPLAY_ORIENTATION_90:
  276. temp = x;
  277. x = mLocked.displayWidth - y;
  278. y = temp;
  279. break;
  280. case DISPLAY_ORIENTATION_180:
  281. x = mLocked.displayWidth - x;
  282. y = mLocked.displayHeight - y;
  283. break;
  284. case DISPLAY_ORIENTATION_270:
  285. temp = x;
  286. x = y;
  287. y = mLocked.displayHeight - temp;
  288. break;
  289. }
  290. // Perform the new rotation.
  291. switch (orientation) {
  292. case DISPLAY_ORIENTATION_90:
  293. temp = x;
  294. x = y;
  295. y = mLocked.displayWidth - temp;
  296. break;
  297. case DISPLAY_ORIENTATION_180:
  298. x = mLocked.displayWidth - x;
  299. y = mLocked.displayHeight - y;
  300. break;
  301. case DISPLAY_ORIENTATION_270:
  302. temp = x;
  303. x = mLocked.displayHeight - y;
  304. y = temp;
  305. break;
  306. }
  307. // Apply offsets to convert from the pixel center to the pixel top-left corner position
  308. // and save the results.
  309. mLocked.pointerX = x - 0.5f;
  310. mLocked.pointerY = y - 0.5f;
  311. mLocked.displayOrientation = orientation;
  312. updatePointerLocked();
  313. }
  314. }
  315. void PointerController::setPointerIcon(const SpriteIcon& icon) {
  316. AutoMutex _l(mLock);
  317. mLocked.pointerIcon = icon.copy();
  318. mLocked.pointerIconChanged = true;
  319. updatePointerLocked();
  320. }
  321. #ifdef HAVE_ANDROID_OS
  322. void PointerController::handleMessage(const Message& message) {
  323. switch (message.what) {
  324. case MSG_ANIMATE:
  325. doAnimate();
  326. break;
  327. case MSG_INACTIVITY_TIMEOUT:
  328. doInactivityTimeout();
  329. break;
  330. }
  331. }
  332. #endif
  333. void PointerController::doAnimate() {
  334. AutoMutex _l(mLock);
  335. bool keepAnimating = false;
  336. mLocked.animationPending = false;
  337. nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;
  338. // Animate pointer fade.
  339. if (mLocked.pointerFadeDirection < 0) {
  340. mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION;
  341. if (mLocked.pointerAlpha <= 0.0f) {
  342. mLocked.pointerAlpha = 0.0f;
  343. mLocked.pointerFadeDirection = 0;
  344. } else {
  345. keepAnimating = true;
  346. }
  347. updatePointerLocked();
  348. } else if (mLocked.pointerFadeDirection > 0) {
  349. mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION;
  350. if (mLocked.pointerAlpha >= 1.0f) {
  351. mLocked.pointerAlpha = 1.0f;
  352. mLocked.pointerFadeDirection = 0;
  353. } else {
  354. keepAnimating = true;
  355. }
  356. updatePointerLocked();
  357. }
  358. // Animate spots that are fading out and being removed.
  359. for (size_t i = 0; i < mLocked.spots.size(); i++) {
  360. Spot* spot = mLocked.spots.itemAt(i);
  361. if (spot->id == Spot::INVALID_ID) {
  362. spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
  363. if (spot->alpha <= 0) {
  364. mLocked.spots.removeAt(i--);
  365. releaseSpotLocked(spot);
  366. } else {
  367. spot->sprite->setAlpha(spot->alpha);
  368. keepAnimating = true;
  369. }
  370. }
  371. }
  372. if (keepAnimating) {
  373. startAnimationLocked();
  374. }
  375. }
  376. void PointerController::doInactivityTimeout() {
  377. fade(TRANSITION_GRADUAL);
  378. }
  379. void PointerController::startAnimationLocked() {
  380. if (!mLocked.animationPending) {
  381. mLocked.animationPending = true;
  382. mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
  383. #ifdef HAVE_ANDROID_OS
  384. mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE));
  385. #endif
  386. }
  387. }
  388. void PointerController::resetInactivityTimeoutLocked() {
  389. #ifdef HAVE_ANDROID_OS
  390. mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
  391. #endif
  392. nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT
  393. ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL;
  394. #ifdef HAVE_ANDROID_OS
  395. mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT);
  396. #endif
  397. }
  398. void PointerController::removeInactivityTimeoutLocked() {
  399. #ifdef HAVE_ANDROID_OS
  400. mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT);
  401. #endif
  402. }
  403. void PointerController::updatePointerLocked() {
  404. mSpriteController->openTransaction();
  405. mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER);
  406. mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY);
  407. if (mLocked.pointerAlpha > 0) {
  408. mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha);
  409. mLocked.pointerSprite->setVisible(true);
  410. } else {
  411. mLocked.pointerSprite->setVisible(false);
  412. }
  413. if (mLocked.pointerIconChanged || mLocked.presentationChanged) {
  414. mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER
  415. ? mLocked.pointerIcon : mResources.spotAnchor);
  416. mLocked.pointerIconChanged = false;
  417. mLocked.presentationChanged = false;
  418. }
  419. mSpriteController->closeTransaction();
  420. }
  421. PointerController::Spot* PointerController::getSpotLocked(uint32_t id) {
  422. for (size_t i = 0; i < mLocked.spots.size(); i++) {
  423. Spot* spot = mLocked.spots.itemAt(i);
  424. if (spot->id == id) {
  425. return spot;
  426. }
  427. }
  428. return NULL;
  429. }
  430. PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) {
  431. // Remove spots until we have fewer than MAX_SPOTS remaining.
  432. while (mLocked.spots.size() >= MAX_SPOTS) {
  433. Spot* spot = removeFirstFadingSpotLocked();
  434. if (!spot) {
  435. spot = mLocked.spots.itemAt(0);
  436. mLocked.spots.removeAt(0);
  437. }
  438. releaseSpotLocked(spot);
  439. }
  440. // Obtain a sprite from the recycled pool.
  441. sp<Sprite> sprite;
  442. if (! mLocked.recycledSprites.isEmpty()) {
  443. sprite = mLocked.recycledSprites.top();
  444. mLocked.recycledSprites.pop();
  445. } else {
  446. sprite = mSpriteController->createSprite();
  447. }
  448. // Return the new spot.
  449. Spot* spot = new Spot(id, sprite);
  450. mLocked.spots.push(spot);
  451. return spot;
  452. }
  453. PointerController::Spot* PointerController::removeFirstFadingSpotLocked() {
  454. for (size_t i = 0; i < mLocked.spots.size(); i++) {
  455. Spot* spot = mLocked.spots.itemAt(i);
  456. if (spot->id == Spot::INVALID_ID) {
  457. mLocked.spots.removeAt(i);
  458. return spot;
  459. }
  460. }
  461. return NULL;
  462. }
  463. void PointerController::releaseSpotLocked(Spot* spot) {
  464. spot->sprite->clearIcon();
  465. if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
  466. mLocked.recycledSprites.push(spot->sprite);
  467. }
  468. delete spot;
  469. }
  470. void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) {
  471. if (spot->id != Spot::INVALID_ID) {
  472. spot->id = Spot::INVALID_ID;
  473. startAnimationLocked();
  474. }
  475. }
  476. void PointerController::fadeOutAndReleaseAllSpotsLocked() {
  477. for (size_t i = 0; i < mLocked.spots.size(); i++) {
  478. Spot* spot = mLocked.spots.itemAt(i);
  479. fadeOutAndReleaseSpotLocked(spot);
  480. }
  481. }
  482. void PointerController::loadResources() {
  483. mPolicy->loadPointerResources(&mResources);
  484. }
  485. // --- PointerController::Spot ---
  486. void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) {
  487. sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
  488. sprite->setAlpha(alpha);
  489. sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
  490. sprite->setPosition(x, y);
  491. this->x = x;
  492. this->y = y;
  493. if (icon != lastIcon) {
  494. lastIcon = icon;
  495. if (icon) {
  496. sprite->setIcon(*icon);
  497. sprite->setVisible(true);
  498. } else {
  499. sprite->setVisible(false);
  500. }
  501. }
  502. }
  503. } // namespace android