blob: 2ead171155768369aa388c4d90b1c3b0b8a05f8b [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 Vishniakou2899c552023-07-10 18:20:46 -070017#include <android-base/logging.h>
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -080018#include <android-base/stringprintf.h>
chaviw98318de2021-05-19 16:45:23 -050019#include <gui/WindowInfo.h>
Garfield Tane84e6f92019-08-29 17:28:41 -070020
21#include "InputTarget.h"
Garfield Tane84e6f92019-08-29 17:28:41 -070022#include "TouchState.h"
23
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080024using namespace android::ftl::flag_operators;
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -080025using android::base::StringPrintf;
chaviw98318de2021-05-19 16:45:23 -050026using android::gui::WindowInfo;
27using android::gui::WindowInfoHandle;
Garfield Tane84e6f92019-08-29 17:28:41 -070028
29namespace android::inputdispatcher {
30
Garfield Tane84e6f92019-08-29 17:28:41 -070031void TouchState::reset() {
Prabir Pradhane680f9b2022-02-04 04:24:00 -080032 *this = TouchState();
Garfield Tane84e6f92019-08-29 17:28:41 -070033}
34
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070035bool TouchState::hasTouchingPointers(DeviceId deviceId) const {
Siarhei Vishniakou45504fe2023-05-05 16:05:10 -070036 return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) {
37 return window.hasTouchingPointers(deviceId);
38 });
39}
40
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070041void TouchState::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000042 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070043 touchedWindow.removeTouchingPointer(deviceId, pointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000044 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080045 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000046}
47
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070048void TouchState::removeTouchingPointerFromWindow(
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070049 DeviceId deviceId, int32_t pointerId,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070050 const sp<android::gui::WindowInfoHandle>& windowHandle) {
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080051 for (TouchedWindow& touchedWindow : windows) {
52 if (touchedWindow.windowHandle == windowHandle) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070053 touchedWindow.removeTouchingPointer(deviceId, pointerId);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080054 clearWindowsWithoutPointers();
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080055 return;
56 }
57 }
58}
59
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070060void TouchState::clearHoveringPointers(DeviceId deviceId) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000061 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070062 touchedWindow.removeAllHoveringPointersForDevice(deviceId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000063 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080064 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000065}
66
67void TouchState::clearWindowsWithoutPointers() {
68 std::erase_if(windows, [](const TouchedWindow& w) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070069 return !w.hasTouchingPointers() && !w.hasHoveringPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000070 });
71}
72
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080073void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070074 ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070075 std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -080076 std::optional<nsecs_t> firstDownTimeInTarget) {
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070077 if (touchingPointerIds.none()) {
78 LOG(FATAL) << __func__ << "No pointers specified for " << windowHandle->getName();
79 return;
80 }
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -080081 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000082 // We do not compare windows by token here because two windows that share the same token
Siarhei Vishniakou2899c552023-07-10 18:20:46 -070083 // may have a different transform. They will be combined later when we create InputTargets.
84 // At that point, per-pointer window transform will be considered.
85 // An alternative design choice here would have been to compare here by token, but to
86 // store per-pointer transform.
Garfield Tane84e6f92019-08-29 17:28:41 -070087 if (touchedWindow.windowHandle == windowHandle) {
88 touchedWindow.targetFlags |= targetFlags;
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080089 if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
90 touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
Garfield Tane84e6f92019-08-29 17:28:41 -070091 }
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000092 // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070093 // downTime set initially. Need to update existing window when a pointer is down for the
94 // window.
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070095 touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -070096 if (firstDownTimeInTarget) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -070097 touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000098 }
Garfield Tane84e6f92019-08-29 17:28:41 -070099 return;
100 }
101 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700102 TouchedWindow touchedWindow;
103 touchedWindow.windowHandle = windowHandle;
104 touchedWindow.targetFlags = targetFlags;
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700105 touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700106 if (firstDownTimeInTarget) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700107 touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700108 }
Garfield Tane84e6f92019-08-29 17:28:41 -0700109 windows.push_back(touchedWindow);
110}
111
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000112void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700113 DeviceId deviceId, int32_t hoveringPointerId) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000114 for (TouchedWindow& touchedWindow : windows) {
115 if (touchedWindow.windowHandle == windowHandle) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700116 touchedWindow.addHoveringPointer(deviceId, hoveringPointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000117 return;
118 }
119 }
120
121 TouchedWindow touchedWindow;
122 touchedWindow.windowHandle = windowHandle;
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700123 touchedWindow.addHoveringPointer(deviceId, hoveringPointerId);
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000124 windows.push_back(touchedWindow);
125}
126
Garfield Tane84e6f92019-08-29 17:28:41 -0700127void TouchState::removeWindowByToken(const sp<IBinder>& token) {
128 for (size_t i = 0; i < windows.size(); i++) {
129 if (windows[i].windowHandle->getToken() == token) {
130 windows.erase(windows.begin() + i);
131 return;
132 }
133 }
134}
135
Sam Dubeyf886dec2023-01-27 13:28:19 +0000136void TouchState::filterNonAsIsTouchWindows() {
137 for (size_t i = 0; i < windows.size();) {
138 TouchedWindow& window = windows[i];
139 if (window.targetFlags.any(InputTarget::Flags::DISPATCH_AS_IS |
140 InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
141 window.targetFlags.clear(InputTarget::DISPATCH_MASK);
142 window.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
143 i += 1;
144 } else {
145 windows.erase(windows.begin() + i);
146 }
147 }
148}
149
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700150void TouchState::cancelPointersForWindowsExcept(DeviceId deviceId,
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700151 std::bitset<MAX_POINTER_ID + 1> pointerIds,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000152 const sp<IBinder>& token) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700153 std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000154 if (w.windowHandle->getToken() != token) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700155 w.removeTouchingPointers(deviceId, pointerIds);
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000156 }
157 });
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800158 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000159}
160
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800161/**
162 * For any pointer that's being pilfered, remove it from all of the other windows that currently
163 * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and
164 * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window
165 * B.
166 */
167void TouchState::cancelPointersForNonPilferingWindows() {
168 // First, find all pointers that are being pilfered, across all windows
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700169 std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700170 for (const TouchedWindow& w : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700171 for (const auto& [deviceId, pilferedPointerIds] : w.getPilferingPointers()) {
172 allPilferedPointerIdsByDevice[deviceId] |= pilferedPointerIds;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700173 }
174 };
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800175
176 // Optimization: most of the time, pilfering does not occur
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700177 if (allPilferedPointerIdsByDevice.empty()) return;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800178
179 // Now, remove all pointers from every window that's being pilfered by other windows.
180 // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2
181 // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
182 // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
183 // limitation here.
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700184 for (const auto& [deviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700185 std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
186 std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700187 w.getPilferingPointers(deviceId) ^ allPilferedPointerIds;
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700188 // Remove all pointers pilfered by other windows
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700189 w.removeTouchingPointers(deviceId, pilferedByOtherWindows);
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700190 });
191 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800192 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000193}
194
chaviw98318de2021-05-19 16:45:23 -0500195sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700196 for (size_t i = 0; i < windows.size(); i++) {
197 const TouchedWindow& window = windows[i];
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800198 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700199 return window.windowHandle;
200 }
201 }
202 return nullptr;
203}
204
205bool TouchState::isSlippery() const {
206 // Must have exactly one foreground window.
207 bool haveSlipperyForegroundWindow = false;
208 for (const TouchedWindow& window : windows) {
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800209 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700210 if (haveSlipperyForegroundWindow ||
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800211 !window.windowHandle->getInfo()->inputConfig.test(
212 WindowInfo::InputConfig::SLIPPERY)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700213 return false;
214 }
215 haveSlipperyForegroundWindow = true;
216 }
217 }
218 return haveSlipperyForegroundWindow;
219}
220
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000221sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
222 for (size_t i = 0; i < windows.size(); i++) {
223 const TouchedWindow& window = windows[i];
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800224 if (window.windowHandle->getInfo()->inputConfig.test(
225 gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000226 return window.windowHandle;
227 }
228 }
229 return nullptr;
230}
231
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -0800232const TouchedWindow& TouchState::getTouchedWindow(const sp<WindowInfoHandle>& windowHandle) const {
233 auto it = std::find_if(windows.begin(), windows.end(),
234 [&](const TouchedWindow& w) { return w.windowHandle == windowHandle; });
235 LOG_ALWAYS_FATAL_IF(it == windows.end(), "Could not find %s", windowHandle->getName().c_str());
236 return *it;
237}
238
Siarhei Vishniakou2899c552023-07-10 18:20:46 -0700239bool TouchState::isDown(DeviceId deviceId) const {
240 return std::any_of(windows.begin(), windows.end(), [&deviceId](const TouchedWindow& window) {
241 return window.hasTouchingPointers(deviceId);
242 });
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700243}
244
Siarhei Vishniakou2899c552023-07-10 18:20:46 -0700245bool TouchState::hasHoveringPointers(DeviceId deviceId) const {
246 return std::any_of(windows.begin(), windows.end(), [&deviceId](const TouchedWindow& window) {
247 return window.hasHoveringPointers(deviceId);
248 });
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800249}
250
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700251std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId,
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000252 int32_t pointerId) const {
253 std::set<sp<WindowInfoHandle>> out;
254 for (const TouchedWindow& window : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700255 if (window.hasHoveringPointer(deviceId, pointerId)) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000256 out.insert(window.windowHandle);
257 }
258 }
259 return out;
260}
261
262void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoveringPointerId) {
263 for (TouchedWindow& window : windows) {
264 window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId);
265 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800266 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000267}
268
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700269void TouchState::removeAllPointersForDevice(DeviceId deviceId) {
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700270 for (TouchedWindow& window : windows) {
Siarhei Vishniakou7e2f8f12023-07-11 10:51:20 -0700271 window.removeAllHoveringPointersForDevice(deviceId);
272 window.removeAllTouchingPointersForDevice(deviceId);
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700273 }
Siarhei Vishniakou0836a302023-05-03 13:54:30 -0700274
Siarhei Vishniakou0686f0c2023-05-02 11:56:15 -0700275 clearWindowsWithoutPointers();
276}
277
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800278std::string TouchState::dump() const {
279 std::string out;
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800280 if (!windows.empty()) {
281 out += " Windows:\n";
282 for (size_t i = 0; i < windows.size(); i++) {
283 const TouchedWindow& touchedWindow = windows[i];
284 out += StringPrintf(" %zu : ", i) + touchedWindow.dump();
285 }
286 } else {
287 out += " Windows: <none>\n";
288 }
289 return out;
290}
291
Siarhei Vishniakou72945a02023-09-18 18:30:25 -0700292std::ostream& operator<<(std::ostream& out, const TouchState& state) {
293 out << state.dump();
294 return out;
295}
296
Garfield Tane84e6f92019-08-29 17:28:41 -0700297} // namespace android::inputdispatcher