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