VirtualTouchpad_test.cpp revision 89af70bce420f011adfeb0f80984b3895c4d7d9b
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  void WriteInputEvent(uint16_t type, uint16_t code, int32_t value) {
19    struct input_event event;
20    memset(&event, 0, sizeof(event));
21    event.type = type;
22    event.code = code;
23    event.value = value;
24    Write(&event, sizeof(event));
25  }
26};
27
28// Recording test implementation of UInput.
29//
30class UInputRecorder : public UInputForTesting {
31 public:
32  UInputRecorder() {}
33  virtual ~UInputRecorder() {}
34
35  const std::string& GetString() const { return s_; }
36  void Reset() { s_.clear(); }
37
38  // UInput overrides:
39
40  int Open() override {
41    s_ += "o;";
42    return 0;
43  }
44
45  int Close() override {
46    s_ += "c;";
47    return 0;
48  }
49
50  int Write(const void* buf, size_t count) override {
51    s_ += "w(";
52    s_ += Encode(&count, sizeof(count));
53    s_ += ",";
54    s_ += Encode(buf, count);
55    s_ += ");";
56    return 0;
57  }
58
59  int IoctlVoid(int request) override {
60    s_ += "i(";
61    s_ += Encode(&request, sizeof(request));
62    s_ += ");";
63    return 0;
64  }
65
66  int IoctlSetInt(int request, int value) override {
67    s_ += "i(";
68    s_ += Encode(&request, sizeof(request));
69    s_ += ",";
70    s_ += Encode(&value, sizeof(value));
71    s_ += ");";
72    return 0;
73  }
74
75 private:
76  std::string s_;
77
78  std::string Encode(const void* buf, size_t count) {
79    const char* in = static_cast<const char*>(buf);
80    char out[2 * count + 1];
81    for (size_t i = 0; i < count; ++i) {
82      snprintf(&out[2 * i], 3, "%02X", in[i]);
83    }
84    return out;
85  }
86};
87
88class EvdevInjectorForTesting : public EvdevInjector {
89 public:
90  EvdevInjectorForTesting(UInput& uinput) { SetUInputForTesting(&uinput); }
91  const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
92};
93
94class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
95 public:
96  static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
97    VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
98    touchpad->SetEvdevInjectorForTesting(&injector);
99    touchpad->Initialize();
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  // Check some aspects of uinput_user_dev.
126  const uinput_user_dev* uidev = injector.GetUiDev();
127  for (int i = 0; i < ABS_CNT; ++i) {
128    EXPECT_EQ(0, uidev->absmin[i]);
129    EXPECT_EQ(0, uidev->absfuzz[i]);
130    EXPECT_EQ(0, uidev->absflat[i]);
131    if (i != ABS_MT_POSITION_X && i != ABS_MT_POSITION_Y && i != ABS_MT_SLOT) {
132      EXPECT_EQ(0, uidev->absmax[i]);
133    }
134  }
135  const int32_t width = 1 + uidev->absmax[ABS_MT_POSITION_X];
136  const int32_t height = 1 + uidev->absmax[ABS_MT_POSITION_Y];
137  const int32_t slots = uidev->absmax[ABS_MT_SLOT];
138
139  // Check the system calls performed by initialization.
140  // From ConfigureBegin():
141  expect.Open();
142  // From ConfigureInputProperty(INPUT_PROP_DIRECT):
143  expect.IoctlSetInt(UI_SET_PROPBIT, INPUT_PROP_DIRECT);
144  // From ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1):
145  expect.IoctlSetInt(UI_SET_EVBIT, EV_ABS);
146  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_X);
147  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
148  // From ConfigureAbsSlots(kSlots):
149  expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
150  // From ConfigureKey(BTN_TOUCH):
151  expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
152  expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
153  // From ConfigureEnd():
154  expect.Write(uidev, sizeof(uinput_user_dev));
155  expect.IoctlVoid(UI_DEV_CREATE);
156  EXPECT_EQ(expect.GetString(), record.GetString());
157
158  expect.Reset();
159  record.Reset();
160  int touch_status = touchpad->Touch(0, 0, 0);
161  EXPECT_EQ(0, touch_status);
162  expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
163  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
164  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0);
165  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0);
166  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
167  EXPECT_EQ(expect.GetString(), record.GetString());
168
169  expect.Reset();
170  record.Reset();
171  touch_status = touchpad->Touch(0.25f, 0.75f, 0.5f);
172  EXPECT_EQ(0, touch_status);
173  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
174  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
175  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height);
176  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS);
177  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
178  EXPECT_EQ(expect.GetString(), record.GetString());
179
180  expect.Reset();
181  record.Reset();
182  touch_status = touchpad->Touch(1.0f, 1.0f, 1.0f);
183  EXPECT_EQ(0, touch_status);
184  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
185  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
186  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, height);
187  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
188  EXPECT_EQ(expect.GetString(), record.GetString());
189
190  expect.Reset();
191  record.Reset();
192  touch_status = touchpad->Touch(0.25f, 0.75f, -0.01f);
193  EXPECT_EQ(0, touch_status);
194  expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
195  expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
196  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
197  EXPECT_EQ(expect.GetString(), record.GetString());
198
199  expect.Reset();
200  record.Reset();
201  touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_BACK);
202  EXPECT_EQ(0, touch_status);
203  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
204  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
205  EXPECT_EQ(expect.GetString(), record.GetString());
206
207  expect.Reset();
208  record.Reset();
209  touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_BACK);
210  EXPECT_EQ(0, touch_status);
211  EXPECT_EQ(expect.GetString(), record.GetString());
212
213  expect.Reset();
214  record.Reset();
215  touch_status = touchpad->ButtonState(0);
216  EXPECT_EQ(0, touch_status);
217  expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
218  expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
219  EXPECT_EQ(expect.GetString(), record.GetString());
220
221  expect.Reset();
222  record.Reset();
223}
224
225TEST_F(VirtualTouchpadTest, Badness) {
226  UInputRecorder expect;
227  UInputRecorder record;
228  EvdevInjectorForTesting injector(record);
229  sp<VirtualTouchpad> touchpad(
230      VirtualTouchpadForTesting::Create(injector));
231
232  // Touch off-screen should return an error,
233  // and should not result in any system calls.
234  expect.Reset();
235  record.Reset();
236  status_t touch_status = touchpad->Touch(-0.25f, 0.75f, 1.0f);
237  EXPECT_NE(OK, touch_status);
238  touch_status = touchpad->Touch(0.25f, -0.75f, 1.0f);
239  EXPECT_NE(OK, touch_status);
240  touch_status = touchpad->Touch(1.25f, 0.75f, 1.0f);
241  EXPECT_NE(OK, touch_status);
242  touch_status = touchpad->Touch(0.25f, 1.75f, 1.0f);
243  EXPECT_NE(OK, touch_status);
244  EXPECT_EQ(expect.GetString(), record.GetString());
245
246  // Unsupported button should return an error,
247  // and should not result in any system calls.
248  expect.Reset();
249  record.Reset();
250  touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_FORWARD);
251  EXPECT_NE(OK, touch_status);
252  EXPECT_EQ(expect.GetString(), record.GetString());
253}
254
255}  // namespace dvr
256}  // namespace android
257