OSDN Git Service

Add DVR API for scroll event injection.
authorKevin Schoedel <kpschoedel@google.com>
Mon, 5 Jun 2017 15:13:20 +0000 (11:13 -0400)
committerKevin Schoedel <kpschoedel@google.com>
Tue, 6 Jun 2017 16:34:39 +0000 (12:34 -0400)
Bug: 62226675
Test: manual, vrcore build
Change-Id: Ic7d329eba8003b0e294b3a11a83ed5f868b801f8

15 files changed:
libs/vr/libdvr/dvr_api.cpp
libs/vr/libdvr/include/dvr/dvr_api.h
libs/vr/libdvr/include/dvr/dvr_api_entries.h
services/vr/virtual_touchpad/DvrVirtualTouchpadClient.cpp
services/vr/virtual_touchpad/EvdevInjector.cpp
services/vr/virtual_touchpad/EvdevInjector.h
services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
services/vr/virtual_touchpad/VirtualTouchpadService.cpp
services/vr/virtual_touchpad/VirtualTouchpadService.h
services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
services/vr/virtual_touchpad/include/VirtualTouchpad.h
services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h

index 5f35dcf..dc31917 100644 (file)
@@ -3,6 +3,8 @@
 #include <errno.h>
 #include <utils/Log.h>
 
+#include <algorithm>
+
 // Headers from libdvr
 #include <dvr/dvr_buffer.h>
 #include <dvr/dvr_buffer_queue.h>
@@ -23,15 +25,20 @@ int dvrGetApi(void* api, size_t struct_size, int version) {
   ALOGI("dvrGetApi: api=%p struct_size=%zu version=%d", api, struct_size,
         version);
   if (version == 1) {
-    if (struct_size != sizeof(DvrApi_v1)) {
-      ALOGE("dvrGetApi: Size mismatch: expected %zu; actual %zu",
-            sizeof(DvrApi_v1), struct_size);
-      return -EINVAL;
-    }
+    // New entry points are added at the end. If the caller's struct and
+    // this library have different sizes, we define the entry points in common.
+    // The caller is expected to handle unset entry points if necessary.
+    size_t clamped_struct_size = std::min(struct_size, sizeof(DvrApi_v1));
     DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
 
 // Defines an API entry for V1 (no version suffix).
-#define DVR_V1_API_ENTRY(name) dvr_api->name = dvr##name
+#define DVR_V1_API_ENTRY(name)                                 \
+  do {                                                         \
+    if ((offsetof(DvrApi_v1, name) + sizeof(dvr_api->name)) <= \
+        clamped_struct_size) {                                 \
+      dvr_api->name = dvr##name;                               \
+    }                                                          \
+  } while (0)
 
 #include "include/dvr/dvr_api_entries.h"
 
index 0c10907..4693c7f 100644 (file)
@@ -238,6 +238,8 @@ typedef int (*DvrVirtualTouchpadTouchPtr)(DvrVirtualTouchpad* client,
                                           float pressure);
 typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
                                                 int touchpad, int buttons);
+typedef int (*DvrVirtualTouchpadScrollPtr)(DvrVirtualTouchpad* client,
+                                           int touchpad, float x, float y);
 
 // dvr_hardware_composer_client.h
 typedef struct DvrHwcClient DvrHwcClient;
index 802a0f7..ae5ef18 100644 (file)
@@ -141,3 +141,9 @@ DVR_V1_API_ENTRY(HwcFrameGetLayerNumVisibleRegions);
 DVR_V1_API_ENTRY(HwcFrameGetLayerVisibleRegion);
 DVR_V1_API_ENTRY(HwcFrameGetLayerNumDamagedRegions);
 DVR_V1_API_ENTRY(HwcFrameGetLayerDamagedRegion);
+
+// New entries added at the end to allow the DVR platform library API
+// to be updated before updating VrCore.
+
+// Virtual touchpad client
+DVR_V1_API_ENTRY(VirtualTouchpadScroll);
index eb152ed..3ab77a7 100644 (file)
@@ -40,6 +40,11 @@ int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
   return FromC(client)->ButtonState(touchpad, buttons);
 }
 
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+                             float y) {
+  return FromC(client)->Scroll(touchpad, x, y);
+}
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
index a4ccdd0..7fad379 100644 (file)
@@ -168,6 +168,25 @@ int EvdevInjector::ConfigureAbsSlots(int slots) {
   return ConfigureAbs(ABS_MT_SLOT, 0, slots, 0, 0);
 }
 
