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
DumpDifference(const char * expect,const char * actual)113 void DumpDifference(const char* expect, const char* actual) {
114 printf(" common: ");
115 while (*expect && *expect == *actual) {
116 putchar(*expect);
117 ++expect;
118 ++actual;
119 }
120 printf("\n expect: %s\n", expect);
121 printf(" actual: %s\n", actual);
122 }
123
124 } // anonymous namespace
125
126 class VirtualTouchpadTest : public testing::Test {};
127
TEST_F(VirtualTouchpadTest,Goodness)128 TEST_F(VirtualTouchpadTest, Goodness) {
129 std::unique_ptr<VirtualTouchpadForTesting> touchpad(
130 VirtualTouchpadForTesting::New());
131 UInputRecorder expect;
132
133 status_t touch_status = touchpad->Attach();
134 EXPECT_EQ(0, touch_status);
135
136 // Check some aspects of uinput_user_dev.
137 const uinput_user_dev* uidev;
138 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
139 SCOPED_TRACE(t);
140 uidev = touchpad->injector[t].GetUiDev();
141 String8 name;
142 name.appendFormat("vr-virtual-touchpad-%d", t);
143 EXPECT_EQ(name, uidev->name);
144 for (int i = 0; i < ABS_CNT; ++i) {
145 EXPECT_EQ(0, uidev->absmin[i]);
146 EXPECT_EQ(0, uidev->absfuzz[i]);
147 EXPECT_EQ(0, uidev->absflat[i]);
148 if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y &&
149 i != ABS_MT_SLOT) {
150 EXPECT_EQ(0, uidev->absmax[i]);
151 }
152 }
153 }
154 const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
155 const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
156 const int32_t slots = uidev->absmax[ABS_MT_SLOT];
157
158 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
159 SCOPED_TRACE(t);
160 // Check the system calls performed by initialization.
161 expect.Reset();
162 // From ConfigureBegin():
163 expect.Open();
164 // From ConfigureInputProperty(INPUT_PROP_DIRECT):
165 expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
166 // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
167 expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
168 expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
169 expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
170 // From ConfigureAbsSlots(kSlots):
171 expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
172 // From ConfigureRel(REL_WHEEL):
173 expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
174 expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
175 // From ConfigureRel(REL_HWHEEL):
176 expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
177 // From ConfigureKey(BTN_TOUCH):
178 expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
179 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
180 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
181 // From ConfigureEnd():
182 expect.Write(touchpad->injector[t].GetUiDev(), sizeof(uinput_user_dev));
183 expect.IoctlVoid(UI_DEV_CREATE);
184 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
185 }
186
187 expect.Reset();
188 expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
189 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
190 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
191 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
192 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
193 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
194 SCOPED_TRACE(t);
195 touchpad->injector[t].record.Reset();
196 touch_status = touchpad->Touch(t, 0, 0, 0);
197 EXPECT_EQ(0, touch_status);
198 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
199 }
200
201 expect.Reset();
202 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
203 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
204 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
205 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
206 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
207 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
208 SCOPED_TRACE(t);
209 touchpad->injector[t].record.Reset();
210 touch_status = touchpad->Touch(t, 0.25f, 0.75f, 0.5f);
211 EXPECT_EQ(0, touch_status);
212 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
213 }
214
215 expect.Reset();
216 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
217 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
218 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
219 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
220 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
221 SCOPED_TRACE(t);
222 touchpad->injector[t].record.Reset();
223 touch_status = touchpad->Touch(t, 0.99f, 0.99f, 0.99f);
224 EXPECT_EQ(0, touch_status);
225 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
226 }
227
228 expect.Reset();
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, 1.0f, 1.0f, 1.0f);
233 EXPECT_EQ(EINVAL, touch_status);
234 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
235 }
236
237 expect.Reset();
238 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
239 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
240 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
241 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
242 SCOPED_TRACE(t);
243 touchpad->injector[t].record.Reset();
244 touch_status = touchpad->Touch(t, 0.25f, 0.75f, -0.01f);
245 EXPECT_EQ(0, touch_status);
246 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
247 }
248
249 expect.Reset();
250 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
251 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
252 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
253 SCOPED_TRACE(t);
254 touchpad->injector[t].record.Reset();
255 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
256 EXPECT_EQ(0, touch_status);
257 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
258 }
259
260 expect.Reset();
261 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
262 SCOPED_TRACE(t);
263 touchpad->injector[t].record.Reset();
264 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
265 EXPECT_EQ(0, touch_status);
266 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
267 }
268
269 expect.Reset();
270 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
271 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
272 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
273 SCOPED_TRACE(t);
274 touchpad->injector[t].record.Reset();
275 touch_status = touchpad->ButtonState(t, 0);
276 EXPECT_EQ(0, touch_status);
277 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
278 }
279
280 expect.Reset();
281 expect.Close();
282 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
283 SCOPED_TRACE(t);
284 touchpad->injector[t].record.Reset();
285 }
286 touch_status = touchpad->Detach();
287 EXPECT_EQ(0, touch_status);
288 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
289 SCOPED_TRACE(t);
290 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
291 }
292 }
293
TEST_F(VirtualTouchpadTest,Badness)294 TEST_F(VirtualTouchpadTest, Badness) {
295 std::unique_ptr<VirtualTouchpadForTesting> touchpad(
296 VirtualTouchpadForTesting::New());
297 UInputRecorder expect;
298 UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
299
300 status_t touch_status = touchpad->Attach();
301 EXPECT_EQ(0, touch_status);
302
303 // Touch off-screen should return an error,
304 // and should not result in any system calls.
305 expect.Reset();
306 record.Reset();
307 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
308 EXPECT_NE(OK, touch_status);
309 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
310 EXPECT_NE(OK, touch_status);
311 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f);
312 EXPECT_NE(OK, touch_status);
313 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 1.75f, 1.0f);
314 EXPECT_NE(OK, touch_status);
315 EXPECT_EQ(expect.GetString(), record.GetString());
316
317 // Unsupported button should return an error,
318 // and should not result in any system calls.
319 expect.Reset();
320 record.Reset();
321 touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
322 AMOTION_EVENT_BUTTON_FORWARD);
323 EXPECT_NE(OK, touch_status);
324 EXPECT_EQ(expect.GetString(), record.GetString());
325
326 // Repeated attach is an error.
327 touch_status = touchpad->Attach();
328 EXPECT_NE(0, touch_status);
329 }
330
331 } // namespace dvr
332 } // namespace android
333