Add synthetic back button to virtual touchpad/stylus.

Also add a bit more error checking and documentation.

Test: added to VirtualTouchpad_test.cpp
Bug: 34673438
Change-Id: I3851a2ad79c5338cdd1db0c7d460aecfff082cc3
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.cpp b/services/vr/virtual_touchpad/VirtualTouchpad.cpp
index b137dd7..f3936fc 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpad.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpad.cpp
@@ -1,20 +1,29 @@
 #include "VirtualTouchpad.h"
 
+#include <android/input.h>
 #include <cutils/log.h>
 #include <inttypes.h>
 #include <linux/input.h>
 
+// References:
+//  [0] Multi-touch (MT) Protocol,
+//      https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt
+
 namespace android {
 namespace dvr {
 
 namespace {
 
-// Virtual evdev device properties.
+// Virtual evdev device properties. The name is arbitrary, but Android can
+// 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 constexpr int16_t kDeviceBusType = BUS_VIRTUAL;
-static constexpr int16_t kDeviceVendor = 0x18D1;   // Google USB vendor ID.
-static constexpr int16_t kDeviceProduct = 0x5652;  // 'VR'
+static constexpr int16_t kDeviceVendor = 0;
+static constexpr int16_t kDeviceProduct = 0;
 static constexpr int16_t kDeviceVersion = 0x0001;
+
 static constexpr int32_t kWidth = 0x10000;
 static constexpr int32_t kHeight = 0x10000;
 static constexpr int32_t kSlots = 2;
@@ -32,18 +41,24 @@
   injector_->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
   injector_->ConfigureAbsSlots(kSlots);
   injector_->ConfigureKey(BTN_TOUCH);
+  injector_->ConfigureKey(BTN_BACK);
   injector_->ConfigureEnd();
   return injector_->GetError();
 }
 
 int VirtualTouchpad::Touch(float x, float y, float pressure) {
-  int error = 0;
+  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);
   ALOGV("(%f,%f) %f -> (%" PRId32 ",%" PRId32 ") %d",
         x, y, pressure, device_x, device_y, touches_);
 
+  if (!injector_) {
+    return EvdevInjector::ERROR_SEQUENCING;
+  }
   injector_->ResetError();
   switch (touches_) {
     case 0b00:  // Hover continues.
@@ -76,5 +91,30 @@
   return injector_->GetError();
 }
 
+int VirtualTouchpad::ButtonState(int buttons) {
+  const int changes = 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_,
+        buttons);
+
+  if (!injector_) {
+    return EvdevInjector::ERROR_SEQUENCING;
+  }
+  injector_->ResetError();
+  if (changes & AMOTION_EVENT_BUTTON_BACK) {
+    injector_->SendKey(BTN_BACK,
+                       (buttons & AMOTION_EVENT_BUTTON_BACK)
+                           ? EvdevInjector::KEY_PRESS
+                           : EvdevInjector::KEY_RELEASE);
+  }
+  last_motion_event_buttons_ = buttons;
+  return injector_->GetError();
+}
+
 }  // namespace dvr
 }  // namespace android