blob: 530d5412979198f0a99d79d301a3b02dd5c21c25 [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,
Arpit Singh80fd68a2024-03-26 18:41:06 +000043 int32_t displayId, bool skipScreenshot) {
Liam Harringtonc782be62020-07-17 19:48:24 +000044 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);
Arpit Singh80fd68a2024-03-26 18:41:06 +000049 sprite->setSkipScreenshot(skipScreenshot);
Prabir Pradhan4cc1a632023-06-09 21:31:26 +000050 x = newX;
51 y = newY;
Liam Harringtonc782be62020-07-17 19:48:24 +000052
53 if (icon != mLastIcon) {
54 mLastIcon = icon;
55 if (icon) {
56 sprite->setIcon(*icon);
57 sprite->setVisible(true);
58 } else {
59 sprite->setVisible(false);
60 }
61 }
62}
63
Michael Wright20f5fd82022-10-28 14:12:24 +010064void TouchSpotController::Spot::dump(std::string& out, const char* prefix) const {
65 out += prefix;
66 base::StringAppendF(&out, "Spot{id=%" PRIx32 ", alpha=%f, scale=%f, pos=[%f, %f]}\n", id, alpha,
67 scale, x, y);
68}
69
Liam Harringtonc782be62020-07-17 19:48:24 +000070// --- TouchSpotController ---
71
72TouchSpotController::TouchSpotController(int32_t displayId, PointerControllerContext& context)
73 : mDisplayId(displayId), mContext(context) {
74 mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
75}
76
77TouchSpotController::~TouchSpotController() {
78 std::scoped_lock lock(mLock);
79
80 size_t numSpots = mLocked.displaySpots.size();
81 for (size_t i = 0; i < numSpots; i++) {
82 delete mLocked.displaySpots[i];
83 }
84 mLocked.displaySpots.clear();
85}
86
87void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
Arpit Singh80fd68a2024-03-26 18:41:06 +000088 BitSet32 spotIdBits, bool skipScreenshot) {
Liam Harringtonc782be62020-07-17 19:48:24 +000089#if DEBUG_SPOT_UPDATES
90 ALOGD("setSpots: idBits=%08x", spotIdBits.value);
91 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
92 uint32_t id = idBits.firstMarkedBit();
93 idBits.clearBit(id);
94 const PointerCoords& c = spotCoords[spotIdToIndex[id]];
95 ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id,
96 c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y),
Linnan Li37c1b992023-11-24 13:05:13 +080097 c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), mDisplayId);
Liam Harringtonc782be62020-07-17 19:48:24 +000098 }
99#endif
100
101 std::scoped_lock lock(mLock);
Prabir Pradhan27c6d992023-08-18 19:44:55 +0000102 auto& spriteController = mContext.getSpriteController();
103 spriteController.openTransaction();
Liam Harringtonc782be62020-07-17 19:48:24 +0000104
105 // Add or move spots for fingers that are down.
106 for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) {
107 uint32_t id = idBits.clearFirstMarkedBit();
108 const PointerCoords& c = spotCoords[spotIdToIndex[id]];
109 const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0
110 ? mResources.spotTouch
111 : mResources.spotHover;
112 float x = c.getAxisValue(AMOTION_EVENT_AXIS_X);
113 float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y);
114
115 Spot* spot = getSpot(id, mLocked.displaySpots);
116 if (!spot) {
117 spot = createAndAddSpotLocked(id, mLocked.displaySpots);
118 }
119
Arpit Singh80fd68a2024-03-26 18:41:06 +0000120 spot->updateSprite(&icon, x, y, mDisplayId, skipScreenshot);
Liam Harringtonc782be62020-07-17 19:48:24 +0000121 }
122
123 for (Spot* spot : mLocked.displaySpots) {
124 if (spot->id != Spot::INVALID_ID && !spotIdBits.hasBit(spot->id)) {
125 fadeOutAndReleaseSpotLocked(spot);
126 }
127 }
128
Prabir Pradhan27c6d992023-08-18 19:44:55 +0000129 spriteController.closeTransaction();
Liam Harringtonc782be62020-07-17 19:48:24 +0000130}
131
132void TouchSpotController::clearSpots() {
133#if DEBUG_SPOT_UPDATES
134 ALOGD("clearSpots");
135#endif
136
137 std::scoped_lock lock(mLock);
138 fadeOutAndReleaseAllSpotsLocked();
139}
140
141TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id,
142 const std::vector<Spot*>& spots) {
143 for (size_t i = 0; i < spots.size(); i++) {
144 Spot* spot = spots[i];
145 if (spot->id == id) {
146 return spot;
147 }
148 }
149 return nullptr;
150}
151
152TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id,
Liam Harringtonce637132020-08-14 04:00:11 +0000153 std::vector<Spot*>& spots)
154 REQUIRES(mLock) {
Liam Harringtonc782be62020-07-17 19:48:24 +0000155 // Remove spots until we have fewer than MAX_SPOTS remaining.
156 while (spots.size() >= MAX_SPOTS) {
157 Spot* spot = removeFirstFadingSpotLocked(spots);
158 if (!spot) {
159 spot = spots[0];
160 spots.erase(spots.begin());
161 }
162 releaseSpotLocked(spot);
163 }
164
165 // Obtain a sprite from the recycled pool.
166 sp<Sprite> sprite;
167 if (!mLocked.recycledSprites.empty()) {
168 sprite = mLocked.recycledSprites.back();
169 mLocked.recycledSprites.pop_back();
170 } else {
Prabir Pradhan27c6d992023-08-18 19:44:55 +0000171 sprite = mContext.getSpriteController().createSprite();
Liam Harringtonc782be62020-07-17 19:48:24 +0000172 }
173
174 // Return the new spot.
175 Spot* spot = new Spot(id, sprite);
176 spots.push_back(spot);
177 return spot;
178}
179
180TouchSpotController::Spot* TouchSpotController::removeFirstFadingSpotLocked(
181 std::vector<Spot*>& spots) REQUIRES(mLock) {
182 for (size_t i = 0; i < spots.size(); i++) {
183 Spot* spot = spots[i];
184 if (spot->id == Spot::INVALID_ID) {
185 spots.erase(spots.begin() + i);
186 return spot;
187 }
188 }
189 return NULL;
190}
191
192void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) {
193 spot->sprite->clearIcon();
194
195 if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) {
196 mLocked.recycledSprites.push_back(spot->sprite);
197 }
Liam Harringtonc782be62020-07-17 19:48:24 +0000198 delete spot;
199}
200
201void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) {
202 if (spot->id != Spot::INVALID_ID) {
203 spot->id = Spot::INVALID_ID;
Liam Harringtonce637132020-08-14 04:00:11 +0000204 startAnimationLocked();
Liam Harringtonc782be62020-07-17 19:48:24 +0000205 }
206}
207
208void TouchSpotController::fadeOutAndReleaseAllSpotsLocked() REQUIRES(mLock) {
209 size_t numSpots = mLocked.displaySpots.size();
210 for (size_t i = 0; i < numSpots; i++) {
211 Spot* spot = mLocked.displaySpots[i];
212 fadeOutAndReleaseSpotLocked(spot);
213 }
214}
215
216void TouchSpotController::reloadSpotResources() {
217 mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId);
218}
219
Liam Harringtonce637132020-08-14 04:00:11 +0000220bool TouchSpotController::doAnimations(nsecs_t timestamp) {
Liam Harringtonc782be62020-07-17 19:48:24 +0000221 std::scoped_lock lock(mLock);
Liam Harringtonce637132020-08-14 04:00:11 +0000222 bool keepAnimating = doFadingAnimationLocked(timestamp);
223 if (!keepAnimating) {
224 /*
225 * We know that this callback will be removed before another
226 * is added. mLock in PointerAnimator will not be released
227 * until after this is removed, and adding another callback
228 * requires that lock. Thus it's safe to set mLocked.animating
229 * here.
230 */
231 mLocked.animating = false;
232 }
233 return keepAnimating;
234}
235
236bool TouchSpotController::doFadingAnimationLocked(nsecs_t timestamp) REQUIRES(mLock) {
237 bool keepAnimating = false;
Liam Harringtonc782be62020-07-17 19:48:24 +0000238 nsecs_t animationTime = mContext.getAnimationTime();
239 nsecs_t frameDelay = timestamp - animationTime;
240 size_t numSpots = mLocked.displaySpots.size();
241 for (size_t i = 0; i < numSpots;) {
242 Spot* spot = mLocked.displaySpots[i];
243 if (spot->id == Spot::INVALID_ID) {
244 spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION;
245 if (spot->alpha <= 0) {
246 mLocked.displaySpots.erase(mLocked.displaySpots.begin() + i);
247 releaseSpotLocked(spot);
248 numSpots--;
249 continue;
250 } else {
251 spot->sprite->setAlpha(spot->alpha);
252 keepAnimating = true;
253 }
254 }
255 ++i;
256 }
257 return keepAnimating;
258}
259
Liam Harringtonce637132020-08-14 04:00:11 +0000260void TouchSpotController::startAnimationLocked() REQUIRES(mLock) {
261 using namespace std::placeholders;
262
263 if (mLocked.animating) {
264 return;
265 }
266 mLocked.animating = true;
267
268 std::function<bool(nsecs_t)> func = std::bind(&TouchSpotController::doAnimations, this, _1);
269 mContext.addAnimationCallback(mDisplayId, func);
270}
271
Michael Wright20f5fd82022-10-28 14:12:24 +0100272void TouchSpotController::dump(std::string& out, const char* prefix) const {
273 using base::StringAppendF;
274 out += prefix;
275 out += "SpotController:\n";
276 out += prefix;
277 StringAppendF(&out, INDENT "DisplayId: %" PRId32 "\n", mDisplayId);
278 std::scoped_lock lock(mLock);
279 out += prefix;
280 StringAppendF(&out, INDENT "Animating: %s\n", toString(mLocked.animating));
281 out += prefix;
282 out += INDENT "Spots:\n";
283 std::string spotPrefix = prefix;
284 spotPrefix += INDENT2;
285 for (const auto& spot : mLocked.displaySpots) {
286 spot->dump(out, spotPrefix.c_str());
287 }
288}
289
Liam Harringtonc782be62020-07-17 19:48:24 +0000290} // namespace android