blob: 9c443f14cf11099108caec054f3c2be43c3f9be6 [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 Vishniakoub581f7f2022-12-07 20:23:06 +000034void TouchState::removeTouchedPointer(int32_t pointerId) {
35 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakou6464e462023-02-06 18:57:59 -080036 touchedWindow.removeTouchingPointer(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 Vishniakou0026b4c2022-11-10 19:33:29 -080041void TouchState::removeTouchedPointerFromWindow(
42 int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) {
43 for (TouchedWindow& touchedWindow : windows) {
44 if (touchedWindow.windowHandle == windowHandle) {
Siarhei Vishniakou6464e462023-02-06 18:57:59 -080045 touchedWindow.removeTouchingPointer(pointerId);
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080046 clearWindowsWithoutPointers();
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -080047 return;
48 }
49 }
50}
51
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000052void TouchState::clearHoveringPointers() {
53 for (TouchedWindow& touchedWindow : windows) {
54 touchedWindow.clearHoveringPointers();
55 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -080056 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000057}
58
59void TouchState::clearWindowsWithoutPointers() {
60 std::erase_if(windows, [](const TouchedWindow& w) {
Siarhei Vishniakou8a878352023-01-30 14:05:01 -080061 return w.pointerIds.none() && !w.hasHoveringPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000062 });
63}
64
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080065void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
Siarhei Vishniakou8a878352023-01-30 14:05:01 -080066 ftl::Flags<InputTarget::Flags> targetFlags,
67 std::bitset<MAX_POINTER_ID + 1> pointerIds,
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -080068 std::optional<nsecs_t> firstDownTimeInTarget) {
Siarhei Vishniakou5cee1e32022-11-29 12:35:39 -080069 for (TouchedWindow& touchedWindow : windows) {
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000070 // We do not compare windows by token here because two windows that share the same token
71 // may have a different transform
Garfield Tane84e6f92019-08-29 17:28:41 -070072 if (touchedWindow.windowHandle == windowHandle) {
73 touchedWindow.targetFlags |= targetFlags;
Siarhei Vishniakou253f4642022-11-09 13:42:06 -080074 if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
75 touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
Garfield Tane84e6f92019-08-29 17:28:41 -070076 }
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000077 // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
78 // downTime set initially. Need to update existing window when an pointer is down for
79 // the window.
Siarhei Vishniakou8a878352023-01-30 14:05:01 -080080 touchedWindow.pointerIds |= pointerIds;
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000081 if (!touchedWindow.firstDownTimeInTarget.has_value()) {
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -080082 touchedWindow.firstDownTimeInTarget = firstDownTimeInTarget;
Vaibhav Devmurari882bd9b2022-06-23 14:54:54 +000083 }
Garfield Tane84e6f92019-08-29 17:28:41 -070084 return;
85 }
86 }
Garfield Tane84e6f92019-08-29 17:28:41 -070087 TouchedWindow touchedWindow;
88 touchedWindow.windowHandle = windowHandle;
89 touchedWindow.targetFlags = targetFlags;
90 touchedWindow.pointerIds = pointerIds;
Siarhei Vishniakoue0431e42023-01-28 17:01:39 -080091 touchedWindow.firstDownTimeInTarget = firstDownTimeInTarget;
Garfield Tane84e6f92019-08-29 17:28:41 -070092 windows.push_back(touchedWindow);
93}
94
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +000095void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
96 int32_t hoveringDeviceId, int32_t hoveringPointerId) {
97 for (TouchedWindow& touchedWindow : windows) {
98 if (touchedWindow.windowHandle == windowHandle) {
99 touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId);
100 return;
101 }
102 }
103
104 TouchedWindow touchedWindow;
105 touchedWindow.windowHandle = windowHandle;
106 touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId);
107 windows.push_back(touchedWindow);
108}
109
Garfield Tane84e6f92019-08-29 17:28:41 -0700110void TouchState::removeWindowByToken(const sp<IBinder>& token) {
111 for (size_t i = 0; i < windows.size(); i++) {
112 if (windows[i].windowHandle->getToken() == token) {
113 windows.erase(windows.begin() + i);
114 return;
115 }
116 }
117}
118
Sam Dubeyf886dec2023-01-27 13:28:19 +0000119void TouchState::filterNonAsIsTouchWindows() {
120 for (size_t i = 0; i < windows.size();) {
121 TouchedWindow& window = windows[i];
122 if (window.targetFlags.any(InputTarget::Flags::DISPATCH_AS_IS |
123 InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
124 window.targetFlags.clear(InputTarget::DISPATCH_MASK);
125 window.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
126 i += 1;
127 } else {
128 windows.erase(windows.begin() + i);
129 }
130 }
131}
132
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800133void TouchState::cancelPointersForWindowsExcept(std::bitset<MAX_POINTER_ID + 1> pointerIds,
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000134 const sp<IBinder>& token) {
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800135 if (pointerIds.none()) return;
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000136 std::for_each(windows.begin(), windows.end(), [&pointerIds, &token](TouchedWindow& w) {
137 if (w.windowHandle->getToken() != token) {
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800138 w.pointerIds &= ~pointerIds;
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000139 }
140 });
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800141 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000142}
143
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800144/**
145 * For any pointer that's being pilfered, remove it from all of the other windows that currently
146 * aren't pilfering it. For example, if we determined that pointer 1 is going to both window A and
147 * window B, but window A is currently pilfering pointer 1, then pointer 1 should not go to window
148 * B.
149 */
150void TouchState::cancelPointersForNonPilferingWindows() {
151 // First, find all pointers that are being pilfered, across all windows
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800152 std::bitset<MAX_POINTER_ID + 1> allPilferedPointerIds;
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800153 std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](const TouchedWindow& w) {
154 allPilferedPointerIds |= w.pilferedPointerIds;
155 });
156
157 // Optimization: most of the time, pilfering does not occur
158 if (allPilferedPointerIds.none()) return;
159
160 // Now, remove all pointers from every window that's being pilfered by other windows.
161 // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2
162 // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
163 // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
164 // limitation here.
165 std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](TouchedWindow& w) {
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800166 std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
Siarhei Vishniakou060f82b2023-01-27 06:39:14 -0800167 w.pilferedPointerIds ^ allPilferedPointerIds;
Siarhei Vishniakou9af4e112023-02-06 10:49:07 -0800168 w.pointerIds &= ~pilferedByOtherWindows;
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000169 });
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800170 clearWindowsWithoutPointers();
Vaibhav Devmurariff798f32022-05-09 23:45:04 +0000171}
172
chaviw98318de2021-05-19 16:45:23 -0500173sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
Garfield Tane84e6f92019-08-29 17:28:41 -0700174 for (size_t i = 0; i < windows.size(); i++) {
175 const TouchedWindow& window = windows[i];
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800176 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700177 return window.windowHandle;
178 }
179 }
180 return nullptr;
181}
182
183bool TouchState::isSlippery() const {
184 // Must have exactly one foreground window.
185 bool haveSlipperyForegroundWindow = false;
186 for (const TouchedWindow& window : windows) {
Siarhei Vishniakou253f4642022-11-09 13:42:06 -0800187 if (window.targetFlags.test(InputTarget::Flags::FOREGROUND)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700188 if (haveSlipperyForegroundWindow ||
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800189 !window.windowHandle->getInfo()->inputConfig.test(
190 WindowInfo::InputConfig::SLIPPERY)) {
Garfield Tane84e6f92019-08-29 17:28:41 -0700191 return false;
192 }
193 haveSlipperyForegroundWindow = true;
194 }
195 }
196 return haveSlipperyForegroundWindow;
197}
198
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000199sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
200 for (size_t i = 0; i < windows.size(); i++) {
201 const TouchedWindow& window = windows[i];
Prabir Pradhan4d5c52f2022-01-31 08:52:10 -0800202 if (window.windowHandle->getInfo()->inputConfig.test(
203 gui::WindowInfo::InputConfig::IS_WALLPAPER)) {
Siarhei Vishniakouca205502021-07-16 21:31:58 +0000204 return window.windowHandle;
205 }
206 }
207 return nullptr;
208}
209
Siarhei Vishniakou0026b4c2022-11-10 19:33:29 -0800210const TouchedWindow& TouchState::getTouchedWindow(const sp<WindowInfoHandle>& windowHandle) const {
211 auto it = std::find_if(windows.begin(), windows.end(),
212 [&](const TouchedWindow& w) { return w.windowHandle == windowHandle; });
213 LOG_ALWAYS_FATAL_IF(it == windows.end(), "Could not find %s", windowHandle->getName().c_str());
214 return *it;
215}
216
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700217bool TouchState::isDown() const {
218 return std::any_of(windows.begin(), windows.end(),
Siarhei Vishniakou8a878352023-01-30 14:05:01 -0800219 [](const TouchedWindow& window) { return window.pointerIds.any(); });
Siarhei Vishniakou3ad385b2022-11-04 10:09:53 -0700220}
221
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800222bool TouchState::hasHoveringPointers() const {
223 return std::any_of(windows.begin(), windows.end(),
224 [](const TouchedWindow& window) { return window.hasHoveringPointers(); });
225}
226
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000227std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(int32_t hoveringDeviceId,
228 int32_t pointerId) const {
229 std::set<sp<WindowInfoHandle>> out;
230 for (const TouchedWindow& window : windows) {
231 if (window.hasHoveringPointer(hoveringDeviceId, pointerId)) {
232 out.insert(window.windowHandle);
233 }
234 }
235 return out;
236}
237
238void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoveringPointerId) {
239 for (TouchedWindow& window : windows) {
240 window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId);
241 }
Siarhei Vishniakouf372b812023-02-14 18:06:51 -0800242 clearWindowsWithoutPointers();
Siarhei Vishniakoub581f7f2022-12-07 20:23:06 +0000243}
244
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800245std::string TouchState::dump() const {
246 std::string out;
Siarhei Vishniakou0b0374d2022-11-17 17:40:53 -0800247 out += StringPrintf("deviceId=%d, source=%s\n", deviceId,
248 inputEventSourceToString(source).c_str());
Siarhei Vishniakou6e1e9872022-11-08 17:51:35 -0800249 if (!windows.empty()) {
250 out += " Windows:\n";
251 for (size_t i = 0; i < windows.size(); i++) {
252 const TouchedWindow& touchedWindow = windows[i];
253 out += StringPrintf(" %zu : ", i) + touchedWindow.dump();
254 }
255 } else {
256 out += " Windows: <none>\n";
257 }
258 return out;
259}
260
Garfield Tane84e6f92019-08-29 17:28:41 -0700261} // namespace android::inputdispatcher