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