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