blob: 8ce61e7800d9cdeeab839e98bd61afd46a766f1a [file] [log] [blame]
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001/*
2 * Copyright 2023 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#pragma once
18
19#include <android-base/logging.h>
Siarhei Vishniakou0438ca82024-03-12 14:27:25 -070020#include <input/InputConsumer.h>
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070021#include "../dispatcher/InputDispatcher.h"
22
23using android::base::Result;
24using android::gui::Pid;
25using android::gui::TouchOcclusionMode;
26using android::gui::Uid;
27using android::gui::WindowInfo;
28using android::gui::WindowInfoHandle;
29
30namespace android {
31namespace inputdispatcher {
32
33namespace {
34
35// The default pid and uid for windows created by the test.
36constexpr gui::Pid WINDOW_PID{999};
37constexpr gui::Uid WINDOW_UID{1001};
38
39static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
40
41} // namespace
42
43class FakeInputReceiver {
44public:
45 std::unique_ptr<InputEvent> consumeEvent(std::chrono::milliseconds timeout) {
46 uint32_t consumeSeq = 0;
47 std::unique_ptr<InputEvent> event;
48
49 std::chrono::time_point start = std::chrono::steady_clock::now();
50 status_t result = WOULD_BLOCK;
51 while (result == WOULD_BLOCK) {
52 InputEvent* rawEventPtr = nullptr;
53 result = mConsumer.consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq,
54 &rawEventPtr);
55 event = std::unique_ptr<InputEvent>(rawEventPtr);
56 std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
57 if (elapsed > timeout) {
58 if (timeout != 0ms) {
59 LOG(ERROR) << "Waited too long for consumer to produce an event, giving up";
60 }
61 break;
62 }
63 }
64 // Events produced by this factory are owned pointers.
65 if (result != OK) {
66 if (timeout == 0ms) {
67 // This is likely expected. No need to log.
68 } else {
69 LOG(ERROR) << "Received result = " << result << " from consume";
70 }
71 return nullptr;
72 }
73 result = mConsumer.sendFinishedSignal(consumeSeq, true);
74 if (result != OK) {
75 LOG(ERROR) << "Received result = " << result << " from sendFinishedSignal";
76 }
77 return event;
78 }
79
80 explicit FakeInputReceiver(std::unique_ptr<InputChannel> channel, const std::string name)
81 : mConsumer(std::move(channel)) {}
82
83 virtual ~FakeInputReceiver() {}
84
85private:
86 std::unique_ptr<InputChannel> mClientChannel;
87 InputConsumer mConsumer;
88 DynamicInputEventFactory mEventFactory;
89};
90
91class FakeWindowHandle : public WindowInfoHandle {
92public:
93 static const int32_t WIDTH = 600;
94 static const int32_t HEIGHT = 800;
95
96 FakeWindowHandle(const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
97 InputDispatcher& dispatcher, const std::string name, int32_t displayId)
98 : mName(name) {
99 Result<std::unique_ptr<InputChannel>> channel = dispatcher.createInputChannel(name);
100 mInfo.token = (*channel)->getConnectionToken();
101 mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
102
103 inputApplicationHandle->updateInfo();
104 mInfo.applicationInfo = *inputApplicationHandle->getInfo();
105
106 mInfo.id = sId++;
107 mInfo.name = name;
108 mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
109 mInfo.alpha = 1.0;
110 mInfo.frame.left = 0;
111 mInfo.frame.top = 0;
112 mInfo.frame.right = WIDTH;
113 mInfo.frame.bottom = HEIGHT;
114 mInfo.transform.set(0, 0);
115 mInfo.globalScaleFactor = 1.0;
116 mInfo.touchableRegion.clear();
117 mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
118 mInfo.ownerPid = WINDOW_PID;
119 mInfo.ownerUid = WINDOW_UID;
120 mInfo.displayId = displayId;
121 mInfo.inputConfig = WindowInfo::InputConfig::DEFAULT;
122 }
123
124 sp<FakeWindowHandle> clone(int32_t displayId) {
125 sp<FakeWindowHandle> handle = sp<FakeWindowHandle>::make(mInfo.name + "(Mirror)");
126 handle->mInfo = mInfo;
127 handle->mInfo.displayId = displayId;
128 handle->mInfo.id = sId++;
129 handle->mInputReceiver = mInputReceiver;
130 return handle;
131 }
132
133 void setTouchable(bool touchable) {
134 mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable);
135 }
136
137 void setFocusable(bool focusable) {
138 mInfo.setInputConfig(WindowInfo::InputConfig::NOT_FOCUSABLE, !focusable);
139 }
140
141 void setVisible(bool visible) {
142 mInfo.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
143 }
144
145 void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
146 mInfo.dispatchingTimeout = timeout;
147 }
148
149 void setPaused(bool paused) {
150 mInfo.setInputConfig(WindowInfo::InputConfig::PAUSE_DISPATCHING, paused);
151 }
152
153 void setPreventSplitting(bool preventSplitting) {
154 mInfo.setInputConfig(WindowInfo::InputConfig::PREVENT_SPLITTING, preventSplitting);
155 }
156
157 void setSlippery(bool slippery) {
158 mInfo.setInputConfig(WindowInfo::InputConfig::SLIPPERY, slippery);
159 }
160
161 void setWatchOutsideTouch(bool watchOutside) {
162 mInfo.setInputConfig(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH, watchOutside);
163 }
164
165 void setSpy(bool spy) { mInfo.setInputConfig(WindowInfo::InputConfig::SPY, spy); }
166
167 void setInterceptsStylus(bool interceptsStylus) {
168 mInfo.setInputConfig(WindowInfo::InputConfig::INTERCEPTS_STYLUS, interceptsStylus);
169 }
170
171 void setDropInput(bool dropInput) {
172 mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT, dropInput);
173 }
174
175 void setDropInputIfObscured(bool dropInputIfObscured) {
176 mInfo.setInputConfig(WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED, dropInputIfObscured);
177 }
178
179 void setNoInputChannel(bool noInputChannel) {
180 mInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, noInputChannel);
181 }
182
183 void setDisableUserActivity(bool disableUserActivity) {
184 mInfo.setInputConfig(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY, disableUserActivity);
185 }
186
187 void setAlpha(float alpha) { mInfo.alpha = alpha; }
188
189 void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; }
190
191 void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; }
192
193 void setFrame(const Rect& frame, const ui::Transform& displayTransform = ui::Transform()) {
194 mInfo.frame.left = frame.left;
195 mInfo.frame.top = frame.top;
196 mInfo.frame.right = frame.right;
197 mInfo.frame.bottom = frame.bottom;
198 mInfo.touchableRegion.clear();
199 mInfo.addTouchableRegion(frame);
200
201 const Rect logicalDisplayFrame = displayTransform.transform(frame);
202 ui::Transform translate;
203 translate.set(-logicalDisplayFrame.left, -logicalDisplayFrame.top);
204 mInfo.transform = translate * displayTransform;
205 }
206
207 void setTouchableRegion(const Region& region) { mInfo.touchableRegion = region; }
208
209 void setIsWallpaper(bool isWallpaper) {
210 mInfo.setInputConfig(WindowInfo::InputConfig::IS_WALLPAPER, isWallpaper);
211 }
212
213 void setDupTouchToWallpaper(bool hasWallpaper) {
214 mInfo.setInputConfig(WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER, hasWallpaper);
215 }
216
217 void setTrustedOverlay(bool trustedOverlay) {
218 mInfo.setInputConfig(WindowInfo::InputConfig::TRUSTED_OVERLAY, trustedOverlay);
219 }
220
221 void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
222 mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
223 }
224
225 void setWindowScale(float xScale, float yScale) { setWindowTransform(xScale, 0, 0, yScale); }
226
227 void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); }
228
229 std::unique_ptr<InputEvent> consume(std::chrono::milliseconds timeout) {
230 if (mInputReceiver == nullptr) {
231 return nullptr;
232 }
233 return mInputReceiver->consumeEvent(timeout);
234 }
235
236 void consumeMotion() {
237 std::unique_ptr<InputEvent> event = consume(100ms);
238
239 if (event == nullptr) {
240 LOG(FATAL) << mName << ": expected a MotionEvent, but didn't get one.";
241 return;
242 }
243
244 if (event->getType() != InputEventType::MOTION) {
245 LOG(FATAL) << mName << " expected a MotionEvent, got " << *event;
246 return;
247 }
248 }
249
250 sp<IBinder> getToken() { return mInfo.token; }
251
252 const std::string& getName() { return mName; }
253
254 void setOwnerInfo(Pid ownerPid, Uid ownerUid) {
255 mInfo.ownerPid = ownerPid;
256 mInfo.ownerUid = ownerUid;
257 }
258
259 Pid getPid() const { return mInfo.ownerPid; }
260
261 void destroyReceiver() { mInputReceiver = nullptr; }
262
263private:
264 FakeWindowHandle(std::string name) : mName(name){};
265 const std::string mName;
266 std::shared_ptr<FakeInputReceiver> mInputReceiver;
267 static std::atomic<int32_t> sId; // each window gets a unique id, like in surfaceflinger
268 friend class sp<FakeWindowHandle>;
269};
270
271std::atomic<int32_t> FakeWindowHandle::sId{1};
272
273} // namespace inputdispatcher
274
275} // namespace android