Merge "Installd: Refactor in preparation for OTA"
diff --git a/include/android/input.h b/include/android/input.h
index 5ab4e29..5eeb7fc 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -644,6 +644,13 @@
      */
     AMOTION_EVENT_AXIS_TILT = 25,
     /**
+     * Axis constant:  Generic scroll axis of a motion event.
+     *
+     * - This is used for scroll axis motion events that can't be classified as strictly
+     *   vertical or horizontal. The movement of a rotating scroller is an example of this.
+     */
+    AMOTION_EVENT_AXIS_SCROLL = 26,
+    /**
      * Axis constant: Generic 1 axis of a motion event.
      * The interpretation of a generic axis is device-specific.
      */
@@ -817,6 +824,8 @@
     AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
     /** joystick */
     AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
+    /** rotary encoder */
+    AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE,
 
     /** any */
     AINPUT_SOURCE_ANY = 0xffffff00,
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index ef01745..9271ed8 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -809,15 +809,6 @@
         mCore->validateConsistencyLocked();
     } // Autolock scope
 
-    // Wait without lock held
-    if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) {
-        // Waiting here allows for two full buffers to be queued but not a
-        // third. In the event that frames take varying time, this makes a
-        // small trade-off in favor of latency rather than throughput.
-        mLastQueueBufferFence->waitForever("Throttling EGL Production");
-        mLastQueueBufferFence = fence;
-    }
-
     // Don't send the GraphicBuffer through the callback, and don't send
     // the slot number, since the consumer shouldn't need it
     item.mGraphicBuffer.clear();
@@ -841,6 +832,15 @@
         mCallbackCondition.broadcast();
     }
 
+    // Wait without lock held
+    if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) {
+        // Waiting here allows for two full buffers to be queued but not a
+        // third. In the event that frames take varying time, this makes a
+        // small trade-off in favor of latency rather than throughput.
+        mLastQueueBufferFence->waitForever("Throttling EGL Production");
+        mLastQueueBufferFence = fence;
+    }
+
     return NO_ERROR;
 }
 
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 5e02ef1..3f9e332 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -101,11 +101,12 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= 		\
-	GLES2/gl2.cpp.arm 	\
+LOCAL_SRC_FILES:= \
+	GLES2/gl2.cpp   \
 #
 
 LOCAL_CLANG := false
+LOCAL_ARM_MODE := arm
 LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
 LOCAL_MODULE:= libGLESv2
 
@@ -120,14 +121,32 @@
 # TODO: This is to work around b/20093774. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
 
-# Symlink libGLESv3.so -> libGLESv2.so
-# Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
-# will be linked against libGLESv3.so.
-# Note we defer the evaluation of the LOCAL_POST_INSTALL_CMD,
-# so $(LOCAL_INSTALLED_MODULE) will be expanded to correct value,
-# even for both 32-bit and 64-bit installed files in multilib build.
-LOCAL_POST_INSTALL_CMD = \
-    $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))libGLESv3.so
+include $(BUILD_SHARED_LIBRARY)
+
+###############################################################################
+# Build the wrapper OpenGL ES 3.x library (this is just different name for v2)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	GLES2/gl2.cpp   \
+#
+
+LOCAL_CLANG := false
+LOCAL_ARM_MODE := arm
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
+LOCAL_MODULE:= libGLESv3
+LOCAL_SHARED_LIBRARIES += libdl
+# we need to access the private Bionic header <bionic_tls.h>
+LOCAL_C_INCLUDES += bionic/libc/private
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv3\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 5859606..2a53dec 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -1191,6 +1191,15 @@
         device->classes |= INPUT_DEVICE_CLASS_CURSOR;
     }
 
+    // See if this is a rotary encoder type device.
+    String8 deviceType = String8();
+    if (device->configuration &&
+        device->configuration->tryGetProperty(String8("device.type"), deviceType)) {
+            if (!deviceType.compare(String8("rotaryEncoder"))) {
+                device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER;
+            }
+    }
+
     // See if this is a touch pad.
     // Is this a new modern multi-touch driver?
     if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 0f94c77..6869253 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -137,6 +137,9 @@
     /* The input device is an external stylus (has data we want to fuse with touch data). */
     INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
 
