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