VirtualTouchpad_test.cpp revision 06936feb07bf6fbef262e4adebeb8e53910d8cf4
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 std::unique_ptr<VirtualTouchpad> Create() { 99 return std::unique_ptr<VirtualTouchpad>(New()); 100 } 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 } 109 int GetTouchpadCount() const { return kTouchpads; } 110 EvdevInjectorForTesting injector[kTouchpads]; 111}; 112 113void 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 126class VirtualTouchpadTest : public testing::Test {}; 127 128TEST_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 ConfigureKey(BTN_TOUCH): 173 expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY); 174 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH); 175 expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK); 176 // From ConfigureEnd(): 177 expect.Write(touchpad->injector[t].GetUiDev(), sizeof(uinput_user_dev)); 178 expect.IoctlVoid(UI_DEV_CREATE); 179 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 180 } 181 182 expect.Reset(); 183 expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0); 184 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0); 185 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0); 186 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0); 187 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0); 188 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 189 SCOPED_TRACE(t); 190 touchpad->injector[t].record.Reset(); 191 touch_status = touchpad->Touch(t, 0, 0, 0); 192 EXPECT_EQ(0, touch_status); 193 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 194 } 195 196 expect.Reset(); 197 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0); 198 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width); 199 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.75f * height); 200 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_PRESS); 201 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0); 202 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 203 SCOPED_TRACE(t); 204 touchpad->injector[t].record.Reset(); 205 touch_status = touchpad->Touch(t, 0.25f, 0.75f, 0.5f); 206 EXPECT_EQ(0, touch_status); 207 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 208 } 209 210 expect.Reset(); 211 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0); 212 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width); 213 expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height); 214 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0); 215 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 216 SCOPED_TRACE(t); 217 touchpad->injector[t].record.Reset(); 218 touch_status = touchpad->Touch(t, 0.99f, 0.99f, 0.99f); 219 EXPECT_EQ(0, touch_status); 220 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 221 } 222 223 expect.Reset(); 224 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 225 SCOPED_TRACE(t); 226 touchpad->injector[t].record.Reset(); 227 touch_status = touchpad->Touch(t, 1.0f, 1.0f, 1.0f); 228 EXPECT_EQ(EINVAL, touch_status); 229 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 230 } 231 232 expect.Reset(); 233 expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE); 234 expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1); 235 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0); 236 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 237 SCOPED_TRACE(t); 238 touchpad->injector[t].record.Reset(); 239 touch_status = touchpad->Touch(t, 0.25f, 0.75f, -0.01f); 240 EXPECT_EQ(0, touch_status); 241 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 242 } 243 244 expect.Reset(); 245 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS); 246 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0); 247 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 248 SCOPED_TRACE(t); 249 touchpad->injector[t].record.Reset(); 250 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK); 251 EXPECT_EQ(0, touch_status); 252 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 253 } 254 255 expect.Reset(); 256 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 257 SCOPED_TRACE(t); 258 touchpad->injector[t].record.Reset(); 259 touch_status = touchpad->ButtonState(t, AMOTION_EVENT_BUTTON_BACK); 260 EXPECT_EQ(0, touch_status); 261 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 262 } 263 264 expect.Reset(); 265 expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE); 266 expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0); 267 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 268 SCOPED_TRACE(t); 269 touchpad->injector[t].record.Reset(); 270 touch_status = touchpad->ButtonState(t, 0); 271 EXPECT_EQ(0, touch_status); 272 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 273 } 274 275 expect.Reset(); 276 expect.Close(); 277 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 278 SCOPED_TRACE(t); 279 touchpad->injector[t].record.Reset(); 280 } 281 touch_status = touchpad->Detach(); 282 EXPECT_EQ(0, touch_status); 283 for (int t = 0; t < touchpad->GetTouchpadCount(); ++t) { 284 SCOPED_TRACE(t); 285 EXPECT_EQ(expect.GetString(), touchpad->injector[t].record.GetString()); 286 } 287} 288 289TEST_F(VirtualTouchpadTest, Badness) { 290 std::unique_ptr<VirtualTouchpadForTesting> touchpad( 291 VirtualTouchpadForTesting::New()); 292 UInputRecorder expect; 293 UInputRecorder& record = touchpad->injector[VirtualTouchpad::PRIMARY].record; 294 295 status_t touch_status = touchpad->Attach(); 296 EXPECT_EQ(0, touch_status); 297 298 // Touch off-screen should return an error, 299 // and should not result in any system calls. 300 expect.Reset(); 301 record.Reset(); 302 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f); 303 EXPECT_NE(OK, touch_status); 304 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, -0.75f, 1.0f); 305 EXPECT_NE(OK, touch_status); 306 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.25f, 0.75f, 1.0f); 307 EXPECT_NE(OK, touch_status); 308 touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 1.75f, 1.0f); 309 EXPECT_NE(OK, touch_status); 310 EXPECT_EQ(expect.GetString(), record.GetString()); 311 312 // Unsupported button should return an error, 313 // and should not result in any system calls. 314 expect.Reset(); 315 record.Reset(); 316 touch_status = touchpad->ButtonState(VirtualTouchpad::PRIMARY, 317 AMOTION_EVENT_BUTTON_FORWARD); 318 EXPECT_NE(OK, touch_status); 319 EXPECT_EQ(expect.GetString(), record.GetString()); 320 321 // Repeated attach is an error. 322 touch_status = touchpad->Attach(); 323 EXPECT_NE(0, touch_status); 324} 325 326} // namespace dvr 327} // namespace android 328