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