Support multiple virtual touchpads.

The service now creates two uinput devices, named
"vr virtual touchpad 0" for VirtualTouchpad::PRIMARY
and "vr virtual touchpad 1" for VirtualTouchpad::VIRTUAL.

Bug: b/35992608
Test: expanded VirtualTouchpad_test unit test
Change-Id: I8749d559a56cfa9c8ec9a039ff7ad44d16f81915
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index bc29408..92193d3 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -18,7 +18,7 @@
 // use it to look up device configuration, so it must be unique. Vendor and
 // product values must be 0 to indicate an internal device and prevent a
 // similar lookup that could conflict with a physical device.
-static const char* const kDeviceName = "vr window manager virtual touchpad";
+static const char* const kDeviceNameFormat = "vr virtual touchpad %d";
 static constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
 static constexpr int16_t kDeviceVendor = 0;
 static constexpr int16_t kDeviceProduct = 0;
@@ -32,122 +32,154 @@
 
 sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
   VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
+  touchpad->Reset();
   return sp<VirtualTouchpad>(touchpad);
 }
 
-status_t VirtualTouchpadEvdev::Attach() {
-  if (!injector_) {
-    owned_injector_.reset(new EvdevInjector());
-    injector_ = owned_injector_.get();
+void VirtualTouchpadEvdev::Reset() {
+  for (auto& touchpad : touchpad_) {
+    if (touchpad.injector) {
+      touchpad.injector->Close();
+    }
+    touchpad.injector = nullptr;
+    touchpad.owned_injector.reset();
+    touchpad.last_device_x = INT32_MIN;
+    touchpad.last_device_y = INT32_MIN;
+    touchpad.touches = 0;
+    touchpad.last_motion_event_buttons = 0;
   }
-  injector_->ConfigureBegin(kDeviceName, kDeviceBusType, kDeviceVendor,
-                            kDeviceProduct, kDeviceVersion);
-  injector_->ConfigureInputProperty(INPUT_PROP_DIRECT);
-  injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
-  injector_->ConfigureAbsSlots(kSlots);
-  injector_->ConfigureKey(BTN_TOUCH);
-  injector_->ConfigureKey(BTN_BACK);
-  injector_->ConfigureEnd();
-  return injector_->GetError();
+}
+
+status_t VirtualTouchpadEvdev::Attach() {
+  status_t status = OK;
+  for (int i = 0; i < kTouchpads; ++i) {
+    Touchpad& touchpad = touchpad_[i];
+    if (!touchpad.injector) {
+      touchpad.owned_injector.reset(new EvdevInjector());
+      touchpad.injector = touchpad.owned_injector.get();
+    }
+    String8 DeviceName;
+    DeviceName.appendFormat(kDeviceNameFormat, i);
+    touchpad.injector->ConfigureBegin(DeviceName, kDeviceBusType,
+                                      kDeviceVendor, kDeviceProduct,
+                                      kDeviceVersion);
+    touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
+    touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
+    touchpad.injector->ConfigureAbsSlots(kSlots);
+    touchpad.injector->ConfigureKey(BTN_TOUCH);
+    touchpad.injector->ConfigureKey(BTN_BACK);
+    touchpad.injector->ConfigureEnd();
+    if (const status_t configuration_status =  touchpad.injector->GetError()) {
+      status = configuration_status;
+    }
+  }
+  return status;
 }
 
 status_t VirtualTouchpadEvdev::Detach() {
-  injector_->Close();
-  injector_ = nullptr;
-  owned_injector_.reset();
-  last_device_x_ = INT32_MIN;
-  last_device_y_ = INT32_MIN;
-  touches_ = 0;
-  last_motion_event_buttons_ = 0;
+  Reset();
   return OK;
 }
 
-int VirtualTouchpadEvdev::Touch(int touchpad, float x, float y,
+int VirtualTouchpadEvdev::Touch(int touchpad_id, float x, float y,
                                 float pressure) {
-  (void)touchpad;  // TODO(b/35992608) Support multiple touchpad devices.
+  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+    return EINVAL;
+  }
   if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
     return EINVAL;
   }
   int32_t device_x = x * kWidth;
   int32_t device_y = y * kHeight;
-  touches_ = ((touches_ & 1) << 1) | (pressure > 0);
+  Touchpad& touchpad = touchpad_[touchpad_id];
+  touchpad.touches = ((touchpad.touches & 1) << 1) | (pressure > 0);
   ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d", x, y, pressure, device_x,
-        device_y, touches_);
+        device_y, touchpad.touches);
 
