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