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