-  if (!injector_) {
+  if (!touchpad.injector) {
     return EvdevInjector::ERROR_SEQUENCING;
   }
-  injector_->ResetError();
-  switch (touches_) {
+  touchpad.injector->ResetError();
+  switch (touchpad.touches) {
     case 0b00:  // Hover continues.
-      if (device_x != last_device_x_ || device_y != last_device_y_) {
-        injector_->SendMultiTouchXY(0, 0, device_x, device_y);
-        injector_->SendSynReport();
+      if (device_x != touchpad.last_device_x ||
+          device_y != touchpad.last_device_y) {
+        touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
+        touchpad.injector->SendSynReport();
       }
       break;
     case 0b01:  // Touch begins.
       // Press.
-      injector_->SendMultiTouchXY(0, 0, device_x, device_y);
-      injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
-      injector_->SendSynReport();
+      touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
+      touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_PRESS);
+      touchpad.injector->SendSynReport();
       break;
     case 0b10:  // Touch ends.
-      injector_->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
-      injector_->SendMultiTouchLift(0);
-      injector_->SendSynReport();
+      touchpad.injector->SendKey(BTN_TOUCH, EvdevInjector::KEY_RELEASE);
+      touchpad.injector->SendMultiTouchLift(0);
+      touchpad.injector->SendSynReport();
       break;
     case 0b11:  // Touch continues.
-      if (device_x != last_device_x_ || device_y != last_device_y_) {
-        injector_->SendMultiTouchXY(0, 0, device_x, device_y);
-        injector_->SendSynReport();
+      if (device_x != touchpad.last_device_x ||
+          device_y != touchpad.last_device_y) {
+        touchpad.injector->SendMultiTouchXY(0, 0, device_x, device_y);
+        touchpad.injector->SendSynReport();
       }
       break;
   }
-  last_device_x_ = device_x;
-  last_device_y_ = device_y;
+  touchpad.last_device_x = device_x;
+  touchpad.last_device_y = device_y;
 
-  return injector_->GetError();
+  return touchpad.injector->GetError();
 }
 
-int VirtualTouchpadEvdev::ButtonState(int touchpad, int buttons) {
-  (void)touchpad;  // TODO(b/35992608) Support multiple touchpad devices.
-  const int changes = last_motion_event_buttons_ ^ buttons;
+int VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) {
+  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+    return EINVAL;
+  }
+  Touchpad& touchpad = touchpad_[touchpad_id];
+  const int changes = touchpad.last_motion_event_buttons ^ buttons;
   if (!changes) {
     return 0;
   }
   if (buttons & ~AMOTION_EVENT_BUTTON_BACK) {
     return ENOTSUP;
   }
-  ALOGV("change %X from %X to %X", changes, last_motion_event_buttons_,
+  ALOGV("change %X from %X to %X", changes, touchpad.last_motion_event_buttons,
         buttons);
 
-  if (!injector_) {
+  if (!touchpad.injector) {
     return EvdevInjector::ERROR_SEQUENCING;
   }
-  injector_->ResetError();
+  touchpad.injector->ResetError();
   if (changes & AMOTION_EVENT_BUTTON_BACK) {
-    injector_->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
-                                     ? EvdevInjector::KEY_PRESS
-                                     : EvdevInjector::KEY_RELEASE);
-    injector_->SendSynReport();
+    touchpad.injector->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
+                                             ? EvdevInjector::KEY_PRESS
+                                             : EvdevInjector::KEY_RELEASE);
+    touchpad.injector->SendSynReport();
   }
-  last_motion_event_buttons_ = buttons;
-  return injector_->GetError();
+  touchpad.last_motion_event_buttons = buttons;
+  return touchpad.injector->GetError();
 }
 
 void VirtualTouchpadEvdev::dumpInternal(String8& result) {
-  result.append("[virtual touchpad]\n");
-  if (!injector_) {
-    result.append("injector = none\n");
-    return;
+  for (int i = 0; i < kTouchpads; ++i) {
+    const auto& touchpad = touchpad_[i];
+    result.appendFormat("[virtual touchpad %d]\n", i);
+    if (!touchpad.injector) {
+      result.append("injector = none\n");
+      return;
+    }
+    result.appendFormat("injector = %s\n",
+                        touchpad.owned_injector ? "normal" : "test");
+    result.appendFormat("touches = %d\n", touchpad.touches);
+    result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
+                        touchpad.last_device_x, touchpad.last_device_y);
+    result.appendFormat("last_buttons = 0x%" PRIX32 "\n",
+                        touchpad.last_motion_event_buttons);
+    touchpad.injector->dumpInternal(result);
+    result.append("\n");
   }
-  result.appendFormat("injector = %s\n", owned_injector_ ? "normal" : "test");
-  result.appendFormat("touches = %d\n", touches_);
-  result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
-                      last_device_x_, last_device_y_);
-  result.appendFormat("last_buttons = 0x%" PRIX32 "\n\n",
-                      last_motion_event_buttons_);
-  injector_->dumpInternal(result);
 }
 
 }  // namespace dvr