VirtualTouchpad_test.cpp revision 4b64dd48b6896d6b963f0a3a0259d3d2a7076a9e
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(UInput& uinput) { SetUInputForTesting(&uinput); }
92  const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
93};
94
95class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
96 public:
97  static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
98    VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
99    touchpad->SetEvdevInjectorForTesting(&injector);
100    return sp<VirtualTouchpad>(touchpad);
101  }
102};
103
104void DumpDifference(const char* expect, const char* actual) {
105  printf("  common: ");
106  while (*expect && *expect == *actual) {
107    putchar(*expect);
108    ++expect;
109    ++actual;
110  }
111  printf("\n  expect: %s\n", expect);
112  printf("  actual: %s\n", actual);
113}
114
115}  // anonymous namespace
116
117class VirtualTouchpadTest : public testing::Test {};
118
119TEST_F(VirtualTouchpadTest, Goodness) {
120  UInputRecorder expect;
121  UInputRecorder record;
122  EvdevInjectorForTesting injector(record);
123  sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
124
125  status_t touch_status = touchpad->Attach();
126  EXPECT_EQ(0, touch_status);
127
128  // Check some aspects of uinput_user_dev.
129  const uinput_user_dev* uidev = injector.GetUiDev();
130  for (int i = 0; i < ABS_CNT; ++i) {
131    EXPECT_EQ(0, uidev->absmin[i]);
132    EXPECT_EQ(0, uidev->absfuzz[i]);
133    EXPECT_EQ(0, uidev->absflat[i]);
134    if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y && i != ABS_MT_SLOT) {
135      EXPECT_EQ(0, uidev->absmax[i]);
136    }
137  }
138  const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
139  const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
140  const int32_t slots = uidev->absmax[ABS_MT_SLOT];
141
142  // Check the system calls performed by initialization.
143  // From ConfigureBegin():
144  expect.Open();
145  // From ConfigureInputProperty(INPUT_PROP_DIRECT):
146  expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
147  // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
148  expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
149  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
150  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
151  // From ConfigureAbsSlots(kSlots):
152  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
153  // From ConfigureKey(BTN_TOUCH):
154  expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
155  expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
156  expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
157  // From ConfigureEnd():
158  expect.Write(uidev, sizeof(uinput_user_dev));
159  expect.IoctlVoid(UI_DEV_CREATE);
160  EXPECT_EQ(expect.GetString(), record.GetString());
161
162  expect.Reset();
163  record.Reset();
164  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0, 0, 0);
165  EXPECT_EQ(0, touch_status);
166  expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
167  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
168  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
169  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
170  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
171  EXPECT_EQ(expect.GetString(), record.GetString());
172
173  expect.Reset();
174  record.Reset();
175  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 0.75f, 0.5f);
176  EXPECT_EQ(0, touch_status);
177  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
178  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
179  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
180  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
181  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
182  EXPECT_EQ(expect.GetString(), record.GetString());
183
184  expect.Reset();
185  record.Reset();
186  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.99f, 0.99f, 0.99f);
187  EXPECT_EQ(0, touch_status);
188  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
189  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
190  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
191  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
192  EXPECT_EQ(expect.GetString(), record.GetString());
193
194  expect.Reset();
195  record.Reset();
196  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.0f, 1.0f, 1.0f);
197  EXPECT_EQ(EINVAL, touch_status);
198  EXPECT_EQ(expect.GetString(), record.GetString());
199
200  expect.Reset();
201  record.Reset();
202  touch_status =
203      touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 0.75f, -0.01f);
204  EXPECT_EQ(0, touch_status);
205  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
206  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
207  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
208  EXPECT_EQ(expect.GetString(), record.GetString());
209
210  expect.Reset();
211  record.Reset();
212  touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
213                                       AMOTION_EVENT_BUTTON_BACK);
214  EXPECT_EQ(0, touch_status);
215  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
216  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
217  EXPECT_EQ(expect.GetString(), record.GetString());
218
219  expect.Reset();
220  record.Reset();
221  touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
222                                       AMOTION_EVENT_BUTTON_BACK);
223  EXPECT_EQ(0, touch_status);
224  EXPECT_EQ(expect.GetString(), record.GetString());
225
226  expect.Reset();
227  record.Reset();
228  touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY, 0);
229  EXPECT_EQ(0, touch_status);
230  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
231  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
232  EXPECT_EQ(expect.GetString(), record.GetString());
233
234  expect.Reset();
235  record.Reset();
236  touch_status = touchpad->Detach();
237  EXPECT_EQ(0, touch_status);
238  expect.Close();
239  EXPECT_EQ(expect.GetString(), record.GetString());
240}
241
242TEST_F(VirtualTouchpadTest, Badness) {
243  UInputRecorder expect;
244  UInputRecorder record;
245  EvdevInjectorForTesting injector(record);
246  sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
247
248  status_t touch_status = touchpad->Attach();
249  EXPECT_EQ(0, touch_status);
250
251  // Touch off-screen should return an error,
252  // and should not result in any system calls.
253  expect.Reset();
254  record.Reset();
255  touch_status =
256      touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
257  EXPECT_NE(OK, touch_status);
258  touch_status =
259      touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f);
260  EXPECT_NE(OK, touch_status);
261  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f);
262  EXPECT_NE(OK, touch_status);
263  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 1.75f, 1.0f);
264  EXPECT_NE(OK, touch_status);
265  EXPECT_EQ(expect.GetString(), record.GetString());
266
267  // Unsupported button should return an error,
268  // and should not result in any system calls.
269  expect.Reset();
270  record.Reset();
271  touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY,
272                                       AMOTION_EVENT_BUTTON_FORWARD);
273  EXPECT_NE(OK, touch_status);
274  EXPECT_EQ(expect.GetString(), record.GetString());
275
276  // Repeated attach is an error.
277  touch_status = touchpad->Attach();
278  EXPECT_NE(0, touch_status);
279}
280
281}  // namespace dvr
282}  // namespace android
283