blob: b8de919fbd8c8fa32a6724b4344d8df00c5feafb [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
Michael Wright20f5fd82022-10-28 14:12:24 +010024#include <android-base/stringprintf.h>
25#include <input/PrintTools.h>
Liam Harringtonc782be62020-07-17 19:48:24 +000026#include <log/log.h>
27
Michael Wright20f5fd82022-10-28 14:12:24 +010028#include <mutex>
29
30#define INDENT " "
31#define INDENT2 " "
32
Liam Harringtonc782be62020-07-17 19:48:24 +000033namespace {
34// Time to spend fading out the spot completely.
35const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
36} // namespace
37
38namespace android {
39
40// --- Spot ---
41
Prabir Pradhan4cc1a632023-06-09 21:31:26 +000042void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float newX, float newY,
Liam Harringtonc782be62020-07-17 19:48:24 +000043 int32_t displayId) {
44 sprite->setLayer(Sprite::BASE_LAYER_SPOT + id);
45 sprite->setAlpha(alpha);
46 sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale));
Prabir Pradhan4cc1a632023-06-09 21:31:26 +000047 sprite->setPosition(newX, newY);
Liam Harringtonc782be62020-07-17 19:48:24 +000048 sprite->setDisplayId(displayId);
Prabir Pradhan4cc1a632023-06-09 21:31:26 +000049 x = newX;
50 y = newY;
Liam Harringtonc782be62020-07-17 19:48:24 +000051
52 if (icon != mLastIcon) {
53 mLastIcon = icon;
54 if (icon) {
55 sprite->setIcon(*icon);
56 sprite->setVisible(true);
57 } else {
58 sprite->setVisible(false);
59 }
60 }
61}
62
Michael Wright20f5fd82022-10-28 14:12:24 +010063void TouchSpotController::Spot::dump(std::string& out, const char* prefix) const {
64 out += prefix;
65 base::StringAppendF(&out, "Spot{id=%" PRIx32 ", alpha=%f, scale=%f, pos=[%f, %f]}\n", id, alpha,
66 scale, x, y);
67}
68
Liam Harringtonc782be62020-07-17 19:48:24 +000069// --- TouchSpotController ---
70
71TouchSpotController::TouchSpotController(int32_t displayId, PointerControllerContext& context)
72 : mDisplayId(displayId), mContext(context) {
73 mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
74}
75
76TouchSpotController::~TouchSpotController() {
77 std::scoped_lock lock(mLock);
78
79 size_t numSpots = mLocked.displaySpots.size();
80 for (size_t i = 0; i < numSpots; i++) {
81 delete mLocked.displaySpots[i];
82 }
83 mLocked.displaySpots.clear();
84}
85
86void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
87 BitSet32 spotIdBits) {
88#if DEBUG_SPOT_UPDATES
89 ALOGD("setSpots: idBits=%08x", spotIdBits.value);
90 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
91 uint32_t id = idBits.firstMarkedBit();
92 idBits.clearBit(id);
93 const PointerCoords& c = spotCoords[spotIdToIndex[id]];
94 ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
95 c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y),
96 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), displayId);
97 }
98#endif
99
100 std::scoped_lock lock(mLock);
Prabir Pradhan27c6d992023-08-18 19:44:55 +0000101 auto& spriteController = mContext.getSpriteController();
102 spriteController.openTransaction();
Liam Harringtonc782be62020-07-17 19:48:24 +0000103
104 // Add or move spots for fingers that are down.
105 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
106 uint32_t id = idBits.clearFirstMarkedBit();
107 const PointerCoords& c = spotCoords[spotIdToIndex[id]];
108 const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
109 ? mResources.spotTouch
110 : mResources.spotHover;
111 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
112 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
113
114 Spot* spot = getSpot(id, mLocked.displaySpots);
115 if (!spot) {
116 spot = createAndAddSpotLocked(id, mLocked.displaySpots);
117 }
118
119 spot->updateSprite(&icon, x, y, mDisplayId);
120 }
121
122 for (Spot* spot : mLocked.displaySpots) {
123 if (spot->id != Spot::INVALID_ID && !spotIdBits.hasBit(spot->id)) {
124 fadeOutAndReleaseSpotLocked(spot);
125 }
126 }
127
Prabir Pradhan27c6d992023-08-18 19:44:55 +0000128 spriteController.closeTransaction();
Liam Harringtonc782be62020-07-17 19:48:24 +0000129}
130
131void TouchSpotController::clearSpots() {
132#if DEBUG_SPOT_UPDATES
133 ALOGD("clearSpots");
134#endif
135
136 std::scoped_lock lock(mLock);
137 fadeOutAndReleaseAllSpotsLocked();
138}
139
140TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
141 const std::vector<Spot*>& spots) {
142 for (size_t i = 0; i < spots.size(); i++) {
143 Spot* spot = spots[i];
144 if (spot->id == id) {
145 return spot;
146 }
147 }
148 return nullptr;
149}
150
151TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
Liam Harringtonce637132020-08-14 04:00:11 +0000152 std::vector<Spot*>& spots)
153 REQUIRES(mLock) {
Liam Harringtonc782be62020-07-17 19:48:24 +0000154 // Remove spots until we have fewer than MAX_SPOTS remaining.
155 while (spots.size() >= MAX_SPOTS) {
156 Spot* spot = removeFirstFadingSpotLocked(spots);
157 if (!spot) {
158 spot = spots[0];
159 spots.erase(spots.begin());
160 }
161 releaseSpotLocked(spot);
162 }
163
164 // Obtain a sprite from the recycled pool.
165 sp<Sprite> sprite;
166 if (!mLocked.recycledSprites.empty()) {
167 sprite = mLocked.recycledSprites.back();
168 mLocked.recycledSprites.pop_back();
169 } else {
Prabir Pradhan27c6d992023-08-18 19:44:55 +0000170 sprite = mContext.getSpriteController().createSprite();
Liam Harringtonc782be62020-07-17 19:48:24 +0000171 }
172
173 // Return the new spot.
174 Spot* spot = new Spot(id, sprite);
175 spots.push_back(spot);
176 return spot;
177}
178
179TouchSpotController::Spot* TouchSpotController::removeFirstFadingSpotLocked(
180 std::vector<Spot*>& spots) REQUIRES(mLock) {
181 for (size_t i = 0; i < spots.size(); i++) {
182 Spot* spot = spots[i];
183 if (spot->id == Spot::INVALID_ID) {
184 spots.erase(spots.begin() + i);
185 return spot;
186 }
187 }
188 return NULL;
189}
190
191void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
192 spot->sprite->clearIcon();
193
194 if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
195 mLocked.recycledSprites.push_back(spot->sprite);
196 }
Liam Harringtonc782be62020-07-17 19:48:24 +0000197 delete spot;
198}
199
200void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
201 if (spot->id != Spot::INVALID_ID) {
202 spot->id = Spot::INVALID_ID;
Liam Harringtonce637132020-08-14 04:00:11 +0000203 startAnimationLocked();
Liam Harringtonc782be62020-07-17 19:48:24 +0000204 }
205}
206
207void TouchSpotController::fadeOutAndReleaseAllSpotsLocked() REQUIRES(mLock) {
208 size_t numSpots = mLocked.displaySpots.size();
209 for (size_t i = 0; i < numSpots; i++) {
210 Spot* spot = mLocked.displaySpots[i];
211 fadeOutAndReleaseSpotLocked(spot);
212 }
213}
214
215void TouchSpotController::reloadSpotResources() {
216 mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
217}
218
Liam Harringtonce637132020-08-14 04:00:11 +0000219bool TouchSpotController::doAnimations(nsecs_t timestamp) {
Liam Harringtonc782be62020-07-17 19:48:24 +0000220 std::scoped_lock lock(mLock);
Liam Harringtonce637132020-08-14 04:00:11 +0000221 bool keepAnimating = doFadingAnimationLocked(timestamp);
222 if (!keepAnimating) {
223 /*
224 * We know that this callback will be removed before another
225 * is added. mLock in PointerAnimator will not be released
226 * until after this is removed, and adding another callback
227 * requires that lock. Thus it's safe to set mLocked.animating
228 * here.
229 */
230 mLocked.animating = false;
231 }
232 return keepAnimating;
233}
234
235bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
236 bool keepAnimating = false;
Liam Harringtonc782be62020-07-17 19:48:24 +0000237 nsecs_t animationTime = mContext.getAnimationTime();
238 nsecs_t frameDelay = timestamp - animationTime;
239 size_t numSpots = mLocked.displaySpots.size();
240 for (size_t i = 0; i < numSpots;) {
241 Spot* spot = mLocked.displaySpots[i];
242 if (spot->id == Spot::INVALID_ID) {
243 spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
244 if (spot->alpha <= 0) {
245 mLocked.displaySpots.erase(mLocked.displaySpots.begin() + i);
246 releaseSpotLocked(spot);
247 numSpots--;
248 continue;
249 } else {
250 spot->sprite->setAlpha(spot->alpha);
251 keepAnimating = true;
252 }
253 }
254 ++i;
255 }
256 return keepAnimating;
257}
258
Liam Harringtonce637132020-08-14 04:00:11 +0000259void TouchSpotController::startAnimationLocked() REQUIRES(mLock) {
260 using namespace std::placeholders;
261
262 if (mLocked.animating) {
263 return;
264 }
265 mLocked.animating = true;
266
267 std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1);
268 mContext.addAnimationCallback(mDisplayId, func);
269}
270
Michael Wright20f5fd82022-10-28 14:12:24 +0100271void TouchSpotController::dump(std::string& out, const char* prefix) const {
272 using base::StringAppendF;
273 out += prefix;
274 out += "SpotController:\n";
275 out += prefix;
276 StringAppendF(&out, INDENT "DisplayId: %" PRId32 "\n", mDisplayId);
277 std::scoped_lock lock(mLock);
278 out += prefix;
279 StringAppendF(&out, INDENT "Animating: %s\n", toString(mLocked.animating));
280 out += prefix;
281 out += INDENT "Spots:\n";
282 std::string spotPrefix = prefix;
283 spotPrefix += INDENT2;
284 for (const auto& spot : mLocked.displaySpots) {
285 spot->dump(out, spotPrefix.c_str());
286 }
287}
288
Liam Harringtonc782be62020-07-17 19:48:24 +0000289} // namespace android