blob: ef188c7844a76572e2c9e7715984ba07b5b6e585 [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 Vishniakou0836a302023-05-03 13:54:30 -070034void TouchState::removeTouchingPointer(int32_t removedDeviceId, int32_t pointerId) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000035 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070036 touchedWindow.removeTouchingPointer(removedDeviceId, pointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000037 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080038 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000039}
40
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070041void TouchState::removeTouchingPointerFromWindow(
42 int32_t removedDeviceId, int32_t pointerId,
43 const sp<android::gui::WindowInfoHandle>& windowHandle) {
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080044 for (TouchedWindow& touchedWindow : windows) {
45 if (touchedWindow.windowHandle == windowHandle) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070046 touchedWindow.removeTouchingPointer(removedDeviceId, pointerId);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080047 clearWindowsWithoutPointers();
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080048 return;
49 }
50 }
51}
52
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000053void TouchState::clearHoveringPointers() {
54 for (TouchedWindow& touchedWindow : windows) {
55 touchedWindow.clearHoveringPointers();
56 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080057 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000058}
59
60void TouchState::clearWindowsWithoutPointers() {
61 std::erase_if(windows, [](const TouchedWindow& w) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070062 return !w.hasTouchingPointers() && !w.hasHoveringPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000063 });
64}
65
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080066void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
Siarhei Vishniakou8a878352023-01-30 14:05:01 -080067 ftl::Flags<InputTarget::Flags> targetFlags,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070068 int32_t addedDeviceId,
69 std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -080070 std::optional<nsecs_t> firstDownTimeInTarget) {
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -080071 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000072 // We do not compare windows by token here because two windows that share the same token
73 // may have a different transform
Garfield Tane84e6f92019-08-29 17:28:41 -070074 if (touchedWindow.windowHandle == windowHandle) {
75 touchedWindow.targetFlags |= targetFlags;
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080076 if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
77 touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
Garfield Tane84e6f92019-08-29 17:28:41 -070078 }
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000079 // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070080 // downTime set initially. Need to update existing window when a pointer is down for the
81 // window.
82 touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds);
83 if (firstDownTimeInTarget) {
84 touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000085 }
Garfield Tane84e6f92019-08-29 17:28:41 -070086 return;
87 }
88 }
Garfield Tane84e6f92019-08-29 17:28:41 -070089 TouchedWindow touchedWindow;
90 touchedWindow.windowHandle = windowHandle;
91 touchedWindow.targetFlags = targetFlags;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070092 touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds);
93 if (firstDownTimeInTarget) {
94 touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget);
95 }
Garfield Tane84e6f92019-08-29 17:28:41 -070096 windows.push_back(touchedWindow);
97}
98
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000099void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
100 int32_t hoveringDeviceId, int32_t hoveringPointerId) {
101 for (TouchedWindow& touchedWindow : windows) {
102 if (touchedWindow.windowHandle == windowHandle) {
103 touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId);
104 return;
105 }
106 }
107
108 TouchedWindow touchedWindow;
109 touchedWindow.windowHandle = windowHandle;
110 touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId);
111 windows.push_back(touchedWindow);
112}
113
Garfield Tane84e6f92019-08-29 17:28:41 -0700114void TouchState::removeWindowByToken(const sp<IBinder>& token) {
115 for (size_t i = 0; i < windows.size(); i++) {
116 if (windows[i].windowHandle->getToken() == token) {
117 windows.erase(windows.begin() + i);
118 return;
119 }
120 }
121}
122
Sam Dubeyf886dec2023-01-27 13:28:19 +0000123void TouchState::filterNonAsIsTouchWindows() {
124 for (size_t i = 0; i < windows.size();) {
125 TouchedWindow& window = windows[i];
126 if (window.targetFlags.any(InputTarget::Flags::DISPATCH_AS_IS |
127 InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
128 window.targetFlags.clear(InputTarget::DISPATCH_MASK);
129 window.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
130 i += 1;
131 } else {
132 windows.erase(windows.begin() + i);
133 }
134 }
135}
136
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700137void TouchState::cancelPointersForWindowsExcept(int32_t touchedDeviceId,
138 std::bitset<MAX_POINTER_ID + 1> pointerIds,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000139 const sp<IBinder>& token) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700140 std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000141 if (w.windowHandle->getToken() != token) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700142 w.removeTouchingPointers(touchedDeviceId, pointerIds);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000143 }
144 });
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800145 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000146}
147
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800148/**
149 * For any pointer that's being pilfered, remove it from all of the other windows that currently
150 * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and
151 * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window
152 * B.
153 */
154void TouchState::cancelPointersForNonPilferingWindows() {
155 // First, find all pointers that are being pilfered, across all windows
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700156 std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
157 for (const TouchedWindow& w : windows) {
158 for (const auto& [iterDeviceId, pilferedPointerIds] : w.getPilferingPointers()) {
159 allPilferedPointerIdsByDevice[iterDeviceId] |= pilferedPointerIds;
160 }
161 };
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800162
163 // Optimization: most of the time, pilfering does not occur
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700164 if (allPilferedPointerIdsByDevice.empty()) return;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800165
166 // Now, remove all pointers from every window that's being pilfered by other windows.
167 // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2
168 // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
169 // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
170 // limitation here.
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700171 for (const auto& [iterDeviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
172 std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
173 std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
174 w.getPilferingPointers(iterDeviceId) ^ allPilferedPointerIds;
175 // Remove all pointers pilfered by other windows
176 w.removeTouchingPointers(iterDeviceId, pilferedByOtherWindows);
177 });
178 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800179 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000180}
181
chaviw98318de2021-05-19 16:45:23 -0500182sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700183 for (size_t i = 0; i < windows.size(); i++) {
184 const TouchedWindow& window = windows[i];
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800185 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700186 return window.windowHandle;
187 }
188 }
189 return nullptr;
190}
191
192bool TouchState::isSlippery() const {
193 // Must have exactly one foreground window.
194 bool haveSlipperyForegroundWindow = false;
195 for (const TouchedWindow& window : windows) {
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800196 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700197 if (haveSlipperyForegroundWindow ||
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800198 !window.windowHandle->getInfo()->inputConfig.test(
199 WindowInfo::InputConfig::SLIPPERY)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700200 return false;
201 }
202 haveSlipperyForegroundWindow = true;
203 }
204 }
205 return haveSlipperyForegroundWindow;
206}
207
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000208sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
209 for (size_t i = 0; i < windows.size(); i++) {
210 const TouchedWindow& window = windows[i];
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800211 if (window.windowHandle->getInfo()->inputConfig.test(
212 gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000213 return window.windowHandle;
214 }
215 }
216 return nullptr;
217}
218
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -0800219const TouchedWindow& TouchState::getTouchedWindow(const sp<WindowInfoHandle>& windowHandle) const {
220 auto it = std::find_if(windows.begin(), windows.end(),
221 [&](const TouchedWindow& w) { return w.windowHandle == windowHandle; });
222 LOG_ALWAYS_FATAL_IF(it == windows.end(), "Could not find %s", windowHandle->getName().c_str());
223 return *it;
224}
225
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700226bool TouchState::isDown() const {
227 return std::any_of(windows.begin(), windows.end(),
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700228 [](const TouchedWindow& window) { return window.hasTouchingPointers(); });
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700229}
230
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800231bool TouchState::hasHoveringPointers() const {
232 return std::any_of(windows.begin(), windows.end(),
233 [](const TouchedWindow& window) { return window.hasHoveringPointers(); });
234}
235
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000236std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(int32_t hoveringDeviceId,
237 int32_t pointerId) const {
238 std::set<sp<WindowInfoHandle>> out;
239 for (const TouchedWindow& window : windows) {
240 if (window.hasHoveringPointer(hoveringDeviceId, pointerId)) {
241 out.insert(window.windowHandle);
242 }
243 }
244 return out;
245}
246
247void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoveringPointerId) {
248 for (TouchedWindow& window : windows) {
249 window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId);
250 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800251 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000252}
253
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700254void TouchState::removeAllPointersForDevice(int32_t removedDeviceId) {
255 for (TouchedWindow& window : windows) {
256 window.removeAllHoveringPointersForDevice(removedDeviceId);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700257 window.removeAllTouchingPointersForDevice(removedDeviceId);
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700258 }
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700259
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700260 clearWindowsWithoutPointers();
261}
262
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800263std::string TouchState::dump() const {
264 std::string out;
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -0800265 out += StringPrintf("deviceId=%d, source=%s\n", deviceId,
266 inputEventSourceToString(source).c_str());
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800267 if (!windows.empty()) {
268 out += " Windows:\n";
269 for (size_t i = 0; i < windows.size(); i++) {
270 const TouchedWindow& touchedWindow = windows[i];
271 out += StringPrintf(" %zu : ", i) + touchedWindow.dump();
272 }
273 } else {
274 out += " Windows: <none>\n";
275 }
276 return out;
277}
278
Garfield Tane84e6f92019-08-29 17:28:41 -0700279} // namespace android::inputdispatcher