+    /* The input device has a rotary encoder */
+    INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000,
+
     /* The input device is virtual (not a real device, not part of UI configuration). */
     INPUT_DEVICE_CLASS_VIRTUAL       = 0x40000000,
 
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index e10a101..2aee8ad 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -450,6 +450,11 @@
         device->addMapper(new SwitchInputMapper(device));
     }
 
+    // Scroll wheel-like devices.
+    if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
+        device->addMapper(new RotaryEncoderInputMapper(device));
+    }
+
     // Vibrator-like devices.
     if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
         device->addMapper(new VibratorInputMapper(device));
@@ -2728,6 +2733,92 @@
     }
 }
 
+// --- RotaryEncoderInputMapper ---
+
+RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
+        InputMapper(device) {
+    mSource = AINPUT_SOURCE_ROTARY_ENCODER;
+}
+
+RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {
+}
+
+uint32_t RotaryEncoderInputMapper::getSources() {
+    return mSource;
+}
+
+void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+    InputMapper::populateDeviceInfo(info);
+
+    if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) {
+        info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f);
+    }
+}
+
+void RotaryEncoderInputMapper::dump(String8& dump) {
+    dump.append(INDENT2 "Rotary Encoder Input Mapper:\n");
+    dump.appendFormat(INDENT3 "HaveWheel: %s\n",
+            toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
+}
+
+void RotaryEncoderInputMapper::configure(nsecs_t when,
+        const InputReaderConfiguration* config, uint32_t changes) {
+    InputMapper::configure(when, config, changes);
+    if (!changes) {
+        mRotaryEncoderScrollAccumulator.configure(getDevice());
+    }
+}
+
+void RotaryEncoderInputMapper::reset(nsecs_t when) {
+    mRotaryEncoderScrollAccumulator.reset(getDevice());
+
+    InputMapper::reset(when);
+}
+
+void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) {
+    mRotaryEncoderScrollAccumulator.process(rawEvent);
+
+    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+        sync(rawEvent->when);
+    }
+}
+
+void RotaryEncoderInputMapper::sync(nsecs_t when) {
+    PointerCoords pointerCoords;
+    pointerCoords.clear();
+
+    PointerProperties pointerProperties;
+    pointerProperties.clear();
+    pointerProperties.id = 0;
+    pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN;
+
+    float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel();
+    bool scrolled = scroll != 0;
+
+    // This is not a pointer, so it's not associated with a display.
+    int32_t displayId = ADISPLAY_ID_NONE;
+
+    // Moving the rotary encoder should wake the device (if specified).
+    uint32_t policyFlags = 0;
+    if (scrolled && getDevice()->isExternal()) {
+        policyFlags |= POLICY_FLAG_WAKE;
+    }
+
+    // Send motion event.
+    if (scrolled) {
+        int32_t metaState = mContext->getGlobalMetaState();
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll);
+
+        NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
+                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
+                AMOTION_EVENT_EDGE_FLAG_NONE,
+                displayId, 1, &pointerProperties, &pointerCoords,
+                0, 0, 0);
+        getListener()->notifyMotion(&scrollArgs);
+    }
+
+    mRotaryEncoderScrollAccumulator.finishSync();
+}
 
 // --- TouchInputMapper ---
 
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 3a5c76f..1de9d19 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1231,6 +1231,26 @@
 };
 
 
+class RotaryEncoderInputMapper : public InputMapper {
+public:
+    RotaryEncoderInputMapper(InputDevice* device);
+    virtual ~RotaryEncoderInputMapper();
+
+    virtual uint32_t getSources();
+    virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
+    virtual void dump(String8& dump);
+    virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
+    virtual void reset(nsecs_t when);
+    virtual void process(const RawEvent* rawEvent);
+
+private:
+    CursorScrollAccumulator mRotaryEncoderScrollAccumulator;
+
+    int32_t mSource;
+
+    void sync(nsecs_t when);
+};
+
 class TouchInputMapper : public InputMapper {
 public:
     TouchInputMapper(InputDevice* device);