+int EvdevInjector::ConfigureRel(uint16_t rel_type) {
+  ALOGV("ConfigureRel 0x%" PRIX16 "", rel_type);
+  if (rel_type < 0 || rel_type >= REL_CNT) {
+    ALOGE("EV_REL type 0x%" PRIX16 " out of range [0,0x%X)", rel_type, REL_CNT);
+    return Error(ERROR_REL_RANGE);
+  }
+  if (const int status = RequireState(State::CONFIGURING)) {
+    return status;
+  }
+  if (const int status = EnableEventType(EV_REL)) {
+    return status;
+  }
+  if (const int status = uinput_->IoctlSetInt(UI_SET_RELBIT, rel_type)) {
+    ALOGE("failed to enable EV_REL 0x%" PRIX16 "", rel_type);
+    return Error(status);
+  }
+  return 0;
+}
+
 int EvdevInjector::ConfigureEnd() {
   ALOGV("ConfigureEnd:");
   ALOGV("  name=\"%s\"", uidev_.name);
@@ -236,6 +255,10 @@ int EvdevInjector::SendAbs(uint16_t code, int32_t value) {
   return Send(EV_ABS, code, value);
 }
 
+int EvdevInjector::SendRel(uint16_t code, int32_t value) {
+  return Send(EV_REL, code, value);
+}
+
 int EvdevInjector::SendMultiTouchSlot(int32_t slot) {
   if (latest_slot_ != slot) {
     if (const int status = SendAbs(ABS_MT_SLOT, slot)) {
index c69dbef..e87c959 100644 (file)
@@ -30,6 +30,7 @@ class EvdevInjector {
     ERROR_KEY_RANGE = -3,       // |KEY_*|/|BTN_*| code out of range.
     ERROR_ABS_RANGE = -4,       // |ABS_*| code out of range.
     ERROR_SEQUENCING = -5,      // Configure/Send out of order.
+    ERROR_REL_RANGE = -6,       // |REL_*| code out of range.
   };
 
   // Key event |value| is not defined in <linux/input.h>.
@@ -87,6 +88,10 @@ class EvdevInjector {
   // Configure multitouch coordinate range.
   int ConfigureMultiTouchXY(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
 
+  // Configure a relative axis.
+  // @param rel_type One of the |REL_*| constants from <linux/input.h>.
+  int ConfigureRel(uint16_t rel_type);
+
   // Complete configuration and create the input device.
   int ConfigureEnd();
 
@@ -96,6 +101,7 @@ class EvdevInjector {
   int SendSynReport();
   int SendKey(uint16_t code, int32_t value);
   int SendAbs(uint16_t code, int32_t value);
+  int SendRel(uint16_t code, int32_t value);
   int SendMultiTouchSlot(int32_t slot);
   int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
   int SendMultiTouchLift(int32_t slot);
index c7c8184..00e4ce6 100644 (file)
@@ -60,6 +60,13 @@ class VirtualTouchpadClientImpl : public VirtualTouchpadClient {
     return service_->buttonState(touchpad, buttons).transactionError();
   }
 
+  status_t Scroll(int touchpad, float x, float y) override {
+    if (service_ == nullptr) {
+      return NO_INIT;
+    }
+    return service_->scroll(touchpad, x, y).transactionError();
+  }
+
   void dumpInternal(String8& result) override {
     result.append("[virtual touchpad]\n");
     result.appendFormat("connected = %s\n\n",
index f0bdcd9..ae56bf6 100644 (file)
@@ -28,6 +28,22 @@ static constexpr int32_t kWidth = 0x10000;
 static constexpr int32_t kHeight = 0x10000;
 static constexpr int32_t kSlots = 2;
 
+int32_t scale_relative_scroll(float x) {
+  // Guilty with an explanation, your honor.
+  // Ideally we should be able to communicate the full incoming precision
+  // to InputFlinger, through the evdev int32_t value, by scaling by a
+  // large factor, i.e. 2²³ for IEEE single precision floating point.
+  // However, although InputFlinger has |wheelVelocityControlParameters|,
+  // those parameters are currently hard coded, with a scale factor of 1.0.
+  // The observed evdev value for a physical mouse scroll wheel is usually
+  // ±1, with higher values up to ±4 for a very fast spin. So we imitate
+  // that. If the incoming value is not actually 0, the resulting magnitude
+  // should be at least 1, so that small movements are not lost.
+  // Adding IDC configurability of |VelocityControlParameters| may be
+  // desirable in the future.
+  return copysignf(ceilf(fabs(4.0f * x)), x);
+}
+
 }  // anonymous namespace
 
 std::unique_ptr<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
@@ -162,6 +178,32 @@ int VirtualTouchpadEvdev::ButtonState(int touchpad_id, int buttons) {
   return touchpad.injector->GetError();
 }
 
+int VirtualTouchpadEvdev::Scroll(int touchpad_id, float x, float y) {
+  if (touchpad_id < 0 || touchpad_id >= kTouchpads) {
+    return EINVAL;
+  }
+  if ((x < -1.0f) || (x > 1.0f) || (y < -1.0f) || (y > 1.0f)) {
+    return EINVAL;
+  }
+  Touchpad& touchpad = touchpad_[touchpad_id];
+  if (!touchpad.injector) {
+    return EvdevInjector::ERROR_SEQUENCING;
+  }
+  touchpad.injector->ResetError();
+  const int32_t scaled_x = scale_relative_scroll(x);
+  const int32_t scaled_y = scale_relative_scroll(y);
+  if (scaled_x) {
+    touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
+  }
+  if (scaled_y) {
+    touchpad.injector->SendRel(REL_WHEEL, scaled_y);
+  }
+  if (scaled_x || scaled_y) {
+    touchpad.injector->SendSynReport();
+  }
+  return touchpad.injector->GetError();
+}
+
 void VirtualTouchpadEvdev::dumpInternal(String8& result) {
   for (int i = 0; i < kTouchpads; ++i) {
     const auto& touchpad = touchpad_[i];
index 2fb8ff3..c9578bf 100644 (file)
@@ -21,6 +21,7 @@ class VirtualTouchpadEvdev : public VirtualTouchpad {
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  status_t Scroll(int touchpad, float x, float y) override;
   void dumpInternal(String8& result) override;
 
  protected:
index 81edd32..523f890 100644 (file)
@@ -87,6 +87,16 @@ binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) {
   return binder::Status::ok();
 }
 
+binder::Status VirtualTouchpadService::scroll(int touchpad, float x, float y) {
+  if (!CheckPermissions()) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  if (const status_t error = touchpad_->Scroll(touchpad, x, y)) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
+}
+
 status_t VirtualTouchpadService::dump(
     int fd, const Vector<String16>& args[[gnu::unused]]) {
   String8 result;
index cf236f9..2c46209 100644 (file)
@@ -23,6 +23,7 @@ class VirtualTouchpadService : public BnVirtualTouchpadService {
   binder::Status detach() override;
   binder::Status touch(int touchpad, float x, float y, float pressure) override;
   binder::Status buttonState(int touchpad, int buttons) override;
+  binder::Status scroll(int touchpad, float x, float y) override;
 
   // Implements BBinder::dump().
   status_t dump(int fd, const Vector<String16>& args) override;
index 9cfb186..256203c 100644 (file)
@@ -34,4 +34,15 @@ interface VirtualTouchpadService
    * @param buttons A union of MotionEvent BUTTON_* values.
    */
   void buttonState(int touchpad, int buttons) = 3;
+
+  /**
+   * Generate a simulated scroll event.
+   *
+   * @param touchpad Selects touchpad.
+   * @param x Horizontal scroll increment.
+   * @param y Vertical scroll increment.
+   *
+   * Scroll values are in the range [-1.0, 1.0].
+   */
+  void scroll(int touchpad, float x, float y) = 4;
 }
index da3a0b7..99b72fc 100644 (file)
@@ -61,6 +61,16 @@ class VirtualTouchpad {
   //
   virtual status_t ButtonState(int touchpad, int buttons) = 0;
 
+  // Generate a simulated scroll event.
+  //
+  // @param touchpad Touchpad selector index.
+  // @param x Horizontal scroll increment.
+  // @param y Vertical scroll increment.
+  //            Values must be in the range [-1.0, 1.0].
+  // @returns OK on success.
+  //
+  virtual status_t Scroll(int touchpad, float x, float y) = 0;
+
   // Report state for 'dumpsys'.
   virtual void dumpInternal(String8& result) = 0;
 
index 23fb9f8..7d73f06 100644 (file)
@@ -17,6 +17,7 @@ class VirtualTouchpadClient : public VirtualTouchpad {
   status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  status_t Scroll(int touchpad, float x, float y) override;
   void dumpInternal(String8& result) override;
 
  protected:
index 15e6687..09fb1cc 100644 (file)
@@ -61,6 +61,17 @@ int dvrVirtualTouchpadTouch(DvrVirtualTouchpad* client, int touchpad, float x,
 int dvrVirtualTouchpadButtonState(DvrVirtualTouchpad* client, int touchpad,
                                   int buttons);
 
+// Generate a simulated scroll event.
+//
+// @param client Pointer to the virtual touchpad client.
+// @param touchpad Selects touchpad.
+// @param x Horizontal scroll increment.
+// @param y Vertical scroll increment.
+// @return Zero on success, status_t-style error code on failure.
+//
+int dvrVirtualTouchpadScroll(DvrVirtualTouchpad* client, int touchpad, float x,
+                             float y);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif