blob: 9dcf615479d8071a64a2a97c1f81d4720e0c9b4e [file] [log] [blame]
Garfield Tane84e6f92019-08-29 17:28:41 -07001/*
2 * Copyright (C) 2019 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
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -080017#include <android-base/stringprintf.h>
chaviw98318de2021-05-19 16:45:23 -050018#include <gui/WindowInfo.h>
Garfield Tane84e6f92019-08-29 17:28:41 -070019
20#include "InputTarget.h"
Garfield Tane84e6f92019-08-29 17:28:41 -070021#include "TouchState.h"
22
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080023using namespace android::ftl::flag_operators;
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -080024using android::base::StringPrintf;
chaviw98318de2021-05-19 16:45:23 -050025using android::gui::WindowInfo;
26using android::gui::WindowInfoHandle;
Garfield Tane84e6f92019-08-29 17:28:41 -070027
28namespace android::inputdispatcher {
29
Garfield Tane84e6f92019-08-29 17:28:41 -070030void TouchState::reset() {
Prabir Pradhane680f9b2022-02-04 04:24:00 -080031 *this = TouchState();
Garfield Tane84e6f92019-08-29 17:28:41 -070032}
33
Siarhei Vishniakou45504fe2023-05-05 16:05:10 -070034std::set<int32_t> TouchState::getActiveDeviceIds() const {
35 std::set<int32_t> out;
36 for (const TouchedWindow& w : windows) {
37 std::set<int32_t> deviceIds = w.getActiveDeviceIds();
38 out.insert(deviceIds.begin(), deviceIds.end());
39 }
40 return out;
41}
42
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070043bool TouchState::hasTouchingPointers(DeviceId deviceId) const {
Siarhei Vishniakou45504fe2023-05-05 16:05:10 -070044 return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) {
45 return window.hasTouchingPointers(deviceId);
46 });
47}
48
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070049void TouchState::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000050 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070051 touchedWindow.removeTouchingPointer(deviceId, pointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000052 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080053 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000054}
55
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070056void TouchState::removeTouchingPointerFromWindow(
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070057 DeviceId deviceId, int32_t pointerId,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070058 const sp<android::gui::WindowInfoHandle>& windowHandle) {
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080059 for (TouchedWindow& touchedWindow : windows) {
60 if (touchedWindow.windowHandle == windowHandle) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070061 touchedWindow.removeTouchingPointer(deviceId, pointerId);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080062 clearWindowsWithoutPointers();
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080063 return;
64 }
65 }
66}
67
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000068void TouchState::clearHoveringPointers() {
69 for (TouchedWindow& touchedWindow : windows) {
70 touchedWindow.clearHoveringPointers();
71 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080072 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000073}
74
75void TouchState::clearWindowsWithoutPointers() {
76 std::erase_if(windows, [](const TouchedWindow& w) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070077 return !w.hasTouchingPointers() && !w.hasHoveringPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000078 });
79}
80
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080081void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070082 ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070083 std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -080084 std::optional<nsecs_t> firstDownTimeInTarget) {
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -080085 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000086 // We do not compare windows by token here because two windows that share the same token
87 // may have a different transform
Garfield Tane84e6f92019-08-29 17:28:41 -070088 if (touchedWindow.windowHandle == windowHandle) {
89 touchedWindow.targetFlags |= targetFlags;
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080090 if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
91 touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
Garfield Tane84e6f92019-08-29 17:28:41 -070092 }
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000093 // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070094 // downTime set initially. Need to update existing window when a pointer is down for the
95 // window.
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070096 touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070097 if (firstDownTimeInTarget) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070098 touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000099 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700100 return;
101 }
102 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700103 TouchedWindow touchedWindow;
104 touchedWindow.windowHandle = windowHandle;
105 touchedWindow.targetFlags = targetFlags;
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700106 touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700107 if (firstDownTimeInTarget) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700108 touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700109 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700110 windows.push_back(touchedWindow);
111}
112
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000113void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700114 DeviceId deviceId, int32_t hoveringPointerId) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000115 for (TouchedWindow& touchedWindow : windows) {
116 if (touchedWindow.windowHandle == windowHandle) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700117 touchedWindow.addHoveringPointer(deviceId, hoveringPointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000118 return;
119 }
120 }
121
122 TouchedWindow touchedWindow;
123 touchedWindow.windowHandle = windowHandle;
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700124 touchedWindow.addHoveringPointer(deviceId, hoveringPointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000125 windows.push_back(touchedWindow);
126}
127
Garfield Tane84e6f92019-08-29 17:28:41 -0700128void TouchState::removeWindowByToken(const sp<IBinder>& token) {
129 for (size_t i = 0; i < windows.size(); i++) {
130 if (windows[i].windowHandle->getToken() == token) {
131 windows.erase(windows.begin() + i);
132 return;
133 }
134 }
135}
136
Sam Dubeyf886dec2023-01-27 13:28:19 +0000137void TouchState::filterNonAsIsTouchWindows() {
138 for (size_t i = 0; i < windows.size();) {
139 TouchedWindow& window = windows[i];
140 if (window.targetFlags.any(InputTarget::Flags::DISPATCH_AS_IS |
141 InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
142 window.targetFlags.clear(InputTarget::DISPATCH_MASK);
143 window.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
144 i += 1;
145 } else {
146 windows.erase(windows.begin() + i);
147 }
148 }
149}
150
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700151void TouchState::cancelPointersForWindowsExcept(DeviceId deviceId,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700152 std::bitset<MAX_POINTER_ID + 1> pointerIds,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000153 const sp<IBinder>& token) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700154 std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000155 if (w.windowHandle->getToken() != token) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700156 w.removeTouchingPointers(deviceId, pointerIds);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000157 }
158 });
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800159 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000160}
161
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800162/**
163 * For any pointer that's being pilfered, remove it from all of the other windows that currently
164 * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and
165 * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window
166 * B.
167 */
168void TouchState::cancelPointersForNonPilferingWindows() {
169 // First, find all pointers that are being pilfered, across all windows
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700170 std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700171 for (const TouchedWindow& w : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700172 for (const auto& [deviceId, pilferedPointerIds] : w.getPilferingPointers()) {
173 allPilferedPointerIdsByDevice[deviceId] |= pilferedPointerIds;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700174 }
175 };
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800176
177 // Optimization: most of the time, pilfering does not occur
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700178 if (allPilferedPointerIdsByDevice.empty()) return;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800179
180 // Now, remove all pointers from every window that's being pilfered by other windows.
181 // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2
182 // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
183 // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
184 // limitation here.
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700185 for (const auto& [deviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700186 std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
187 std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700188 w.getPilferingPointers(deviceId) ^ allPilferedPointerIds;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700189 // Remove all pointers pilfered by other windows
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700190 w.removeTouchingPointers(deviceId, pilferedByOtherWindows);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700191 });
192 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800193 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000194}
195
chaviw98318de2021-05-19 16:45:23 -0500196sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700197 for (size_t i = 0; i < windows.size(); i++) {
198 const TouchedWindow& window = windows[i];
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800199 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700200 return window.windowHandle;
201 }
202 }
203 return nullptr;
204}
205
206bool TouchState::isSlippery() const {
207 // Must have exactly one foreground window.
208 bool haveSlipperyForegroundWindow = false;
209 for (const TouchedWindow& window : windows) {
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800210 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700211 if (haveSlipperyForegroundWindow ||
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800212 !window.windowHandle->getInfo()->inputConfig.test(
213 WindowInfo::InputConfig::SLIPPERY)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700214 return false;
215 }
216 haveSlipperyForegroundWindow = true;
217 }
218 }
219 return haveSlipperyForegroundWindow;
220}
221
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000222sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
223 for (size_t i = 0; i < windows.size(); i++) {
224 const TouchedWindow& window = windows[i];
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800225 if (window.windowHandle->getInfo()->inputConfig.test(
226 gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000227 return window.windowHandle;
228 }
229 }
230 return nullptr;
231}
232
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -0800233const TouchedWindow& TouchState::getTouchedWindow(const sp<WindowInfoHandle>& windowHandle) const {
234 auto it = std::find_if(windows.begin(), windows.end(),
235 [&](const TouchedWindow& w) { return w.windowHandle == windowHandle; });
236 LOG_ALWAYS_FATAL_IF(it == windows.end(), "Could not find %s", windowHandle->getName().c_str());
237 return *it;
238}
239
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700240bool TouchState::isDown() const {
241 return std::any_of(windows.begin(), windows.end(),
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700242 [](const TouchedWindow& window) { return window.hasTouchingPointers(); });
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700243}
244
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800245bool TouchState::hasHoveringPointers() const {
246 return std::any_of(windows.begin(), windows.end(),
247 [](const TouchedWindow& window) { return window.hasHoveringPointers(); });
248}
249
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700250std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000251 int32_t pointerId) const {
252 std::set<sp<WindowInfoHandle>> out;
253 for (const TouchedWindow& window : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700254 if (window.hasHoveringPointer(deviceId, pointerId)) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000255 out.insert(window.windowHandle);
256 }
257 }
258 return out;
259}
260
261void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoveringPointerId) {
262 for (TouchedWindow& window : windows) {
263 window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId);
264 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800265 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000266}
267
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700268void TouchState::removeAllPointersForDevice(DeviceId deviceId) {
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700269 for (TouchedWindow& window : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700270 window.removeAllHoveringPointersForDevice(deviceId);
271 window.removeAllTouchingPointersForDevice(deviceId);
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700272 }
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700273
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700274 clearWindowsWithoutPointers();
275}
276
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800277std::string TouchState::dump() const {
278 std::string out;
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800279 if (!windows.empty()) {
280 out += " Windows:\n";
281 for (size_t i = 0; i < windows.size(); i++) {
282 const TouchedWindow& touchedWindow = windows[i];
283 out += StringPrintf(" %zu : ", i) + touchedWindow.dump();
284 }
285 } else {
286 out += " Windows: <none>\n";
287 }
288 return out;
289}
290
Siarhei Vishniakou72945a02023-09-18 18:30:25 -0700291std::ostream& operator<<(std::ostream& out, const TouchState& state) {
292 out << state.dump();
293 return out;
294}
295
Garfield Tane84e6f92019-08-29 17:28:41 -0700296} // namespace android::inputdispatcher