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 ConfigureKey(BTN_TOUCH):
173 expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
174 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
175 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
176 // From ConfigureEnd():
177 expect.Write(touchpad->injector[t].GetUiDev(), sizeof(uinput_user_dev));
178 expect.IoctlVoid(UI_DEV_CREATE);
179 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
180 }
181
182 expect.Reset();
183 expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
184 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
185 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
186 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
187 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
188 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
189 SCOPED_TRACE(t);
190 touchpad->injector[t].record.Reset();
191 touch_status = touchpad->Touch(t, 0, 0, 0);
192 EXPECT_EQ(0, touch_status);
193 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
194 }
195
196 expect.Reset();
197 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
198 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
199 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
200 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
201 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
202 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
203 SCOPED_TRACE(t);
204 touchpad->injector[t].record.Reset();
205 touch_status = touchpad->Touch(t, 0.25f, 0.75f, 0.5f);
206 EXPECT_EQ(0, touch_status);
207 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
208 }
209
210 expect.Reset();
211 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
212 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
213 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
214 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
215 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
216 SCOPED_TRACE(t);
217 touchpad->injector[t].record.Reset();
218 touch_status = touchpad->Touch(t, 0.99f, 0.99f, 0.99f);
219 EXPECT_EQ(0, touch_status);
220 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
221 }
222
223 expect.Reset();
224 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
225 SCOPED_TRACE(t);
226 touchpad->injector[t].record.Reset();
227 touch_status = touchpad->Touch(t, 1.0f, 1.0f, 1.0f);
228 EXPECT_EQ(EINVAL, touch_status);
229 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
230 }
231
232 expect.Reset();
233 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
234 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
235 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
236 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
237 SCOPED_TRACE(t);
238 touchpad->injector[t].record.Reset();
239 touch_status = touchpad->Touch(t, 0.25f, 0.75f, -0.01f);
240 EXPECT_EQ(0, touch_status);
241 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
242 }
243
244 expect.Reset();
245 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
246 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
247 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
248 SCOPED_TRACE(t);
249 touchpad->injector[t].record.Reset();
250 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
251 EXPECT_EQ(0, touch_status);
252 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
253 }
254
255 expect.Reset();
256 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
257 SCOPED_TRACE(t);
258 touchpad->injector[t].record.Reset();
259 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
260 EXPECT_EQ(0, touch_status);
261 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
262 }
263
264 expect.Reset();
265 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
266 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
267 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
268 SCOPED_TRACE(t);
269 touchpad->injector[t].record.Reset();
270 touch_status = touchpad->ButtonState(t, 0);
271 EXPECT_EQ(0, touch_status);
272 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
273 }
274
275 expect.Reset();
276 expect.Close();
277 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
278 SCOPED_TRACE(t);
279 touchpad->injector[t].record.Reset();
280 }
281 touch_status = touchpad->Detach();
282 EXPECT_EQ(0, touch_status);
283 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
284 SCOPED_TRACE(t);
285 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
286 }
287 }
288
TEST_F(VirtualTouchpadTest,Badness)289 TEST_F(VirtualTouchpadTest, Badness) {
290 std::unique_ptr<VirtualTouchpadForTesting> touchpad(
291 VirtualTouchpadForTesting::New());
292 UInputRecorder expect;
293 UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
294
295 status_t touch_status = touchpad->Attach();
296 EXPECT_EQ(0, touch_status);
297
298 // Touch off-screen should return an error,
299 // and should not result in any system calls.
300 expect.Reset();
301 record.Reset();
302 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
303 EXPECT_NE(OK, touch_status);
304 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
305 EXPECT_NE(OK, touch_status);
306 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f);
307 EXPECT_NE(OK, touch_status);
308 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 1.75f, 1.0f);
309 EXPECT_NE(OK, touch_status);
310 EXPECT_EQ(expect.GetString(), record.GetString());
311
312 // Unsupported button should return an error,
313 // and should not result in any system calls.
314 expect.Reset();
315 record.Reset();
316 touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
317 AMOTION_EVENT_BUTTON_FORWARD);
318 EXPECT_NE(OK, touch_status);
319 EXPECT_EQ(expect.GetString(), record.GetString());
320
321 // Repeated attach is an error.
322 touch_status = touchpad->Attach();
323 EXPECT_NE(0, touch_status);
324 }
325
326 } // namespace dvr
327 } // namespace android
328