VirtualTouchpad_test.cpp revision 0108af72a8d8d2ee2af127b4c099b340ad63e3f8
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
11namespace android {
12namespace dvr {
13
14namespace {
15
16class UInputForTesting : public EvdevInjector::UInput {
17 public:
18  ~UInputForTesting() override {}
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//
31class UInputRecorder : public UInputForTesting {
32 public:
33  UInputRecorder() {}
34  ~UInputRecorder() override {}
35
36  const std::string& GetString() const { return s_; }
37  void Reset() { s_.clear(); }
38
39  // UInput overrides:
40
41  int Open() override {
42    s_ += "o;";
43    return 0;
44  }
45
46  int Close() override {
47    s_ += "c;";
48    return 0;
49  }
50
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
60  int IoctlVoid(int request) override {
61    s_ += "i(";
62    s_ += Encode(&request, sizeof(request));
63    s_ += ");";
64    return 0;
65  }
66
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
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
89class EvdevInjectorForTesting : public EvdevInjector {
90 public:
91  EvdevInjectorForTesting() { SetUInputForTesting(&record); }
92  const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
93  UInputRecorder record;
94};
95
96class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
97 public:
98  static sp<VirtualTouchpad> Create() { return sp<VirtualTouchpad>(New()); }
99  static VirtualTouchpadForTesting* New() {
100    VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
101    touchpad->Reset();
102    for (int t = 0; t < kTouchpads; ++t) {
103      touchpad->SetEvdevInjectorForTesting(t, &touchpad->injector[t]);
104    }
105    return touchpad;
106  }
107  int GetTouchpadCount() const { return kTouchpads; }
108  EvdevInjectorForTesting injector[kTouchpads];
109};
110
111void DumpDifference(const char* expect, const char* actual) {
112  printf("  common: ");
113  while (*expect && *expect == *actual) {
114    putchar(*expect);
115    ++expect;
116    ++actual;
117  }
118  printf("\n  expect: %s\n", expect);
119  printf("  actual: %s\n", actual);
120}
121
122}  // anonymous namespace
123
124class VirtualTouchpadTest : public testing::Test {};
125
126TEST_F(VirtualTouchpadTest, Goodness) {
127  sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
128  UInputRecorder expect;
129
130  status_t touch_status = touchpad->Attach();
131  EXPECT_EQ(0, touch_status);
132
133  // Check some aspects of uinput_user_dev.
134  const uinput_user_dev* uidev;
135  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
136    SCOPED_TRACE(t);
137    uidev = touchpad->injector[t].GetUiDev();
138    String8 name;
139    name.appendFormat("vr virtual touchpad %d", t);
140    EXPECT_EQ(name, uidev->name);
141    for (int i = 0; i < ABS_CNT; ++i) {
142      EXPECT_EQ(0, uidev->absmin[i]);
143      EXPECT_EQ(0, uidev->absfuzz[i]);
144      EXPECT_EQ(0, uidev->absflat[i]);
145      if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y &&
146          i != ABS_MT_SLOT) {
147        EXPECT_EQ(0, uidev->absmax[i]);
148      }
149    }
150  }
151  const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
152  const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
153  const int32_t slots = uidev->absmax[ABS_MT_SLOT];
154
155  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
156    SCOPED_TRACE(t);
157    // Check the system calls performed by initialization.
158    expect.Reset();
159    // From ConfigureBegin():
160    expect.Open();
161    // From ConfigureInputProperty(INPUT_PROP_DIRECT):
162    expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
163    // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
164    expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
165    expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
166    expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
167    // From ConfigureAbsSlots(kSlots):
168    expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
169    // From ConfigureKey(BTN_TOUCH):
170    expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
171    expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
172    expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
173    // From ConfigureEnd():
174    expect.Write(touchpad->injector[t].GetUiDev(), sizeof(uinput_user_dev));
175    expect.IoctlVoid(UI_DEV_CREATE);
176    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
177  }
178
179  expect.Reset();
180  expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
181  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
182  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
183  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
184  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
185  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
186    SCOPED_TRACE(t);
187    touchpad->injector[t].record.Reset();
188    touch_status = touchpad->Touch(t, 0, 0, 0);
189    EXPECT_EQ(0, touch_status);
190    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
191  }
192
193  expect.Reset();
194  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
195  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
196  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
197  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
198  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
199  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
200    SCOPED_TRACE(t);
201    touchpad->injector[t].record.Reset();
202    touch_status = touchpad->Touch(t, 0.25f, 0.75f, 0.5f);
203    EXPECT_EQ(0, touch_status);
204    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
205  }
206
207  expect.Reset();
208  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
209  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
210  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
211  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
212  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
213    SCOPED_TRACE(t);
214    touchpad->injector[t].record.Reset();
215    touch_status = touchpad->Touch(t, 0.99f, 0.99f, 0.99f);
216    EXPECT_EQ(0, touch_status);
217    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
218  }
219
220  expect.Reset();
221  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
222    SCOPED_TRACE(t);
223    touchpad->injector[t].record.Reset();
224    touch_status = touchpad->Touch(t, 1.0f, 1.0f, 1.0f);
225    EXPECT_EQ(EINVAL, touch_status);
226    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
227  }
228
229  expect.Reset();
230  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
231  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
232  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
233  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
234    SCOPED_TRACE(t);
235    touchpad->injector[t].record.Reset();
236    touch_status = touchpad->Touch(t, 0.25f, 0.75f, -0.01f);
237    EXPECT_EQ(0, touch_status);
238    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
239  }
240
241  expect.Reset();
242  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
243  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
244  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
245    SCOPED_TRACE(t);
246    touchpad->injector[t].record.Reset();
247    touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
248    EXPECT_EQ(0, touch_status);
249    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
250  }
251
252  expect.Reset();
253  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
254    SCOPED_TRACE(t);
255    touchpad->injector[t].record.Reset();
256    touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK);
257    EXPECT_EQ(0, touch_status);
258    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
259  }
260
261  expect.Reset();
262  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
263  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
264  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
265    SCOPED_TRACE(t);
266    touchpad->injector[t].record.Reset();
267    touch_status = touchpad->ButtonState(t, 0);
268    EXPECT_EQ(0, touch_status);
269    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
270  }
271
272  expect.Reset();
273  expect.Close();
274  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
275    SCOPED_TRACE(t);
276    touchpad->injector[t].record.Reset();
277  }
278  touch_status = touchpad->Detach();
279  EXPECT_EQ(0, touch_status);
280  for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) {
281    SCOPED_TRACE(t);
282    EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString());
283  }
284}
285
286TEST_F(VirtualTouchpadTest, Badness) {
287  sp<VirtualTouchpadForTesting> touchpad(VirtualTouchpadForTesting::New());
288  UInputRecorder expect;
289  UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record;
290
291  status_t touch_status = touchpad->Attach();
292  EXPECT_EQ(0, touch_status);
293
294  // Touch off-screen should return an error,
295  // and should not result in any system calls.
296  expect.Reset();
297  record.Reset();
298  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
299  EXPECT_NE(OK, touch_status);
300  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
301  EXPECT_NE(OK, touch_status);
302  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f);
303  EXPECT_NE(OK, touch_status);
304  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 1.75f, 1.0f);
305  EXPECT_NE(OK, touch_status);
306  EXPECT_EQ(expect.GetString(), record.GetString());
307
308  // Unsupported button should return an error,
309  // and should not result in any system calls.
310  expect.Reset();
311  record.Reset();
312  touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
313                                       AMOTION_EVENT_BUTTON_FORWARD);
314  EXPECT_NE(OK, touch_status);
315  EXPECT_EQ(expect.GetString(), record.GetString());
316
317  // Repeated attach is an error.
318  touch_status = touchpad->Attach();
319  EXPECT_NE(0, touch_status);
320}
321
322}  // namespace dvr
323}  // namespace android
324