xref: /aosp_15_r20/frameworks/native/services/inputflinger/dispatcher/TouchedWindow.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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 
hasPointerId(const std::vector<TouchedWindow::HoveringPointer> & pointers,int32_t pointerId)39 bool hasPointerId(const std::vector<TouchedWindow::HoveringPointer>& pointers, int32_t pointerId) {
40     return std::find_if(pointers.begin(), pointers.end(),
41                         [&pointerId](const TouchedWindow::HoveringPointer& pointer) {
42                             return pointer.properties.id == pointerId;
43                         }) != pointers.end();
44 }
45 
46 } // namespace
47 
hasHoveringPointers() const48 bool TouchedWindow::hasHoveringPointers() const {
49     for (const auto& [_, state] : mDeviceStates) {
50         if (!state.hoveringPointers.empty()) {
51             return true;
52         }
53     }
54     return false;
55 }
56 
hasHoveringPointers(DeviceId deviceId) const57 bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const {
58     const auto stateIt = mDeviceStates.find(deviceId);
59     if (stateIt == mDeviceStates.end()) {
60         return false;
61     }
62     const DeviceState& state = stateIt->second;
63 
64     return !state.hoveringPointers.empty();
65 }
66 
clearHoveringPointers(DeviceId deviceId)67 void TouchedWindow::clearHoveringPointers(DeviceId deviceId) {
68     auto stateIt = mDeviceStates.find(deviceId);
69     if (stateIt == mDeviceStates.end()) {
70         return;
71     }
72     DeviceState& state = stateIt->second;
73     state.hoveringPointers.clear();
74     if (!state.hasPointers()) {
75         mDeviceStates.erase(stateIt);
76     }
77 }
78 
hasHoveringPointer(DeviceId deviceId,int32_t pointerId) const79 bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const {
80     const auto stateIt = mDeviceStates.find(deviceId);
81     if (stateIt == mDeviceStates.end()) {
82         return false;
83     }
84     const DeviceState& state = stateIt->second;
85     return hasPointerId(state.hoveringPointers, pointerId);
86 }
87 
addHoveringPointer(DeviceId deviceId,const PointerProperties & properties,float x,float y)88 void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& properties,
89                                        float x, float y) {
90     std::vector<HoveringPointer>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers;
91     const size_t initialSize = hoveringPointers.size();
92     std::erase_if(hoveringPointers, [&properties](const HoveringPointer& pointer) {
93         return pointer.properties.id == properties.id;
94     });
95     if (hoveringPointers.size() != initialSize) {
96         LOG(ERROR) << __func__ << ": " << properties << ", device " << deviceId << " was in "
97                    << *this;
98     }
99     hoveringPointers.push_back({properties, x, y});
100 }
101 
addTouchingPointers(DeviceId deviceId,const std::vector<PointerProperties> & pointers)102 Result<void> TouchedWindow::addTouchingPointers(DeviceId deviceId,
103                                                 const std::vector<PointerProperties>& pointers) {
104     std::vector<PointerProperties>& touchingPointers = mDeviceStates[deviceId].touchingPointers;
105     const size_t initialSize = touchingPointers.size();
106     for (const PointerProperties& pointer : pointers) {
107         std::erase_if(touchingPointers, [&pointer](const PointerProperties& properties) {
108             return properties.id == pointer.id;
109         });
110     }
111     const bool foundInconsistentState = touchingPointers.size() != initialSize;
112     touchingPointers.insert(touchingPointers.end(), pointers.begin(), pointers.end());
113     if (foundInconsistentState) {
114         LOG(ERROR) << __func__ << ": " << dumpVector(pointers, streamableToString) << ", device "
115                    << deviceId << " already in " << *this;
116         return android::base::Error();
117     }
118     return {};
119 }
120 
hasTouchingPointers() const121 bool TouchedWindow::hasTouchingPointers() const {
122     for (const auto& [_, state] : mDeviceStates) {
123         if (!state.touchingPointers.empty()) {
124             return true;
125         }
126     }
127     return false;
128 }
129 
hasTouchingPointers(DeviceId deviceId) const130 bool TouchedWindow::hasTouchingPointers(DeviceId deviceId) const {
131     return !getTouchingPointers(deviceId).empty();
132 }
133 
hasTouchingPointer(DeviceId deviceId,int32_t pointerId) const134 bool TouchedWindow::hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const {
135     const auto stateIt = mDeviceStates.find(deviceId);
136     if (stateIt == mDeviceStates.end()) {
137         return false;
138     }
139     const DeviceState& state = stateIt->second;
140     return hasPointerId(state.touchingPointers, pointerId);
141 }
142 
getTouchingPointers(DeviceId deviceId) const143 std::vector<PointerProperties> TouchedWindow::getTouchingPointers(DeviceId deviceId) const {
144     const auto stateIt = mDeviceStates.find(deviceId);
145     if (stateIt == mDeviceStates.end()) {
146         return {};
147     }
148     const DeviceState& state = stateIt->second;
149     return state.touchingPointers;
150 }
151 
removeTouchingPointer(DeviceId deviceId,int32_t pointerId)152 void TouchedWindow::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
153     std::bitset<MAX_POINTER_ID + 1> pointerIds;
154     pointerIds.set(pointerId, true);
155 
156     removeTouchingPointers(deviceId, pointerIds);
157 }
158 
removeTouchingPointers(DeviceId deviceId,std::bitset<MAX_POINTER_ID+1> pointers)159 void TouchedWindow::removeTouchingPointers(DeviceId deviceId,
160                                            std::bitset<MAX_POINTER_ID + 1> pointers) {
161     const auto stateIt = mDeviceStates.find(deviceId);
162     if (stateIt == mDeviceStates.end()) {
163         return;
164     }
165     DeviceState& state = stateIt->second;
166 
167     std::erase_if(state.touchingPointers, [&pointers](const PointerProperties& properties) {
168         return pointers.test(properties.id);
169     });
170 
171     state.pilferingPointerIds &= ~pointers;
172 
173     if (!state.hasPointers()) {
174         mDeviceStates.erase(stateIt);
175     }
176 }
177 
hasActiveStylus() const178 bool TouchedWindow::hasActiveStylus() const {
179     for (const auto& [_, state] : mDeviceStates) {
180         for (const PointerProperties& properties : state.touchingPointers) {
181             if (properties.toolType == ToolType::STYLUS) {
182                 return true;
183             }
184         }
185         for (const HoveringPointer& pointer : state.hoveringPointers) {
186             if (pointer.properties.toolType == ToolType::STYLUS) {
187                 return true;
188             }
189         }
190     }
191     return false;
192 }
193 
getTouchingDeviceIds() const194 std::set<DeviceId> TouchedWindow::getTouchingDeviceIds() const {
195     std::set<DeviceId> deviceIds;
196     for (const auto& [deviceId, deviceState] : mDeviceStates) {
197         if (!deviceState.touchingPointers.empty()) {
198             deviceIds.insert(deviceId);
199         }
200     }
201     return deviceIds;
202 }
203 
hasPilferingPointers(DeviceId deviceId) const204 bool TouchedWindow::hasPilferingPointers(DeviceId deviceId) const {
205     const auto stateIt = mDeviceStates.find(deviceId);
206     if (stateIt == mDeviceStates.end()) {
207         return false;
208     }
209     const DeviceState& state = stateIt->second;
210 
211     return state.pilferingPointerIds.any();
212 }
213 
addPilferingPointers(DeviceId deviceId,std::bitset<MAX_POINTER_ID+1> pointerIds)214 void TouchedWindow::addPilferingPointers(DeviceId deviceId,
215                                          std::bitset<MAX_POINTER_ID + 1> pointerIds) {
216     mDeviceStates[deviceId].pilferingPointerIds |= pointerIds;
217 }
218 
addPilferingPointer(DeviceId deviceId,int32_t pointerId)219 void TouchedWindow::addPilferingPointer(DeviceId deviceId, int32_t pointerId) {
220     mDeviceStates[deviceId].pilferingPointerIds.set(pointerId);
221 }
222 
getPilferingPointers(DeviceId deviceId) const223 std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(DeviceId deviceId) const {
224     const auto stateIt = mDeviceStates.find(deviceId);
225     if (stateIt == mDeviceStates.end()) {
226         return {};
227     }
228     const DeviceState& state = stateIt->second;
229 
230     return state.pilferingPointerIds;
231 }
232 
getPilferingPointers() const233 std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const {
234     std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> out;
235     for (const auto& [deviceId, state] : mDeviceStates) {
236         out.emplace(deviceId, state.pilferingPointerIds);
237     }
238     return out;
239 }
240 
getDownTimeInTarget(DeviceId deviceId) const241 std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(DeviceId deviceId) const {
242     const auto stateIt = mDeviceStates.find(deviceId);
243     if (stateIt == mDeviceStates.end()) {
244         return {};
245     }
246     const DeviceState& state = stateIt->second;
247     return state.downTimeInTarget;
248 }
249 
trySetDownTimeInTarget(DeviceId deviceId,nsecs_t downTime)250 void TouchedWindow::trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime) {
251     auto [stateIt, _] = mDeviceStates.try_emplace(deviceId);
252     DeviceState& state = stateIt->second;
253 
254     if (!state.downTimeInTarget) {
255         state.downTimeInTarget = downTime;
256     }
257 }
258 
removeAllTouchingPointersForDevice(DeviceId deviceId)259 void TouchedWindow::removeAllTouchingPointersForDevice(DeviceId deviceId) {
260     const auto stateIt = mDeviceStates.find(deviceId);
261     if (stateIt == mDeviceStates.end()) {
262         return;
263     }
264     DeviceState& state = stateIt->second;
265 
266     state.touchingPointers.clear();
267     state.pilferingPointerIds.reset();
268     state.downTimeInTarget.reset();
269 
270     if (!state.hasPointers()) {
271         mDeviceStates.erase(stateIt);
272     }
273 }
274 
removeHoveringPointer(DeviceId deviceId,int32_t pointerId)275 void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) {
276     const auto stateIt = mDeviceStates.find(deviceId);
277     if (stateIt == mDeviceStates.end()) {
278         return;
279     }
280     DeviceState& state = stateIt->second;
281 
282     std::erase_if(state.hoveringPointers, [&pointerId](const HoveringPointer& pointer) {
283         return pointer.properties.id == pointerId;
284     });
285 
286     if (!state.hasPointers()) {
287         mDeviceStates.erase(stateIt);
288     }
289 }
290 
eraseHoveringPointersIf(std::function<bool (const PointerProperties &,float,float)> condition)291 std::vector<DeviceId> TouchedWindow::eraseHoveringPointersIf(
292         std::function<bool(const PointerProperties&, float /*x*/, float /*y*/)> condition) {
293     std::vector<DeviceId> erasedDevices;
294     for (auto& [deviceId, state] : mDeviceStates) {
295         std::erase_if(state.hoveringPointers, [&](const HoveringPointer& pointer) {
296             if (condition(pointer.properties, pointer.x, pointer.y)) {
297                 erasedDevices.push_back(deviceId);
298                 return true;
299             }
300             return false;
301         });
302     }
303 
304     return erasedDevices;
305 }
306 
removeAllHoveringPointersForDevice(DeviceId deviceId)307 void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) {
308     const auto stateIt = mDeviceStates.find(deviceId);
309     if (stateIt == mDeviceStates.end()) {
310         return;
311     }
312     DeviceState& state = stateIt->second;
313 
314     state.hoveringPointers.clear();
315 
316     if (!state.hasPointers()) {
317         mDeviceStates.erase(stateIt);
318     }
319 }
320 
deviceStateToString(const TouchedWindow::DeviceState & state)321 std::string TouchedWindow::deviceStateToString(const TouchedWindow::DeviceState& state) {
322     return StringPrintf("[touchingPointers=%s, "
323                         "downTimeInTarget=%s, hoveringPointers=%s, pilferingPointerIds=%s]",
324                         dumpVector(state.touchingPointers, streamableToString).c_str(),
325                         toString(state.downTimeInTarget).c_str(),
326                         dumpVector(state.hoveringPointers, streamableToString).c_str(),
327                         bitsetToString(state.pilferingPointerIds).c_str());
328 }
329 
dump() const330 std::string TouchedWindow::dump() const {
331     std::string out;
332     std::string deviceStates =
333             dumpMap(mDeviceStates, constToString, TouchedWindow::deviceStateToString);
334     out += StringPrintf("name='%s', targetFlags=%s, mDeviceStates=%s\n",
335                         windowHandle->getName().c_str(), targetFlags.string().c_str(),
336                         deviceStates.c_str());
337     return out;
338 }
339 
operator <<(std::ostream & out,const TouchedWindow::HoveringPointer & pointer)340 std::ostream& operator<<(std::ostream& out, const TouchedWindow::HoveringPointer& pointer) {
341     out << pointer.properties << " at (" << pointer.x << ", " << pointer.y << ")";
342     return out;
343 }
344 
operator <<(std::ostream & out,const TouchedWindow & window)345 std::ostream& operator<<(std::ostream& out, const TouchedWindow& window) {
346     out << window.dump();
347     return out;
348 }
349 
350 } // namespace inputdispatcher
351 } // namespace android
352