Fix virtual touchpad scroll events.

1. Correctly configure the uinput device to pass REL_*WHEEL events.

2. Configure the virtual touchpad as a 'rotary encoder', which is
   an inputflinger device class originally provided for the G1 scroll
   ball. This provides two advantages over the default mouse-wheel
   interpretation:
   - It works without an associated mouse pointer to determine the
     event target.
   - It allows for higher resolution through a scale factor (the
     scaling here is chosen by experiment to feel no worse than wheel
     mode, but might benefit from future adjustment).
   There is one accompanying disadvantage: inputflinger only handles
   vertical scrolling (REL_WHEEL) and ignores the horizontal axis
   (REL_HWHEEL).

Bug: 62632827
Test: manual on sailfish
Change-Id: Ic8edad01796d75e8c94fa20f05a5badb0727a948
diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp
index b9aa8fe..6b11ce3 100644
--- a/services/vr/virtual_touchpad/Android.bp
+++ b/services/vr/virtual_touchpad/Android.bp
@@ -33,9 +33,6 @@
 test_static_libs = [
     "libcutils",
     "libvirtualtouchpad",
-]
-
-test_shared_libs = [
     "libbase",
     "liblog",
     "libutils",
@@ -46,7 +43,6 @@
 cc_test {
     srcs: test_src_files,
     static_libs: test_static_libs,
-    shared_libs: test_shared_libs,
     header_libs: header_libraries,
     cppflags = [
         "-std=c++11",
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index ae56bf6..251ed0e 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -28,20 +28,10 @@
 static constexpr int32_t kHeight = 0x10000;
 static constexpr int32_t kSlots = 2;
 
+static constexpr float kScrollScale = 100.0f;
+
 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);
+  return kScrollScale * x;
 }
 
 }  // anonymous namespace
@@ -82,6 +72,8 @@
     touchpad.injector->ConfigureInputProperty(INPUT_PROP_DIRECT);
     touchpad.injector->ConfigureMultiTouchXY(0, 0, kWidth - 1, kHeight - 1);
     touchpad.injector->ConfigureAbsSlots(kSlots);
+    touchpad.injector->ConfigureRel(REL_WHEEL);
+    touchpad.injector->ConfigureRel(REL_HWHEEL);
     touchpad.injector->ConfigureKey(BTN_TOUCH);
     touchpad.injector->ConfigureKey(BTN_BACK);
     touchpad.injector->ConfigureEnd();
@@ -192,6 +184,7 @@
   touchpad.injector->ResetError();
   const int32_t scaled_x = scale_relative_scroll(x);
   const int32_t scaled_y = scale_relative_scroll(y);
+  ALOGV("(%f,%f) -> (%" PRId32 ",%" PRId32 ")", x, y, scaled_x, scaled_y);
   if (scaled_x) {
     touchpad.injector->SendRel(REL_HWHEEL, scaled_x);
   }
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
new file mode 100644
index 0000000..205e8b9
--- /dev/null
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc
@@ -0,0 +1,26 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Virtual touchpad for the primary display
+device.internal = 1
+
+touch.deviceType = touchScreen
+
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
index 3728ef0..d9714e0 100644
--- a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
+++ b/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-1.idc
@@ -18,6 +18,13 @@
 
 touch.deviceType = touchScreen
 
+# Have input flinger treat injected scroll events like a G1 ball
+# rather than the default mouse wheel, because the latter requires
+# a visible pointer for targeting.
+device.type = rotaryEncoder
+device.res = 1.0e+2
+device.scalingFactor = 1.0e-2
+
 # This displayID matches the unique ID of the virtual display created for VR.
 # This will indicate to input flinger than it should link this input device
 # with the virtual display.
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 564bcd7..b19b018 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -169,6 +169,11 @@
     expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_POSITION_Y);
     // From ConfigureAbsSlots(kSlots):
     expect.IoctlSetInt(UI_SET_ABSBIT, ABS_MT_SLOT);
+    // From ConfigureRel(REL_WHEEL):
+    expect.IoctlSetInt(UI_SET_EVBIT, EV_REL);
+    expect.IoctlSetInt(UI_SET_RELBIT, REL_WHEEL);
+    // From ConfigureRel(REL_HWHEEL):
+    expect.IoctlSetInt(UI_SET_RELBIT, REL_HWHEEL);
     // From ConfigureKey(BTN_TOUCH):
     expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
     expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);