xref: /aosp_15_r20/frameworks/native/services/inputflinger/dispatcher/TouchState.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #include <android-base/logging.h>
18*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
19*38e8c45fSAndroid Build Coastguard Worker #include <gui/WindowInfo.h>
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include "InputTarget.h"
22*38e8c45fSAndroid Build Coastguard Worker #include "TouchState.h"
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker using namespace android::ftl::flag_operators;
25*38e8c45fSAndroid Build Coastguard Worker using android::base::StringPrintf;
26*38e8c45fSAndroid Build Coastguard Worker using android::gui::WindowInfo;
27*38e8c45fSAndroid Build Coastguard Worker using android::gui::WindowInfoHandle;
28*38e8c45fSAndroid Build Coastguard Worker 
29*38e8c45fSAndroid Build Coastguard Worker namespace android::inputdispatcher {
30*38e8c45fSAndroid Build Coastguard Worker 
reset()31*38e8c45fSAndroid Build Coastguard Worker void TouchState::reset() {
32*38e8c45fSAndroid Build Coastguard Worker     *this = TouchState();
33*38e8c45fSAndroid Build Coastguard Worker }
34*38e8c45fSAndroid Build Coastguard Worker 
hasTouchingPointers(DeviceId deviceId) const35*38e8c45fSAndroid Build Coastguard Worker bool TouchState::hasTouchingPointers(DeviceId deviceId) const {
36*38e8c45fSAndroid Build Coastguard Worker     return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) {
37*38e8c45fSAndroid Build Coastguard Worker         return window.hasTouchingPointers(deviceId);
38*38e8c45fSAndroid Build Coastguard Worker     });
39*38e8c45fSAndroid Build Coastguard Worker }
40*38e8c45fSAndroid Build Coastguard Worker 
removeTouchingPointer(DeviceId deviceId,int32_t pointerId)41*38e8c45fSAndroid Build Coastguard Worker void TouchState::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
42*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& touchedWindow : windows) {
43*38e8c45fSAndroid Build Coastguard Worker         touchedWindow.removeTouchingPointer(deviceId, pointerId);
44*38e8c45fSAndroid Build Coastguard Worker     }
45*38e8c45fSAndroid Build Coastguard Worker     clearWindowsWithoutPointers();
46*38e8c45fSAndroid Build Coastguard Worker }
47*38e8c45fSAndroid Build Coastguard Worker 
removeTouchingPointerFromWindow(DeviceId deviceId,int32_t pointerId,const sp<android::gui::WindowInfoHandle> & windowHandle)48*38e8c45fSAndroid Build Coastguard Worker void TouchState::removeTouchingPointerFromWindow(
49*38e8c45fSAndroid Build Coastguard Worker         DeviceId deviceId, int32_t pointerId,
50*38e8c45fSAndroid Build Coastguard Worker         const sp<android::gui::WindowInfoHandle>& windowHandle) {
51*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& touchedWindow : windows) {
52*38e8c45fSAndroid Build Coastguard Worker         if (touchedWindow.windowHandle == windowHandle) {
53*38e8c45fSAndroid Build Coastguard Worker             touchedWindow.removeTouchingPointer(deviceId, pointerId);
54*38e8c45fSAndroid Build Coastguard Worker             clearWindowsWithoutPointers();
55*38e8c45fSAndroid Build Coastguard Worker             return;
56*38e8c45fSAndroid Build Coastguard Worker         }
57*38e8c45fSAndroid Build Coastguard Worker     }
58*38e8c45fSAndroid Build Coastguard Worker }
59*38e8c45fSAndroid Build Coastguard Worker 
clearHoveringPointers(DeviceId deviceId)60*38e8c45fSAndroid Build Coastguard Worker void TouchState::clearHoveringPointers(DeviceId deviceId) {
61*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& touchedWindow : windows) {
62*38e8c45fSAndroid Build Coastguard Worker         touchedWindow.removeAllHoveringPointersForDevice(deviceId);
63*38e8c45fSAndroid Build Coastguard Worker     }
64*38e8c45fSAndroid Build Coastguard Worker     clearWindowsWithoutPointers();
65*38e8c45fSAndroid Build Coastguard Worker }
66*38e8c45fSAndroid Build Coastguard Worker 
clearWindowsWithoutPointers()67*38e8c45fSAndroid Build Coastguard Worker void TouchState::clearWindowsWithoutPointers() {
68*38e8c45fSAndroid Build Coastguard Worker     std::erase_if(windows, [](const TouchedWindow& w) {
69*38e8c45fSAndroid Build Coastguard Worker         return !w.hasTouchingPointers() && !w.hasHoveringPointers();
70*38e8c45fSAndroid Build Coastguard Worker     });
71*38e8c45fSAndroid Build Coastguard Worker }
72*38e8c45fSAndroid Build Coastguard Worker 
addOrUpdateWindow(const sp<WindowInfoHandle> & windowHandle,InputTarget::DispatchMode dispatchMode,ftl::Flags<InputTarget::Flags> targetFlags,DeviceId deviceId,const std::vector<PointerProperties> & touchingPointers,std::optional<nsecs_t> firstDownTimeInTarget)73*38e8c45fSAndroid Build Coastguard Worker android::base::Result<void> TouchState::addOrUpdateWindow(
74*38e8c45fSAndroid Build Coastguard Worker         const sp<WindowInfoHandle>& windowHandle, InputTarget::DispatchMode dispatchMode,
75*38e8c45fSAndroid Build Coastguard Worker         ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
76*38e8c45fSAndroid Build Coastguard Worker         const std::vector<PointerProperties>& touchingPointers,
77*38e8c45fSAndroid Build Coastguard Worker         std::optional<nsecs_t> firstDownTimeInTarget) {
78*38e8c45fSAndroid Build Coastguard Worker     if (touchingPointers.empty()) {
79*38e8c45fSAndroid Build Coastguard Worker         LOG(FATAL) << __func__ << "No pointers specified for " << windowHandle->getName();
80*38e8c45fSAndroid Build Coastguard Worker         return android::base::Error();
81*38e8c45fSAndroid Build Coastguard Worker     }
82*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& touchedWindow : windows) {
83*38e8c45fSAndroid Build Coastguard Worker         // We do not compare windows by token here because two windows that share the same token
84*38e8c45fSAndroid Build Coastguard Worker         // may have a different transform. They will be combined later when we create InputTargets.
85*38e8c45fSAndroid Build Coastguard Worker         // At that point, per-pointer window transform will be considered.
86*38e8c45fSAndroid Build Coastguard Worker         // An alternative design choice here would have been to compare here by token, but to
87*38e8c45fSAndroid Build Coastguard Worker         // store per-pointer transform.
88*38e8c45fSAndroid Build Coastguard Worker         if (touchedWindow.windowHandle == windowHandle) {
89*38e8c45fSAndroid Build Coastguard Worker             touchedWindow.dispatchMode = dispatchMode;
90*38e8c45fSAndroid Build Coastguard Worker             touchedWindow.targetFlags |= targetFlags;
91*38e8c45fSAndroid Build Coastguard Worker             // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
92*38e8c45fSAndroid Build Coastguard Worker             // downTime set initially. Need to update existing window when a pointer is down for the
93*38e8c45fSAndroid Build Coastguard Worker             // window.
94*38e8c45fSAndroid Build Coastguard Worker             android::base::Result<void> addResult =
95*38e8c45fSAndroid Build Coastguard Worker                     touchedWindow.addTouchingPointers(deviceId, touchingPointers);
96*38e8c45fSAndroid Build Coastguard Worker             if (firstDownTimeInTarget) {
97*38e8c45fSAndroid Build Coastguard Worker                 touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
98*38e8c45fSAndroid Build Coastguard Worker             }
99*38e8c45fSAndroid Build Coastguard Worker             return addResult;
100*38e8c45fSAndroid Build Coastguard Worker         }
101*38e8c45fSAndroid Build Coastguard Worker     }
102*38e8c45fSAndroid Build Coastguard Worker     TouchedWindow touchedWindow;
103*38e8c45fSAndroid Build Coastguard Worker     touchedWindow.windowHandle = windowHandle;
104*38e8c45fSAndroid Build Coastguard Worker     touchedWindow.dispatchMode = dispatchMode;
105*38e8c45fSAndroid Build Coastguard Worker     touchedWindow.targetFlags = targetFlags;
106*38e8c45fSAndroid Build Coastguard Worker     touchedWindow.addTouchingPointers(deviceId, touchingPointers);
107*38e8c45fSAndroid Build Coastguard Worker     if (firstDownTimeInTarget) {
108*38e8c45fSAndroid Build Coastguard Worker         touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
109*38e8c45fSAndroid Build Coastguard Worker     }
110*38e8c45fSAndroid Build Coastguard Worker     windows.push_back(touchedWindow);
111*38e8c45fSAndroid Build Coastguard Worker     return {};
112*38e8c45fSAndroid Build Coastguard Worker }
113*38e8c45fSAndroid Build Coastguard Worker 
addHoveringPointerToWindow(const sp<WindowInfoHandle> & windowHandle,DeviceId deviceId,const PointerProperties & pointer,float x,float y)114*38e8c45fSAndroid Build Coastguard Worker void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
115*38e8c45fSAndroid Build Coastguard Worker                                             DeviceId deviceId, const PointerProperties& pointer,
116*38e8c45fSAndroid Build Coastguard Worker                                             float x, float y) {
117*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& touchedWindow : windows) {
118*38e8c45fSAndroid Build Coastguard Worker         if (touchedWindow.windowHandle == windowHandle) {
119*38e8c45fSAndroid Build Coastguard Worker             touchedWindow.addHoveringPointer(deviceId, pointer, x, y);
120*38e8c45fSAndroid Build Coastguard Worker             return;
121*38e8c45fSAndroid Build Coastguard Worker         }
122*38e8c45fSAndroid Build Coastguard Worker     }
123*38e8c45fSAndroid Build Coastguard Worker 
124*38e8c45fSAndroid Build Coastguard Worker     TouchedWindow touchedWindow;
125*38e8c45fSAndroid Build Coastguard Worker     touchedWindow.windowHandle = windowHandle;
126*38e8c45fSAndroid Build Coastguard Worker     touchedWindow.addHoveringPointer(deviceId, pointer, x, y);
127*38e8c45fSAndroid Build Coastguard Worker     windows.push_back(touchedWindow);
128*38e8c45fSAndroid Build Coastguard Worker }
129*38e8c45fSAndroid Build Coastguard Worker 
removeWindowByToken(const sp<IBinder> & token)130*38e8c45fSAndroid Build Coastguard Worker void TouchState::removeWindowByToken(const sp<IBinder>& token) {
131*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < windows.size(); i++) {
132*38e8c45fSAndroid Build Coastguard Worker         if (windows[i].windowHandle->getToken() == token) {
133*38e8c45fSAndroid Build Coastguard Worker             windows.erase(windows.begin() + i);
134*38e8c45fSAndroid Build Coastguard Worker             return;
135*38e8c45fSAndroid Build Coastguard Worker         }
136*38e8c45fSAndroid Build Coastguard Worker     }
137*38e8c45fSAndroid Build Coastguard Worker }
138*38e8c45fSAndroid Build Coastguard Worker 
cancelPointersForWindowsExcept(DeviceId deviceId,std::bitset<MAX_POINTER_ID+1> pointerIds,const sp<IBinder> & token)139*38e8c45fSAndroid Build Coastguard Worker void TouchState::cancelPointersForWindowsExcept(DeviceId deviceId,
140*38e8c45fSAndroid Build Coastguard Worker                                                 std::bitset<MAX_POINTER_ID + 1> pointerIds,
141*38e8c45fSAndroid Build Coastguard Worker                                                 const sp<IBinder>& token) {
142*38e8c45fSAndroid Build Coastguard Worker     std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
143*38e8c45fSAndroid Build Coastguard Worker         if (w.windowHandle->getToken() != token) {
144*38e8c45fSAndroid Build Coastguard Worker             w.removeTouchingPointers(deviceId, pointerIds);
145*38e8c45fSAndroid Build Coastguard Worker         }
146*38e8c45fSAndroid Build Coastguard Worker     });
147*38e8c45fSAndroid Build Coastguard Worker     clearWindowsWithoutPointers();
148*38e8c45fSAndroid Build Coastguard Worker }
149*38e8c45fSAndroid Build Coastguard Worker 
150*38e8c45fSAndroid Build Coastguard Worker /**
151*38e8c45fSAndroid Build Coastguard Worker  * For any pointer that's being pilfered, remove it from all of the other windows that currently
152*38e8c45fSAndroid Build Coastguard Worker  * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and
153*38e8c45fSAndroid Build Coastguard Worker  * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window
154*38e8c45fSAndroid Build Coastguard Worker  * B.
155*38e8c45fSAndroid Build Coastguard Worker  */
cancelPointersForNonPilferingWindows()156*38e8c45fSAndroid Build Coastguard Worker void TouchState::cancelPointersForNonPilferingWindows() {
157*38e8c45fSAndroid Build Coastguard Worker     // First, find all pointers that are being pilfered, across all windows
158*38e8c45fSAndroid Build Coastguard Worker     std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
159*38e8c45fSAndroid Build Coastguard Worker     for (const TouchedWindow& w : windows) {
160*38e8c45fSAndroid Build Coastguard Worker         for (const auto& [deviceId, pilferedPointerIds] : w.getPilferingPointers()) {
161*38e8c45fSAndroid Build Coastguard Worker             allPilferedPointerIdsByDevice[deviceId] |= pilferedPointerIds;
162*38e8c45fSAndroid Build Coastguard Worker         }
163*38e8c45fSAndroid Build Coastguard Worker     };
164*38e8c45fSAndroid Build Coastguard Worker 
165*38e8c45fSAndroid Build Coastguard Worker     // Optimization: most of the time, pilfering does not occur
166*38e8c45fSAndroid Build Coastguard Worker     if (allPilferedPointerIdsByDevice.empty()) return;
167*38e8c45fSAndroid Build Coastguard Worker 
168*38e8c45fSAndroid Build Coastguard Worker     // Now, remove all pointers from every window that's being pilfered by other windows.
169*38e8c45fSAndroid Build Coastguard Worker     // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2
170*38e8c45fSAndroid Build Coastguard Worker     // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
171*38e8c45fSAndroid Build Coastguard Worker     // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
172*38e8c45fSAndroid Build Coastguard Worker     // limitation here.
173*38e8c45fSAndroid Build Coastguard Worker     for (const auto& [deviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
174*38e8c45fSAndroid Build Coastguard Worker         std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
175*38e8c45fSAndroid Build Coastguard Worker             std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
176*38e8c45fSAndroid Build Coastguard Worker                     w.getPilferingPointers(deviceId) ^ allPilferedPointerIds;
177*38e8c45fSAndroid Build Coastguard Worker             // Remove all pointers pilfered by other windows
178*38e8c45fSAndroid Build Coastguard Worker             w.removeTouchingPointers(deviceId, pilferedByOtherWindows);
179*38e8c45fSAndroid Build Coastguard Worker         });
180*38e8c45fSAndroid Build Coastguard Worker     }
181*38e8c45fSAndroid Build Coastguard Worker     clearWindowsWithoutPointers();
182*38e8c45fSAndroid Build Coastguard Worker }
183*38e8c45fSAndroid Build Coastguard Worker 
getFirstForegroundWindowHandle(DeviceId deviceId) const184*38e8c45fSAndroid Build Coastguard Worker sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle(DeviceId deviceId) const {
185*38e8c45fSAndroid Build Coastguard Worker     for (const auto& window : windows) {
186*38e8c45fSAndroid Build Coastguard Worker         if (!window.hasTouchingPointers(deviceId)) {
187*38e8c45fSAndroid Build Coastguard Worker             continue;
188*38e8c45fSAndroid Build Coastguard Worker         }
189*38e8c45fSAndroid Build Coastguard Worker         if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
190*38e8c45fSAndroid Build Coastguard Worker             return window.windowHandle;
191*38e8c45fSAndroid Build Coastguard Worker         }
192*38e8c45fSAndroid Build Coastguard Worker     }
193*38e8c45fSAndroid Build Coastguard Worker     return nullptr;
194*38e8c45fSAndroid Build Coastguard Worker }
195*38e8c45fSAndroid Build Coastguard Worker 
isSlippery(DeviceId deviceId) const196*38e8c45fSAndroid Build Coastguard Worker bool TouchState::isSlippery(DeviceId deviceId) const {
197*38e8c45fSAndroid Build Coastguard Worker     // Must have exactly one foreground window.
198*38e8c45fSAndroid Build Coastguard Worker     bool haveSlipperyForegroundWindow = false;
199*38e8c45fSAndroid Build Coastguard Worker     for (const TouchedWindow& window : windows) {
200*38e8c45fSAndroid Build Coastguard Worker         if (!window.hasTouchingPointers(deviceId)) {
201*38e8c45fSAndroid Build Coastguard Worker             continue;
202*38e8c45fSAndroid Build Coastguard Worker         }
203*38e8c45fSAndroid Build Coastguard Worker         if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
204*38e8c45fSAndroid Build Coastguard Worker             if (haveSlipperyForegroundWindow ||
205*38e8c45fSAndroid Build Coastguard Worker                 !window.windowHandle->getInfo()->inputConfig.test(
206*38e8c45fSAndroid Build Coastguard Worker                         WindowInfo::InputConfig::SLIPPERY)) {
207*38e8c45fSAndroid Build Coastguard Worker                 return false;
208*38e8c45fSAndroid Build Coastguard Worker             }
209*38e8c45fSAndroid Build Coastguard Worker             haveSlipperyForegroundWindow = true;
210*38e8c45fSAndroid Build Coastguard Worker         }
211*38e8c45fSAndroid Build Coastguard Worker     }
212*38e8c45fSAndroid Build Coastguard Worker     return haveSlipperyForegroundWindow;
213*38e8c45fSAndroid Build Coastguard Worker }
214*38e8c45fSAndroid Build Coastguard Worker 
getWallpaperWindow(DeviceId deviceId) const215*38e8c45fSAndroid Build Coastguard Worker sp<WindowInfoHandle> TouchState::getWallpaperWindow(DeviceId deviceId) const {
216*38e8c45fSAndroid Build Coastguard Worker     for (const auto& window : windows) {
217*38e8c45fSAndroid Build Coastguard Worker         if (!window.hasTouchingPointers(deviceId)) {
218*38e8c45fSAndroid Build Coastguard Worker             continue;
219*38e8c45fSAndroid Build Coastguard Worker         }
220*38e8c45fSAndroid Build Coastguard Worker         if (window.windowHandle->getInfo()->inputConfig.test(
221*38e8c45fSAndroid Build Coastguard Worker                     gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
222*38e8c45fSAndroid Build Coastguard Worker             return window.windowHandle;
223*38e8c45fSAndroid Build Coastguard Worker         }
224*38e8c45fSAndroid Build Coastguard Worker     }
225*38e8c45fSAndroid Build Coastguard Worker     return nullptr;
226*38e8c45fSAndroid Build Coastguard Worker }
227*38e8c45fSAndroid Build Coastguard Worker 
getTouchedWindow(const sp<WindowInfoHandle> & windowHandle) const228*38e8c45fSAndroid Build Coastguard Worker const TouchedWindow& TouchState::getTouchedWindow(const sp<WindowInfoHandle>& windowHandle) const {
229*38e8c45fSAndroid Build Coastguard Worker     auto it = std::find_if(windows.begin(), windows.end(),
230*38e8c45fSAndroid Build Coastguard Worker                            [&](const TouchedWindow& w) { return w.windowHandle == windowHandle; });
231*38e8c45fSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(it == windows.end(), "Could not find %s", windowHandle->getName().c_str());
232*38e8c45fSAndroid Build Coastguard Worker     return *it;
233*38e8c45fSAndroid Build Coastguard Worker }
234*38e8c45fSAndroid Build Coastguard Worker 
isDown(DeviceId deviceId) const235*38e8c45fSAndroid Build Coastguard Worker bool TouchState::isDown(DeviceId deviceId) const {
236*38e8c45fSAndroid Build Coastguard Worker     return std::any_of(windows.begin(), windows.end(), [&deviceId](const TouchedWindow& window) {
237*38e8c45fSAndroid Build Coastguard Worker         return window.hasTouchingPointers(deviceId);
238*38e8c45fSAndroid Build Coastguard Worker     });
239*38e8c45fSAndroid Build Coastguard Worker }
240*38e8c45fSAndroid Build Coastguard Worker 
hasHoveringPointers(DeviceId deviceId) const241*38e8c45fSAndroid Build Coastguard Worker bool TouchState::hasHoveringPointers(DeviceId deviceId) const {
242*38e8c45fSAndroid Build Coastguard Worker     return std::any_of(windows.begin(), windows.end(), [&deviceId](const TouchedWindow& window) {
243*38e8c45fSAndroid Build Coastguard Worker         return window.hasHoveringPointers(deviceId);
244*38e8c45fSAndroid Build Coastguard Worker     });
245*38e8c45fSAndroid Build Coastguard Worker }
246*38e8c45fSAndroid Build Coastguard Worker 
hasActiveStylus() const247*38e8c45fSAndroid Build Coastguard Worker bool TouchState::hasActiveStylus() const {
248*38e8c45fSAndroid Build Coastguard Worker     return std::any_of(windows.begin(), windows.end(),
249*38e8c45fSAndroid Build Coastguard Worker                        [](const TouchedWindow& window) { return window.hasActiveStylus(); });
250*38e8c45fSAndroid Build Coastguard Worker }
251*38e8c45fSAndroid Build Coastguard Worker 
getWindowsWithHoveringPointer(DeviceId deviceId,int32_t pointerId) const252*38e8c45fSAndroid Build Coastguard Worker std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId,
253*38e8c45fSAndroid Build Coastguard Worker                                                                          int32_t pointerId) const {
254*38e8c45fSAndroid Build Coastguard Worker     std::set<sp<WindowInfoHandle>> out;
255*38e8c45fSAndroid Build Coastguard Worker     for (const TouchedWindow& window : windows) {
256*38e8c45fSAndroid Build Coastguard Worker         if (window.hasHoveringPointer(deviceId, pointerId)) {
257*38e8c45fSAndroid Build Coastguard Worker             out.insert(window.windowHandle);
258*38e8c45fSAndroid Build Coastguard Worker         }
259*38e8c45fSAndroid Build Coastguard Worker     }
260*38e8c45fSAndroid Build Coastguard Worker     return out;
261*38e8c45fSAndroid Build Coastguard Worker }
262*38e8c45fSAndroid Build Coastguard Worker 
removeHoveringPointer(int32_t hoveringDeviceId,int32_t hoveringPointerId)263*38e8c45fSAndroid Build Coastguard Worker void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoveringPointerId) {
264*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& window : windows) {
265*38e8c45fSAndroid Build Coastguard Worker         window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId);
266*38e8c45fSAndroid Build Coastguard Worker     }
267*38e8c45fSAndroid Build Coastguard Worker     clearWindowsWithoutPointers();
268*38e8c45fSAndroid Build Coastguard Worker }
269*38e8c45fSAndroid Build Coastguard Worker 
removeAllPointersForDevice(DeviceId deviceId)270*38e8c45fSAndroid Build Coastguard Worker void TouchState::removeAllPointersForDevice(DeviceId deviceId) {
271*38e8c45fSAndroid Build Coastguard Worker     for (TouchedWindow& window : windows) {
272*38e8c45fSAndroid Build Coastguard Worker         window.removeAllHoveringPointersForDevice(deviceId);
273*38e8c45fSAndroid Build Coastguard Worker         window.removeAllTouchingPointersForDevice(deviceId);
274*38e8c45fSAndroid Build Coastguard Worker     }
275*38e8c45fSAndroid Build Coastguard Worker 
276*38e8c45fSAndroid Build Coastguard Worker     clearWindowsWithoutPointers();
277*38e8c45fSAndroid Build Coastguard Worker }
278*38e8c45fSAndroid Build Coastguard Worker 
dump() const279*38e8c45fSAndroid Build Coastguard Worker std::string TouchState::dump() const {
280*38e8c45fSAndroid Build Coastguard Worker     std::string out;
281*38e8c45fSAndroid Build Coastguard Worker     if (!windows.empty()) {
282*38e8c45fSAndroid Build Coastguard Worker         out += "  Windows:\n";
283*38e8c45fSAndroid Build Coastguard Worker         for (size_t i = 0; i < windows.size(); i++) {
284*38e8c45fSAndroid Build Coastguard Worker             const TouchedWindow& touchedWindow = windows[i];
285*38e8c45fSAndroid Build Coastguard Worker             out += StringPrintf("    %zu : ", i) + touchedWindow.dump();
286*38e8c45fSAndroid Build Coastguard Worker         }
287*38e8c45fSAndroid Build Coastguard Worker     } else {
288*38e8c45fSAndroid Build Coastguard Worker         out += "  Windows: <none>\n";
289*38e8c45fSAndroid Build Coastguard Worker     }
290*38e8c45fSAndroid Build Coastguard Worker     return out;
291*38e8c45fSAndroid Build Coastguard Worker }
292*38e8c45fSAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const TouchState & state)293*38e8c45fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& out, const TouchState& state) {
294*38e8c45fSAndroid Build Coastguard Worker     out << state.dump();
295*38e8c45fSAndroid Build Coastguard Worker     return out;
296*38e8c45fSAndroid Build Coastguard Worker }
297*38e8c45fSAndroid Build Coastguard Worker 
298*38e8c45fSAndroid Build Coastguard Worker } // namespace android::inputdispatcher
299