1 /*
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 
17 #include <input/InputWindow.h>
18 
19 #include "InputTarget.h"
20 
21 #include "TouchState.h"
22 
23 using android::InputWindowHandle;
24 
25 namespace android::inputdispatcher {
26 
TouchState()27 TouchState::TouchState()
28       : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {}
29 
~TouchState()30 TouchState::~TouchState() {}
31 
reset()32 void TouchState::reset() {
33     down = false;
34     split = false;
35     deviceId = -1;
36     source = 0;
37     displayId = ADISPLAY_ID_NONE;
38     windows.clear();
39     portalWindows.clear();
40     gestureMonitors.clear();
41 }
42 
copyFrom(const TouchState & other)43 void TouchState::copyFrom(const TouchState& other) {
44     down = other.down;
45     split = other.split;
46     deviceId = other.deviceId;
47     source = other.source;
48     displayId = other.displayId;
49     windows = other.windows;
50     portalWindows = other.portalWindows;
51     gestureMonitors = other.gestureMonitors;
52 }
53 
addOrUpdateWindow(const sp<InputWindowHandle> & windowHandle,int32_t targetFlags,BitSet32 pointerIds)54 void TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags,
55                                    BitSet32 pointerIds) {
56     if (targetFlags & InputTarget::FLAG_SPLIT) {
57         split = true;
58     }
59 
60     for (size_t i = 0; i < windows.size(); i++) {
61         TouchedWindow& touchedWindow = windows[i];
62         if (touchedWindow.windowHandle == windowHandle) {
63             touchedWindow.targetFlags |= targetFlags;
64             if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
65                 touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
66             }
67             touchedWindow.pointerIds.value |= pointerIds.value;
68             return;
69         }
70     }
71 
72     TouchedWindow touchedWindow;
73     touchedWindow.windowHandle = windowHandle;
74     touchedWindow.targetFlags = targetFlags;
75     touchedWindow.pointerIds = pointerIds;
76     windows.push_back(touchedWindow);
77 }
78 
addPortalWindow(const sp<InputWindowHandle> & windowHandle)79 void TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
80     size_t numWindows = portalWindows.size();
81     for (size_t i = 0; i < numWindows; i++) {
82         if (portalWindows[i] == windowHandle) {
83             return;
84         }
85     }
86     portalWindows.push_back(windowHandle);
87 }
88 
addGestureMonitors(const std::vector<TouchedMonitor> & newMonitors)89 void TouchState::addGestureMonitors(const std::vector<TouchedMonitor>& newMonitors) {
90     const size_t newSize = gestureMonitors.size() + newMonitors.size();
91     gestureMonitors.reserve(newSize);
92     gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors),
93                            std::end(newMonitors));
94 }
95 
removeWindow(const sp<InputWindowHandle> & windowHandle)96 void TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
97     for (size_t i = 0; i < windows.size(); i++) {
98         if (windows[i].windowHandle == windowHandle) {
99             windows.erase(windows.begin() + i);
100             return;
101         }
102     }
103 }
104 
removeWindowByToken(const sp<IBinder> & token)105 void TouchState::removeWindowByToken(const sp<IBinder>& token) {
106     for (size_t i = 0; i < windows.size(); i++) {
107         if (windows[i].windowHandle->getToken() == token) {
108             windows.erase(windows.begin() + i);
109             return;
110         }
111     }
112 }
113 
filterNonAsIsTouchWindows()114 void TouchState::filterNonAsIsTouchWindows() {
115     for (size_t i = 0; i < windows.size();) {
116         TouchedWindow& window = windows[i];
117         if (window.targetFlags &
118             (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
119             window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
120             window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
121             i += 1;
122         } else {
123             windows.erase(windows.begin() + i);
124         }
125     }
126 }
127 
filterNonMonitors()128 void TouchState::filterNonMonitors() {
129     windows.clear();
130     portalWindows.clear();
131 }
132 
getFirstForegroundWindowHandle() const133 sp<InputWindowHandle> TouchState::getFirstForegroundWindowHandle() const {
134     for (size_t i = 0; i < windows.size(); i++) {
135         const TouchedWindow& window = windows[i];
136         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
137             return window.windowHandle;
138         }
139     }
140     return nullptr;
141 }
142 
isSlippery() const143 bool TouchState::isSlippery() const {
144     // Must have exactly one foreground window.
145     bool haveSlipperyForegroundWindow = false;
146     for (const TouchedWindow& window : windows) {
147         if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
148             if (haveSlipperyForegroundWindow ||
149                 !(window.windowHandle->getInfo()->layoutParamsFlags &
150                   InputWindowInfo::FLAG_SLIPPERY)) {
151                 return false;
152             }
153             haveSlipperyForegroundWindow = true;
154         }
155     }
156     return haveSlipperyForegroundWindow;
157 }
158 
159 } // namespace android::inputdispatcher
160