1 #include <android/input.h>
2 #include <gtest/gtest.h>
3 #include <linux/input.h>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cstring>
7
8 #include "EvdevInjector.h"
9 #include "VirtualTouchpadEvdev.h"
10
11 namespace android {
12 namespace dvr {
13
14 namespace {
15
16 class UInputForTesting : public EvdevInjector::UInput {
17 public:
~UInputForTesting()18 ~UInputForTesting() override {}
WriteInputEvent(uint16_t type,uint16_t code,int32_t value)19 void WriteInputEvent(uint16_t type, uint16_t code, int32_t value) {
20 struct input_event event;
21 memset(&event, 0, sizeof(event));
22 event.type = type;
23 event.code = code;
24 event.value = value;
25 Write(&event, sizeof(event));
26 }
27 };
28
29 // Recording test implementation of UInput.
30 //
31 class UInputRecorder : public UInputForTesting {
32 public:
UInputRecorder()33 UInputRecorder() {}
~UInputRecorder()34 ~UInputRecorder() override {}
35
GetString() const36 const std::string& GetString() const { return s_; }
Reset()37 void Reset() { s_.clear(); }
38
39 // UInput overrides:
40
Open()41 int Open() override {
42 s_ += "o;";
43 return 0;
44 }
45
Close()46 int Close() override {
47 s_ += "c;";
48 return 0;
49 }
50
Write(const void * buf,size_t count)51 int Write(const void* buf, size_t count) override {
52 s_ += "w(";
53 s_ += Encode(&count, sizeof(count));
54 s_ += ",";
55 s_ += Encode(buf, count);
56 s_ += ");";
57 return 0;
58 }
59
IoctlVoid(int request)60 int IoctlVoid(int request) override {
61 s_ += "i(";
62 s_ += Encode(&request, sizeof(request));
63 s_ += ");";
64 return 0;
65 }
66
IoctlSetInt(int request,int value)67 int IoctlSetInt(int request, int value) override {
68 s_ += "i(";
69 s_ += Encode(&request, sizeof(request));
70 s_ += ",";
71 s_ += Encode(&value, sizeof(value));
72 s_ += ");";
73 return 0;
74 }
75
76 private:
77 std::string s_;
78
Encode(const void * buf,size_t count)79 std::string Encode(const void* buf, size_t count) {
80 const char* in = static_cast<const char*>(buf);
81 char out[2 * count + 1];
82 for (size_t i = 0; i < count; ++i) {
83 snprintf(&out[2 * i], 3, "%02X", in[i]);
84 }
85 return out;
86 }
87 };
88
89 class EvdevInjectorForTesting : public EvdevInjector {
90 public:
EvdevInjectorForTesting()91 EvdevInjectorForTesting() { SetUInputForTesting(&record); }
GetUiDev() const92 const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
93 UInputRecorder record;
94 };
95
96 class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
97 public:
Create()98 static std::unique_ptr<VirtualTouchpad> Create() {
99 return std::unique_ptr<VirtualTouchpad>(New());
100 }
New()101 static VirtualTouchpadForTesting* New() {
102 VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
103 touchpad->Reset();
104 for (int t = 0; t < kTouchpads; ++t) {
105 touchpad->SetEvdevInjectorForTesting(t, &touchpad->injector[t]);
106 }
107 return touchpad;
108 }
GetTouchpadCount() const109 int GetTouchpadCount() const { return kTouchpads; }
110 EvdevInjectorForTesting injector[kTouchpads];
111 };
112
113 } // anonymous namespace
114
115 class VirtualTouchpadTest : public testing::Test {};
116
TEST_F(VirtualTouchpadTest,Goodness)117 TEST_F(VirtualTouchpadTest, Goodness) {
118 std::unique_ptr<VirtualTouchpadForTesting> touchpad(
119 VirtualTouchpadForTesting::New());
120 UInputRecorder expect;
121
122 status_t touch_status = touchpad->Attach();
123 EXPECT_EQ(0, touch_status);
124
125 // Check some aspects of uinput_user_dev.
126 const uinput_user_dev* uidev;
127 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
128 SCOPED_TRACE(t);
129 uidev = touchpad->injector[t].GetUiDev();
130 String8 name;
131 name.appendFormat("vr-virtual-touchpad-%d", t);
132 EXPECT_EQ(name, uidev->name);
133 for (int i = 0; i < ABS_CNT; ++i) {
134 EXPECT_EQ(0, uidev->absmin[i]);
135 EXPECT_EQ(0, uidev->absfuzz[i]);
136 EXPECT_EQ(0, uidev->absflat[i]);
137 if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y &&
138 i != ABS_MT_SLOT) {
139 EXPECT_EQ(0, uidev->absmax[i]);
140 }
141 }
142 }
143 const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
144 const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
145
146 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
147 SCOPED_TRACE(t);
148 // Check the system calls performed by initialization.
149 expect.Reset();
150 // From ConfigureBegin():
151 expect.Open();
152 // From ConfigureInputProperty(INPUT_PROP_DIRECT):
153 expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
154 // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
155 expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
156 expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
157 expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
158 // From ConfigureAbsSlots(kSlots):
159 expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
160 // From ConfigureRel(REL_WHEEL):
161 expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
162 expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
163 // From ConfigureRel(REL_HWHEEL):
164 expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
165 // From ConfigureKey(BTN_TOUCH):
166 expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
167 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
168 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
169 // From ConfigureEnd():
170 expect.Write(touchpad->injector[t].GetUiDev(), sizeof(uinput_user_dev));
171 expect.IoctlVoid(UI_DEV_CREATE);
172 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
173 }
174
175 expect.Reset();
176 expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
177 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
178 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
179 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
180 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
181 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
182 SCOPED_TRACE(t);
183 touchpad->injector[t].record.Reset();
184 touch_status = touchpad->Touch(t, 0, 0, 0);
185 EXPECT_EQ(0, touch_status);
186 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
187 }
188
189 expect.Reset();
190 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
191 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
192 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
193 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
194 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
195 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
196 SCOPED_TRACE(t);
197 touchpad->injector[t].record.Reset();
198 touch_status = touchpad->Touch(t, 0.25f, 0.75f, 0.5f);
199 EXPECT_EQ(0, touch_status);
200 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
201 }
202
203 expect.Reset();
204 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
205 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
206 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
207 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
208 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
209 SCOPED_TRACE(t);
210 touchpad->injector[t].record.Reset();
211 touch_status = touchpad->Touch(t, 0.99f, 0.99f, 0.99f);
212 EXPECT_EQ(0, touch_status);
213 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
214 }
215
216 expect.Reset();
217 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
218 SCOPED_TRACE(t);
219 touchpad->injector[t].record.Reset();
220 touch_status = touchpad->Touch(t, 1.0f, 1.0f, 1.0f);
221 EXPECT_EQ(EINVAL, touch_status);
222 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
223 }
224
225 expect.Reset();
226 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
227 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
228 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
229 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
230 SCOPED_TRACE(t);
231 touchpad->injector[t].record.Reset();
232 touch_status = touchpad->Touch(t, 0.25f, 0.75f, -0.01f);
233 EXPECT_EQ(0, touch_status);
234 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
235 }
236
237 expect.Reset();
238 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
239 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
240 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
241 SCOPED_TRACE(t);
242 touchpad->injector[t].record.Reset();
243 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
244 EXPECT_EQ(0, touch_status);
245 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
246 }
247
248 expect.Reset();
249 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
250 SCOPED_TRACE(t);
251 touchpad->injector[t].record.Reset();
252 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
253 EXPECT_EQ(0, touch_status);
254 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
255 }
256
257 expect.Reset();
258 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
259 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
260 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
261 SCOPED_TRACE(t);
262 touchpad->injector[t].record.Reset();
263 touch_status = touchpad->ButtonState(t, 0);
264 EXPECT_EQ(0, touch_status);
265 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
266 }
267
268 expect.Reset();
269 expect.Close();
270 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
271 SCOPED_TRACE(t);
272 touchpad->injector[t].record.Reset();
273 }
274 touch_status = touchpad->Detach();
275 EXPECT_EQ(0, touch_status);
276 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
277 SCOPED_TRACE(t);
278 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
279 }
280 }
281
TEST_F(VirtualTouchpadTest,Badness)282 TEST_F(VirtualTouchpadTest, Badness) {
283 std::unique_ptr<VirtualTouchpadForTesting> touchpad(
284 VirtualTouchpadForTesting::New());
285 UInputRecorder expect;
286 UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
287
288 status_t touch_status = touchpad->Attach();
289 EXPECT_EQ(0, touch_status);
290
291 // Touch off-screen should return an error,
292 // and should not result in any system calls.
293 expect.Reset();
294 record.Reset();
295 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
296 EXPECT_NE(OK, touch_status);
297 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
298 EXPECT_NE(OK, touch_status);
299 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f);
300 EXPECT_NE(OK, touch_status);
301 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 1.75f, 1.0f);
302 EXPECT_NE(OK, touch_status);
303 EXPECT_EQ(expect.GetString(), record.GetString());
304
305 // Unsupported button should return an error,
306 // and should not result in any system calls.
307 expect.Reset();
308 record.Reset();
309 touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
310 AMOTION_EVENT_BUTTON_FORWARD);
311 EXPECT_NE(OK, touch_status);
312 EXPECT_EQ(expect.GetString(), record.GetString());
313
314 // Repeated attach is an error.
315 touch_status = touchpad->Attach();
316 EXPECT_NE(0, touch_status);
317 }
318
319 } // namespace dvr
320 } // namespace android
321