• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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