blob: c7430ceead41c245a9b894ba02d86db935e5b95f [file] [log] [blame]
Liam Harringtonc782be62020-07-17 19:48:24 +00001/*
2 * Copyright (C) 2020 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 "TouchSpotController"
18
19// Log debug messages about pointer updates
20#define DEBUG_SPOT_UPDATES 0
21
22#include "TouchSpotController.h"
23
24#include <log/log.h>
25
26#include <SkBitmap.h>
27#include <SkBlendMode.h>
28#include <SkCanvas.h>
29#include <SkColor.h>
30#include <SkPaint.h>
31
32namespace {
33// Time to spend fading out the spot completely.
34const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
35} // namespace
36
37namespace android {
38
39// --- Spot ---
40
41void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float x, float y,
42 int32_t displayId) {
43 sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
44 sprite->setAlpha(alpha);
45 sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
46 sprite->setPosition(x, y);
47 sprite->setDisplayId(displayId);
48 this->x = x;
49 this->y = y;
50
51 if (icon != mLastIcon) {
52 mLastIcon = icon;
53 if (icon) {
54 sprite->setIcon(*icon);
55 sprite->setVisible(true);
56 } else {
57 sprite->setVisible(false);
58 }
59 }
60}
61
62// --- TouchSpotController ---
63
64TouchSpotController::TouchSpotController(int32_t displayId, PointerControllerContext& context)
65 : mDisplayId(displayId), mContext(context) {
66 mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
67}
68
69TouchSpotController::~TouchSpotController() {
70 std::scoped_lock lock(mLock);
71
72 size_t numSpots = mLocked.displaySpots.size();
73 for (size_t i = 0; i < numSpots; i++) {
74 delete mLocked.displaySpots[i];
75 }
76 mLocked.displaySpots.clear();
77}
78
79void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
80 BitSet32 spotIdBits) {
81#if DEBUG_SPOT_UPDATES
82 ALOGD("setSpots: idBits=%08x", spotIdBits.value);
83 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
84 uint32_t id = idBits.firstMarkedBit();
85 idBits.clearBit(id);
86 const PointerCoords& c = spotCoords[spotIdToIndex[id]];
87 ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
88 c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y),
89 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), displayId);
90 }
91#endif
92
93 std::scoped_lock lock(mLock);
94 sp<SpriteController> spriteController = mContext.getSpriteController();
95 spriteController->openTransaction();
96
97 // Add or move spots for fingers that are down.
98 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
99 uint32_t id = idBits.clearFirstMarkedBit();
100 const PointerCoords& c = spotCoords[spotIdToIndex[id]];
101 const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
102 ? mResources.spotTouch
103 : mResources.spotHover;
104 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
105 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
106
107 Spot* spot = getSpot(id, mLocked.displaySpots);
108 if (!spot) {
109 spot = createAndAddSpotLocked(id, mLocked.displaySpots);
110 }
111
112 spot->updateSprite(&icon, x, y, mDisplayId);
113 }
114
115 for (Spot* spot : mLocked.displaySpots) {
116 if (spot->id != Spot::INVALID_ID && !spotIdBits.hasBit(spot->id)) {
117 fadeOutAndReleaseSpotLocked(spot);
118 }
119 }
120
121 spriteController->closeTransaction();
122}
123
124void TouchSpotController::clearSpots() {
125#if DEBUG_SPOT_UPDATES
126 ALOGD("clearSpots");
127#endif
128
129 std::scoped_lock lock(mLock);
130 fadeOutAndReleaseAllSpotsLocked();
131}
132
133TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
134 const std::vector<Spot*>& spots) {
135 for (size_t i = 0; i < spots.size(); i++) {
136 Spot* spot = spots[i];
137 if (spot->id == id) {
138 return spot;
139 }
140 }
141 return nullptr;
142}
143
144TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
145 std::vector<Spot*>& spots) {
146 // Remove spots until we have fewer than MAX_SPOTS remaining.
147 while (spots.size() >= MAX_SPOTS) {
148 Spot* spot = removeFirstFadingSpotLocked(spots);
149 if (!spot) {
150 spot = spots[0];
151 spots.erase(spots.begin());
152 }
153 releaseSpotLocked(spot);
154 }
155
156 // Obtain a sprite from the recycled pool.
157 sp<Sprite> sprite;
158 if (!mLocked.recycledSprites.empty()) {
159 sprite = mLocked.recycledSprites.back();
160 mLocked.recycledSprites.pop_back();
161 } else {
162 sprite = mContext.getSpriteController()->createSprite();
163 }
164
165 // Return the new spot.
166 Spot* spot = new Spot(id, sprite);
167 spots.push_back(spot);
168 return spot;
169}
170
171TouchSpotController::Spot* TouchSpotController::removeFirstFadingSpotLocked(
172 std::vector<Spot*>& spots) REQUIRES(mLock) {
173 for (size_t i = 0; i < spots.size(); i++) {
174 Spot* spot = spots[i];
175 if (spot->id == Spot::INVALID_ID) {
176 spots.erase(spots.begin() + i);
177 return spot;
178 }
179 }
180 return NULL;
181}
182
183void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
184 spot->sprite->clearIcon();
185
186 if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
187 mLocked.recycledSprites.push_back(spot->sprite);
188 }
189
190 delete spot;
191}
192
193void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
194 if (spot->id != Spot::INVALID_ID) {
195 spot->id = Spot::INVALID_ID;
196 mContext.startAnimation();
197 }
198}
199
200void TouchSpotController::fadeOutAndReleaseAllSpotsLocked() REQUIRES(mLock) {
201 size_t numSpots = mLocked.displaySpots.size();
202 for (size_t i = 0; i < numSpots; i++) {
203 Spot* spot = mLocked.displaySpots[i];
204 fadeOutAndReleaseSpotLocked(spot);
205 }
206}
207
208void TouchSpotController::reloadSpotResources() {
209 mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
210}
211
212bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) {
213 std::scoped_lock lock(mLock);
214 nsecs_t animationTime = mContext.getAnimationTime();
215 nsecs_t frameDelay = timestamp - animationTime;
216 size_t numSpots = mLocked.displaySpots.size();
217 for (size_t i = 0; i < numSpots;) {
218 Spot* spot = mLocked.displaySpots[i];
219 if (spot->id == Spot::INVALID_ID) {
220 spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
221 if (spot->alpha <= 0) {
222 mLocked.displaySpots.erase(mLocked.displaySpots.begin() + i);
223 releaseSpotLocked(spot);
224 numSpots--;
225 continue;
226 } else {
227 spot->sprite->setAlpha(spot->alpha);
228 keepAnimating = true;
229 }
230 }
231 ++i;
232 }
233 return keepAnimating;
234}
235
236} // namespace android