1 /*
2 * Copyright (C) 2022 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 #include "TouchedWindow.h"
18
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <input/PrintTools.h>
22
23 using android::base::Result;
24 using android::base::StringPrintf;
25
26 namespace android {
27
28 namespace inputdispatcher {
29
30 namespace {
31
hasPointerId(const std::vector<PointerProperties> & pointers,int32_t pointerId)32 bool hasPointerId(const std::vector<PointerProperties>& pointers, int32_t pointerId) {
33 return std::find_if(pointers.begin(), pointers.end(),
34 [&pointerId](const PointerProperties& properties) {
35 return properties.id == pointerId;
36 }) != pointers.end();
37 }
38
39 } // namespace
40
hasHoveringPointers() const41 bool TouchedWindow::hasHoveringPointers() const {
42 for (const auto& [_, state] : mDeviceStates) {
43 if (!state.hoveringPointers.empty()) {
44 return true;
45 }
46 }
47 return false;
48 }
49
hasHoveringPointers(DeviceId deviceId) const50 bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const {
51 const auto stateIt = mDeviceStates.find(deviceId);
52 if (stateIt == mDeviceStates.end()) {
53 return false;
54 }
55 const DeviceState& state = stateIt->second;
56
57 return !state.hoveringPointers.empty();
58 }
59
clearHoveringPointers(DeviceId deviceId)60 void TouchedWindow::clearHoveringPointers(DeviceId deviceId) {
61 auto stateIt = mDeviceStates.find(deviceId);
62 if (stateIt == mDeviceStates.end()) {
63 return;
64 }
65 DeviceState& state = stateIt->second;
66 state.hoveringPointers.clear();
67 if (!state.hasPointers()) {
68 mDeviceStates.erase(stateIt);
69 }
70 }
71
hasHoveringPointer(DeviceId deviceId,int32_t pointerId) const72 bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const {
73 const auto stateIt = mDeviceStates.find(deviceId);
74 if (stateIt == mDeviceStates.end()) {
75 return false;
76 }
77 const DeviceState& state = stateIt->second;
78 return hasPointerId(state.hoveringPointers, pointerId);
79 }
80
addHoveringPointer(DeviceId deviceId,const PointerProperties & pointer)81 void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer) {
82 std::vector<PointerProperties>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers;
83 const size_t initialSize = hoveringPointers.size();
84 std::erase_if(hoveringPointers, [&pointer](const PointerProperties& properties) {
85 return properties.id == pointer.id;
86 });
87 if (hoveringPointers.size() != initialSize) {
88 LOG(ERROR) << __func__ << ": " << pointer << ", device " << deviceId << " was in " << *this;
89 }
90 hoveringPointers.push_back(pointer);
91 }
92
addTouchingPointers(DeviceId deviceId,const std::vector<PointerProperties> & pointers)93 Result<void> TouchedWindow::addTouchingPointers(DeviceId deviceId,
94 const std::vector<PointerProperties>& pointers) {
95 std::vector<PointerProperties>& touchingPointers = mDeviceStates[deviceId].touchingPointers;
96 const size_t initialSize = touchingPointers.size();
97 for (const PointerProperties& pointer : pointers) {
98 std::erase_if(touchingPointers, [&pointer](const PointerProperties& properties) {
99 return properties.id == pointer.id;
100 });
101 }
102 const bool foundInconsistentState = touchingPointers.size() != initialSize;
103 touchingPointers.insert(touchingPointers.end(), pointers.begin(), pointers.end());
104 if (foundInconsistentState) {
105 LOG(ERROR) << __func__ << ": " << dumpVector(pointers, streamableToString) << ", device "
106 << deviceId << " already in " << *this;
107 return android::base::Error();
108 }
109 return {};
110 }
111
hasTouchingPointers() const112 bool TouchedWindow::hasTouchingPointers() const {
113 for (const auto& [_, state] : mDeviceStates) {
114 if (!state.touchingPointers.empty()) {
115 return true;
116 }
117 }
118 return false;
119 }
120
hasTouchingPointers(DeviceId deviceId) const121 bool TouchedWindow::hasTouchingPointers(DeviceId deviceId) const {
122 return !getTouchingPointers(deviceId).empty();
123 }
124
hasTouchingPointer(DeviceId deviceId,int32_t pointerId) const125 bool TouchedWindow::hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const {
126 const auto stateIt = mDeviceStates.find(deviceId);
127 if (stateIt == mDeviceStates.end()) {
128 return false;
129 }
130 const DeviceState& state = stateIt->second;
131 return hasPointerId(state.touchingPointers, pointerId);
132 }
133
getTouchingPointers(DeviceId deviceId) const134 std::vector<PointerProperties> TouchedWindow::getTouchingPointers(DeviceId deviceId) const {
135 const auto stateIt = mDeviceStates.find(deviceId);
136 if (stateIt == mDeviceStates.end()) {
137 return {};
138 }
139 const DeviceState& state = stateIt->second;
140 return state.touchingPointers;
141 }
142
removeTouchingPointer(DeviceId deviceId,int32_t pointerId)143 void TouchedWindow::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
144 std::bitset<MAX_POINTER_ID + 1> pointerIds;
145 pointerIds.set(pointerId, true);
146
147 removeTouchingPointers(deviceId, pointerIds);
148 }
149
removeTouchingPointers(DeviceId deviceId,std::bitset<MAX_POINTER_ID+1> pointers)150 void TouchedWindow::removeTouchingPointers(DeviceId deviceId,
151 std::bitset<MAX_POINTER_ID + 1> pointers) {
152 const auto stateIt = mDeviceStates.find(deviceId);
153 if (stateIt == mDeviceStates.end()) {
154 return;
155 }
156 DeviceState& state = stateIt->second;
157
158 std::erase_if(state.touchingPointers, [&pointers](const PointerProperties& properties) {
159 return pointers.test(properties.id);
160 });
161
162 state.pilferingPointerIds &= ~pointers;
163
164 if (!state.hasPointers()) {
165 mDeviceStates.erase(stateIt);
166 }
167 }
168
hasActiveStylus() const169 bool TouchedWindow::hasActiveStylus() const {
170 for (const auto& [_, state] : mDeviceStates) {
171 for (const PointerProperties& properties : state.touchingPointers) {
172 if (properties.toolType == ToolType::STYLUS) {
173 return true;
174 }
175 }
176 for (const PointerProperties& properties : state.hoveringPointers) {
177 if (properties.toolType == ToolType::STYLUS) {
178 return true;
179 }
180 }
181 }
182 return false;
183 }
184
getTouchingDeviceIds() const185 std::set<DeviceId> TouchedWindow::getTouchingDeviceIds() const {
186 std::set<DeviceId> deviceIds;
187 for (const auto& [deviceId, deviceState] : mDeviceStates) {
188 if (!deviceState.touchingPointers.empty()) {
189 deviceIds.insert(deviceId);
190 }
191 }
192 return deviceIds;
193 }
194
hasPilferingPointers(DeviceId deviceId) const195 bool TouchedWindow::hasPilferingPointers(DeviceId deviceId) const {
196 const auto stateIt = mDeviceStates.find(deviceId);
197 if (stateIt == mDeviceStates.end()) {
198 return false;
199 }
200 const DeviceState& state = stateIt->second;
201
202 return state.pilferingPointerIds.any();
203 }
204
addPilferingPointers(DeviceId deviceId,std::bitset<MAX_POINTER_ID+1> pointerIds)205 void TouchedWindow::addPilferingPointers(DeviceId deviceId,
206 std::bitset<MAX_POINTER_ID + 1> pointerIds) {
207 mDeviceStates[deviceId].pilferingPointerIds |= pointerIds;
208 }
209
addPilferingPointer(DeviceId deviceId,int32_t pointerId)210 void TouchedWindow::addPilferingPointer(DeviceId deviceId, int32_t pointerId) {
211 mDeviceStates[deviceId].pilferingPointerIds.set(pointerId);
212 }
213
getPilferingPointers(DeviceId deviceId) const214 std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(DeviceId deviceId) const {
215 const auto stateIt = mDeviceStates.find(deviceId);
216 if (stateIt == mDeviceStates.end()) {
217 return {};
218 }
219 const DeviceState& state = stateIt->second;
220
221 return state.pilferingPointerIds;
222 }
223
getPilferingPointers() const224 std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const {
225 std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> out;
226 for (const auto& [deviceId, state] : mDeviceStates) {
227 out.emplace(deviceId, state.pilferingPointerIds);
228 }
229 return out;
230 }
231
getDownTimeInTarget(DeviceId deviceId) const232 std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(DeviceId deviceId) const {
233 const auto stateIt = mDeviceStates.find(deviceId);
234 if (stateIt == mDeviceStates.end()) {
235 return {};
236 }
237 const DeviceState& state = stateIt->second;
238 return state.downTimeInTarget;
239 }
240
trySetDownTimeInTarget(DeviceId deviceId,nsecs_t downTime)241 void TouchedWindow::trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime) {
242 auto [stateIt, _] = mDeviceStates.try_emplace(deviceId);
243 DeviceState& state = stateIt->second;
244
245 if (!state.downTimeInTarget) {
246 state.downTimeInTarget = downTime;
247 }
248 }
249
removeAllTouchingPointersForDevice(DeviceId deviceId)250 void TouchedWindow::removeAllTouchingPointersForDevice(DeviceId deviceId) {
251 const auto stateIt = mDeviceStates.find(deviceId);
252 if (stateIt == mDeviceStates.end()) {
253 return;
254 }
255 DeviceState& state = stateIt->second;
256
257 state.touchingPointers.clear();
258 state.pilferingPointerIds.reset();
259 state.downTimeInTarget.reset();
260
261 if (!state.hasPointers()) {
262 mDeviceStates.erase(stateIt);
263 }
264 }
265
removeHoveringPointer(DeviceId deviceId,int32_t pointerId)266 void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) {
267 const auto stateIt = mDeviceStates.find(deviceId);
268 if (stateIt == mDeviceStates.end()) {
269 return;
270 }
271 DeviceState& state = stateIt->second;
272
273 std::erase_if(state.hoveringPointers, [&pointerId](const PointerProperties& properties) {
274 return properties.id == pointerId;
275 });
276
277 if (!state.hasPointers()) {
278 mDeviceStates.erase(stateIt);
279 }
280 }
281
removeAllHoveringPointersForDevice(DeviceId deviceId)282 void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) {
283 const auto stateIt = mDeviceStates.find(deviceId);
284 if (stateIt == mDeviceStates.end()) {
285 return;
286 }
287 DeviceState& state = stateIt->second;
288
289 state.hoveringPointers.clear();
290
291 if (!state.hasPointers()) {
292 mDeviceStates.erase(stateIt);
293 }
294 }
295
deviceStateToString(const TouchedWindow::DeviceState & state)296 std::string TouchedWindow::deviceStateToString(const TouchedWindow::DeviceState& state) {
297 return StringPrintf("[touchingPointers=%s, "
298 "downTimeInTarget=%s, hoveringPointers=%s, pilferingPointerIds=%s]",
299 dumpVector(state.touchingPointers, streamableToString).c_str(),
300 toString(state.downTimeInTarget).c_str(),
301 dumpVector(state.hoveringPointers, streamableToString).c_str(),
302 bitsetToString(state.pilferingPointerIds).c_str());
303 }
304
dump() const305 std::string TouchedWindow::dump() const {
306 std::string out;
307 std::string deviceStates =
308 dumpMap(mDeviceStates, constToString, TouchedWindow::deviceStateToString);
309 out += StringPrintf("name='%s', targetFlags=%s, mDeviceStates=%s\n",
310 windowHandle->getName().c_str(), targetFlags.string().c_str(),
311 deviceStates.c_str());
312 return out;
313 }
314
operator <<(std::ostream & out,const TouchedWindow & window)315 std::ostream& operator<<(std::ostream& out, const TouchedWindow& window) {
316 out << window.dump();
317 return out;
318 }
319
320 } // namespace inputdispatcher
321 } // namespace android
322