Bug 712973 - Use InputReader from libui in gonk widget backend, r=cjones
authorMichael Wu <mwu@mozilla.com>
Wed, 25 Jan 2012 11:00:34 -0800
changeset 86590 df5b6590fcd3ae161b65ae3d4efb1e5c98493255
parent 86589 6a64b8fcffaf630d0ca1a8d446e91cfdb323c9c3
child 86591 a79f4ada83431c06d2d4bc8debb4161ea708986f
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs712973
milestone12.0a1
Bug 712973 - Use InputReader from libui in gonk widget backend, r=cjones
configure.in
toolkit/library/Makefile.in
widget/gonk/nsAppShell.cpp
widget/gonk/nsAppShell.h
--- a/configure.in
+++ b/configure.in
@@ -332,16 +332,17 @@ if test -n "$gonkdir" ; then
         HOST_CXXFLAGS=" "
     fi
     if test -z "$HOST_LDFLAGS" ; then
         HOST_LDFLAGS=" "
     fi
 
     AC_DEFINE(ANDROID)
     AC_DEFINE(HAVE_SYS_UIO_H)
+    AC_DEFINE(HAVE_PTHREADS)
     CROSS_COMPILE=1
     MOZ_CHROME_FILE_FORMAT=omni
     ZLIB_DIR=yes
     direct_nspr_config=1
 else
 case "$target" in
 *-android*|*-linuxandroid*)
     if test -z "$android_ndk" ; then
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -420,16 +420,17 @@ OS_LIBS += -lGLESv2
 endif
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 OS_LIBS += \
   -lui \
   -lmedia \
   -lhardware_legacy \
   -lhardware \
+  -lutils \
   $(NULL)
 endif
 
 EXTRA_DEPS += \
   $(topsrcdir)/intl/unicharutil/util/objs.mk \
   $(topsrcdir)/rdf/util/src/objs.mk \
   $(NULL)
 
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -37,67 +37,51 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #define _GNU_SOURCE
 
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <linux/input.h>
 #include <signal.h>
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "nscore.h"
 #include "mozilla/FileUtils.h"
+#include "mozilla/Mutex.h"
 #include "mozilla/Services.h"
 #include "nsAppShell.h"
 #include "nsGkAtoms.h"
 #include "nsGUIEvent.h"
 #include "nsIObserverService.h"
 #include "nsWindow.h"
 
 #include "android/log.h"
-
-#ifndef ABS_MT_TOUCH_MAJOR
-// Taken from include/linux/input.h
-// XXX update the bionic input.h so we don't have to do this!
-#define ABS_X			0x00
-#define ABS_Y			0x01
-// ...
-#define ABS_MT_TOUCH_MAJOR      0x30    /* Major axis of touching ellipse */
-#define ABS_MT_TOUCH_MINOR      0x31    /* Minor axis (omit if circular) */
-#define ABS_MT_WIDTH_MAJOR      0x32    /* Major axis of approaching ellipse */
-#define ABS_MT_WIDTH_MINOR      0x33    /* Minor axis (omit if circular) */
-#define ABS_MT_ORIENTATION      0x34    /* Ellipse orientation */
-#define ABS_MT_POSITION_X       0x35    /* Center X ellipse position */
-#define ABS_MT_POSITION_Y       0x36    /* Center Y ellipse position */
-#define ABS_MT_TOOL_TYPE        0x37    /* Type of touching device */
-#define ABS_MT_BLOB_ID          0x38    /* Group a set of packets as a blob */
-#define ABS_MT_TRACKING_ID      0x39    /* Unique ID of initiated contact */
-#define ABS_MT_PRESSURE         0x3a    /* Pressure on contact area */
-#define SYN_MT_REPORT           2
-#endif
+#include "ui/EventHub.h"
+#include "ui/InputReader.h"
+#include "ui/InputDispatcher.h"
 
 #define LOG(args...)                                            \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #ifdef VERBOSE_LOG_ENABLED
 # define VERBOSE_LOG(args...)                           \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #else
 # define VERBOSE_LOG(args...)                   \
     (void)0
 #endif
 
 using namespace mozilla;
+using namespace android;
 
 bool gDrawRequest = false;
 static nsAppShell *gAppShell = NULL;
 static int epollfd = 0;
 static int signalfds[2] = {0};
 
 namespace mozilla {
 
@@ -118,139 +102,237 @@ pipeHandler(int fd, FdHandler *data)
 {
     ssize_t len;
     do {
         char tmp[32];
         len = read(fd, tmp, sizeof(tmp));
     } while (len > 0);
 }
 
-static
-PRUint64 timevalToMS(const struct timeval &time)
-{
-    return time.tv_sec * 1000 + time.tv_usec / 1000;
-}
-
 static void
-sendMouseEvent(PRUint32 msg, struct timeval& time, int x, int y)
+sendMouseEvent(PRUint32 msg, uint64_t timeMs, int x, int y)
 {
     nsMouseEvent event(true, msg, NULL,
                        nsMouseEvent::eReal, nsMouseEvent::eNormal);
 
     event.refPoint.x = x;
     event.refPoint.y = y;
-    event.time = timevalToMS(time);
+    event.time = timeMs;
     event.isShift = false;
     event.isControl = false;
     event.isMeta = false;
     event.isAlt = false;
     event.button = nsMouseEvent::eLeftButton;
     if (msg != NS_MOUSE_MOVE)
         event.clickCount = 1;
 
     nsWindow::DispatchInputEvent(event);
 }
 
 static nsEventStatus
 sendKeyEventWithMsg(PRUint32 keyCode,
                     PRUint32 msg,
-                    const timeval &time,
+                    uint64_t timeMs,
                     PRUint32 flags)
 {
     nsKeyEvent event(true, msg, NULL);
     event.keyCode = keyCode;
-    event.time = timevalToMS(time);
+    event.time = timeMs;
     event.flags |= flags;
     return nsWindow::DispatchInputEvent(event);
 }
 
 static void
-sendKeyEvent(PRUint32 keyCode, bool down, const timeval &time)
+sendKeyEvent(PRUint32 keyCode, bool down, uint64_t timeMs)
 {
     nsEventStatus status =
-        sendKeyEventWithMsg(keyCode, down ? NS_KEY_DOWN : NS_KEY_UP, time, 0);
+        sendKeyEventWithMsg(keyCode, down ? NS_KEY_DOWN : NS_KEY_UP, timeMs, 0);
     if (down) {
-        sendKeyEventWithMsg(keyCode, NS_KEY_PRESS, time,
+        sendKeyEventWithMsg(keyCode, NS_KEY_PRESS, timeMs,
                             status == nsEventStatus_eConsumeNoDefault ?
                             NS_EVENT_FLAG_NO_DEFAULT : 0);
     }
 }
 
 static void
-sendSpecialKeyEvent(nsIAtom *command, const timeval &time)
+sendSpecialKeyEvent(nsIAtom *command, uint64_t timeMs)
 {
     nsCommandEvent event(true, nsGkAtoms::onAppCommand, command, NULL);
-    event.time = timevalToMS(time);
+    event.time = timeMs;
     nsWindow::DispatchInputEvent(event);
 }
 
 static void
-maybeSendKeyEvent(int keyCode, bool pressed, const timeval& time)
+maybeSendKeyEvent(int keyCode, bool pressed, uint64_t timeMs)
 {
     switch (keyCode) {
     case KEY_BACK:
-        sendKeyEvent(NS_VK_ESCAPE, pressed, time);
+        sendKeyEvent(NS_VK_ESCAPE, pressed, timeMs);
         break;
     case KEY_MENU:
         if (!pressed)
-            sendSpecialKeyEvent(nsGkAtoms::Menu, time);
+            sendSpecialKeyEvent(nsGkAtoms::Menu, timeMs);
         break;
     case KEY_SEARCH:
         if (pressed)
-            sendSpecialKeyEvent(nsGkAtoms::Search, time);
+            sendSpecialKeyEvent(nsGkAtoms::Search, timeMs);
         break;
     case KEY_HOME:
-        sendKeyEvent(NS_VK_HOME, pressed, time);
+        sendKeyEvent(NS_VK_HOME, pressed, timeMs);
         break;
     case KEY_POWER:
-        sendKeyEvent(NS_VK_SLEEP, pressed, time);
+        sendKeyEvent(NS_VK_SLEEP, pressed, timeMs);
         break;
     case KEY_VOLUMEUP:
         if (pressed)
-            sendSpecialKeyEvent(nsGkAtoms::VolumeUp, time);
+            sendSpecialKeyEvent(nsGkAtoms::VolumeUp, timeMs);
         break;
     case KEY_VOLUMEDOWN:
         if (pressed)
-            sendSpecialKeyEvent(nsGkAtoms::VolumeDown, time);
+            sendSpecialKeyEvent(nsGkAtoms::VolumeDown, timeMs);
         break;
     default:
         VERBOSE_LOG("Got unknown key event code. type 0x%04x code 0x%04x value %d",
                     keyCode, pressed);
     }
 }
 
-static void
-maybeSendKeyEvent(const input_event& e)
-{
-    if (e.type != EV_KEY) {
-        VERBOSE_LOG("Got unknown key event type. type 0x%04x code 0x%04x value %d",
-            e.type, e.code, e.value);
-        return;
-    }
+struct UserInputData {
+    uint64_t timeMs;
+    enum {
+        MOTION_DATA,
+        KEY_DATA
+    } type;
+    int32_t action;
+    int32_t flags;
+    int32_t metaState;
+    union {
+        struct {
+            int32_t keyCode;
+            int32_t scanCode;
+        } key;
+        struct {
+            PointerCoords coords;
+        } motion;
+    };
+};
+
+class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
+public:
+    GeckoInputReaderPolicy() {}
+
+    virtual bool getDisplayInfo(int32_t displayId,
+            int32_t* width, int32_t* height, int32_t* orientation);
+    virtual bool filterTouchEvents();
+    virtual bool filterJumpyTouchEvents();
+    virtual nsecs_t getVirtualKeyQuietTime();
+    virtual void getVirtualKeyDefinitions(const String8& deviceName,
+            Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
+    virtual void getInputDeviceCalibration(const String8& deviceName,
+            InputDeviceCalibration& outCalibration);
+    virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
+
+protected:
+    virtual ~GeckoInputReaderPolicy() {}
+};
+
+class GeckoInputDispatcher : public InputDispatcherInterface {
+public:
+    GeckoInputDispatcher()
+        : mQueueLock("GeckoInputDispatcher::mQueueMutex")
+    {}
+
+    virtual void dump(String8& dump);
+
+    // Called on the main thread
+    virtual void dispatchOnce();
 
-    if (e.value != 0 && e.value != 1) {
-        VERBOSE_LOG("Got unknown key event value. type 0x%04x code 0x%04x value %d",
-            e.type, e.code, e.value);
-        return;
-    }
+    // notify* methods are called on the InputReaderThread
+    virtual void notifyConfigurationChanged(nsecs_t eventTime);
+    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
+            uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
+            int32_t scanCode, int32_t metaState, nsecs_t downTime);
+    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
+            uint32_t policyFlags, int32_t action, int32_t flags,
+            int32_t metaState, int32_t edgeFlags,
+            uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
+            float xPrecision, float yPrecision, nsecs_t downTime);
+    virtual void notifySwitch(nsecs_t when,
+            int32_t switchCode, int32_t switchValue, uint32_t policyFlags);
+
+    virtual int32_t injectInputEvent(const InputEvent* event,
+            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
+    virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
+    virtual void setFocusedApplication(const InputApplication* inputApplication);
+    virtual void setInputDispatchMode(bool enabled, bool frozen);
+    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, bool monitor);
+    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
+
+protected:
+    virtual ~GeckoInputDispatcher() {}
 
-    bool pressed = e.value == 1;
-    maybeSendKeyEvent(e.code, pressed, e.time);
+private:
+    // mQueueLock should generally be locked while using mEventQueue.
+    // UserInputData is pushed on on the InputReaderThread and
+    // popped and dispatched on the main thread.
+    mozilla::Mutex mQueueLock;
+    std::queue<UserInputData> mEventQueue;
+};
+
+// GeckoInputReaderPolicy
+bool
+GeckoInputReaderPolicy::getDisplayInfo(int32_t displayId,
+                                       int32_t* width,
+                                       int32_t* height,
+                                       int32_t* orientation)
+{
+    // 0 is the default displayId. We only support one display
+    if (displayId)
+        return false;
+
+    if (width)
+        *width = gScreenBounds.width;
+    if (height)
+        *height = gScreenBounds.height;
+    if (orientation)
+        *orientation = ROTATION_0;
+    return true;
 }
 
-static void
-configureVButtons(FdHandler& data)
+bool
+GeckoInputReaderPolicy::filterTouchEvents()
+{
+    return false;
+}
+
+bool
+GeckoInputReaderPolicy::filterJumpyTouchEvents()
 {
+    return false;
+}
+
+nsecs_t
+GeckoInputReaderPolicy::getVirtualKeyQuietTime()
+{
+    return 0;
+}
+
+void
+GeckoInputReaderPolicy::getVirtualKeyDefinitions(const String8& deviceName,
+    Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions)
+{
+    outVirtualKeyDefinitions.clear();
+
     char vbuttonsPath[PATH_MAX];
     snprintf(vbuttonsPath, sizeof(vbuttonsPath),
              "/sys/board_properties/virtualkeys.%s",
-             data.name);
+             deviceName.string());
     ScopedClose fd(open(vbuttonsPath, O_RDONLY));
     if (0 > fd.mFd) {
-        LOG("No vbuttons for mt device %s", data.name);
+        LOG("No vbuttons for mt device %s", deviceName.string());
         return;
     }
 
     // This device has vbuttons.  Process the configuration.
     char config[1024];
     ssize_t nread;
     do {
         nread = read(fd.mFd, config, sizeof(config));
@@ -258,304 +340,246 @@ configureVButtons(FdHandler& data)
 
     if (0 > nread) {
         LOG("Error reading virtualkey configuration");
         return;
     }
 
     config[nread] = '\0';
 
-    LOG("Device %s has vbutton config '%s'", data.name, config);
+    LOG("Device %s has vbutton config '%s'", deviceName.string(), config);
 
-    char* startStr = config;
-    for (size_t i = 0; i < FdHandler::kMaxVButtons; ++i) {
-        FdHandler::VButton& vbutton = data.vbuttons[i];
-        char* token;
-        char* state;
-                
+    char* first = config;
+    char* magic;
+    char* state;
+    while ((magic = strtok_r(first, ":", &state))) {
         // XXX not clear what "0x01" is ... maybe a version
         // number?  See InputManager.java.
-        if (!(token = strtok_r(startStr, ":", &state)) ||
-            strcmp(token, "0x01")) {
+        if (strcmp(magic, "0x01")) {
             LOG("  magic 0x01 tag missing");
             break;
         }
-        startStr = NULL;
+        first = NULL;
 
-        if (!(token = strtok_r(NULL, ":", &state))) {
-            LOG("  failed to read keycode");
-            break;
-        }
-        vbutton.keyCode = atoi(token);
-
-        const char *centerX, *centerY, *width, *height;
-        if (!((centerX = strtok_r(NULL, ":", &state)) &&
+        const char *scanCode, *centerX, *centerY, *width, *height;
+        if (!((scanCode = strtok_r(NULL, ":", &state)) &&
+              (centerX = strtok_r(NULL, ":", &state)) &&
               (centerY = strtok_r(NULL, ":", &state)) &&
               (width = strtok_r(NULL, ":", &state)) &&
               (height = strtok_r(NULL, ":", &state)))) {
             LOG("  failed to read bound params");
             break;
         }
 
         // NB: these coordinates are in *screen* space, not input
         // space.  That means the values in /sys/board_config make
         // assumptions about how the raw input events are mapped
         // ... le sigh.
-        nsIntRect rect;
-        rect.width = atoi(width);
-        rect.height = atoi(height);
-        rect.x = atoi(centerX) - rect.width / 2;
-        rect.y = atoi(centerY) - rect.height / 2;
-        vbutton.buttonRect = rect;
+        VirtualKeyDefinition def;
+        def.scanCode = atoi(scanCode);
+        def.centerX = atoi(centerX);
+        def.centerY = atoi(centerY);
+        def.width = atoi(width);
+        def.height = atoi(height);
+        outVirtualKeyDefinitions.push(def);
 
         LOG("  configured vbutton code=%d at <x=%d,y=%d,w=%d,h=%d>",
-            vbutton.keyCode, rect.x, rect.y, rect.width, rect.height);
+            def.scanCode, def.centerX, def.centerY, def.width, def.height);
+    }
+}
+
+void
+GeckoInputReaderPolicy::getInputDeviceCalibration(const String8& deviceName,            InputDeviceCalibration& outCalibration)
+{
+    outCalibration.clear();
+}
+
+void
+GeckoInputReaderPolicy::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames)
+{
+    outExcludedDeviceNames.clear();
+}
+
+// GeckoInputDispatcher
+void
+GeckoInputDispatcher::dump(String8& dump)
+{
+}
+
+void
+GeckoInputDispatcher::dispatchOnce()
+{
+    UserInputData data;
+    {
+        MutexAutoLock lock(mQueueLock);
+        if (mEventQueue.empty())
+            return;
+
+        data = mEventQueue.front();
+        mEventQueue.pop();
+        if (!mEventQueue.empty())
+            gAppShell->NotifyNativeEvent();
+    }
+
+    switch (data.type) {
+    case UserInputData::MOTION_DATA: {
+        PRUint32 msg;
+        switch (data.action) {
+        case AMOTION_EVENT_ACTION_DOWN:
+            msg = NS_MOUSE_BUTTON_DOWN;
+            break;
+        case AMOTION_EVENT_ACTION_MOVE:
+            msg = NS_MOUSE_MOVE;
+            break;
+        case AMOTION_EVENT_ACTION_UP:
+            msg = NS_MOUSE_BUTTON_UP;
+            break;
+        }
+        sendMouseEvent(msg,
+                       data.timeMs,
+                       data.motion.coords.x,
+                       data.motion.coords.y);
+        break;
+    }
+    case UserInputData::KEY_DATA:
+        maybeSendKeyEvent(data.key.scanCode,
+                          data.action == AKEY_EVENT_ACTION_DOWN,
+                          data.timeMs);
+        break;
     }
 }
 
-static bool
-calibrateMultitouchDevice(FdHandler& data)
+
+void
+GeckoInputDispatcher::notifyConfigurationChanged(nsecs_t eventTime)
 {
-    if (data.calibrated)
-        return true;
-    if (gScreenBounds.IsEmpty()) {
-        // The framebuffer hasn't been initialized yet.  We *could*
-        // force it to be initialized here, but that's another patch.
-        LOG("Deferring multitouch calibrate, fb not ready");
-        return false;
-    }
+}
+
+static uint64_t
+nanosecsToMillisecs(nsecs_t nsecs)
+{
+    return nsecs / 1000000;
+}
 
-    struct input_absinfo xInfo, yInfo;
-    if (0 > ioctl(data.fd, EVIOCGABS(ABS_MT_POSITION_X), &xInfo) ||
-        0 > ioctl(data.fd, EVIOCGABS(ABS_MT_POSITION_Y), &yInfo)) {
-        LOG("Couldn't get absinfo for multitouch axes");
-        return false;
+void
+GeckoInputDispatcher::notifyKey(nsecs_t eventTime,
+                                int32_t deviceId,
+                                int32_t source,
+                                uint32_t policyFlags,
+                                int32_t action,
+                                int32_t flags,
+                                int32_t keyCode,
+                                int32_t scanCode,
+                                int32_t metaState,
+                                nsecs_t downTime)
+{
+    UserInputData data;
+    data.timeMs = nanosecsToMillisecs(eventTime);
+    data.type = UserInputData::KEY_DATA;
+    data.action = action;
+    data.flags = flags;
+    data.metaState = metaState;
+    data.key.keyCode = keyCode;
+    data.key.scanCode = scanCode;
+    {
+        MutexAutoLock lock(mQueueLock);
+        mEventQueue.push(data);
     }
-    LOG("Input coordinate bounds: xmin=%d, xmax=%d, ymin=%d, ymax=%d",
-        xInfo.minimum, xInfo.maximum, yInfo.minimum, yInfo.maximum);
-
-    data.inputMinX = xInfo.minimum;
-    data.inputMinY = yInfo.minimum;
-    data.inputToScreenScaleX =
-        float(gScreenBounds.width) / float(xInfo.maximum - xInfo.minimum);
-    data.inputToScreenScaleY =
-        float(gScreenBounds.height) / float(yInfo.maximum - yInfo.minimum);
-
-    configureVButtons(data);
-
-    data.calibrated = true;
-    return true;
+    gAppShell->NotifyNativeEvent();
 }
 
-static void
-multitouchHandler(int fd, FdHandler *data)
+void
+GeckoInputDispatcher::notifyMotion(nsecs_t eventTime,
+                                   int32_t deviceId,
+                                   int32_t source,
+                                   uint32_t policyFlags,
+                                   int32_t action,
+                                   int32_t flags,
+                                   int32_t metaState,
+                                   int32_t edgeFlags,
+                                   uint32_t pointerCount,
+                                   const int32_t* pointerIds,
+                                   const PointerCoords* pointerCoords,
+                                   float xPrecision,
+                                   float yPrecision,
+                                   nsecs_t downTime)
 {
-    if (!calibrateMultitouchDevice(*data))
-        return;
-
-    // The Linux's input documentation (Documentation/input/input.txt)
-    // says that we'll always read a multiple of sizeof(input_event) bytes here.
-    input_event events[16];
-    int event_count = read(fd, events, sizeof(events));
-    if (event_count < 0) {
-        LOG("Error reading in multitouchHandler");
-        return;
+    UserInputData data;
+    data.timeMs = nanosecsToMillisecs(eventTime);
+    data.type = UserInputData::MOTION_DATA;
+    data.action = action;
+    data.flags = flags;
+    data.metaState = metaState;
+    data.motion.coords = *pointerCoords;
+    {
+        MutexAutoLock lock(mQueueLock);
+        mEventQueue.push(data);
     }
-    MOZ_ASSERT(event_count % sizeof(input_event) == 0);
-
-    event_count /= sizeof(struct input_event);
-
-    for (int i = 0; i < event_count; i++) {
-        input_event *event = &events[i];
-
-        if (event->type == EV_ABS) {
-            if (data->mtState == FdHandler::MT_IGNORE)
-                continue;
-            if (data->mtState == FdHandler::MT_START)
-                data->mtState = FdHandler::MT_COLLECT;
+    gAppShell->NotifyNativeEvent();
+}
 
-            switch (event->code) {
-            case ABS_MT_TOUCH_MAJOR:
-                data->mtMajor = event->value;
-                break;
-            case ABS_MT_TOUCH_MINOR:
-            case ABS_MT_WIDTH_MAJOR:
-            case ABS_MT_WIDTH_MINOR:
-            case ABS_MT_ORIENTATION:
-            case ABS_MT_TOOL_TYPE:
-            case ABS_MT_BLOB_ID:
-            case ABS_MT_TRACKING_ID:
-            case ABS_MT_PRESSURE:
-                break;
-            case ABS_MT_POSITION_X:
-                data->mtX = data->inputXToScreenX(event->value);
-                break;
-            case ABS_MT_POSITION_Y:
-                data->mtY = data->inputYToScreenY(event->value);
-                break;
-            default:
-                VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
-                            event->type, event->code, event->value);
-                break;
-            }
-        } else if (event->type == EV_SYN) {
-            switch (event->code) {
-            case SYN_MT_REPORT:
-                if (data->mtState == FdHandler::MT_COLLECT)
-                    data->mtState = FdHandler::MT_IGNORE;
-                break;
-            case SYN_REPORT:
-                if (!data->mtMajor || data->mtState == FdHandler::MT_START) {
-                    data->mtDown = false;
-                    if (data->keyCode) {
-                        maybeSendKeyEvent(data->keyCode, data->mtDown,
-                                          event->time);
-                        data->keyCode = 0;
-                    } else {
-                        sendMouseEvent(NS_MOUSE_BUTTON_UP, event->time,
-                                       data->mtX, data->mtY);
-                    }
-                } else if (!data->mtDown) {
-                    int x = data->mtX, y = data->mtY;
-
-                    bool isKeyEvent = false;
-                    if (!gScreenBounds.Contains(x, y)) {
-                        // Off-screen mt down.  Should be a vbutton.
-                        for (size_t i = 0; i < FdHandler::kMaxVButtons; ++i) {
-                            const FdHandler::VButton& vbutton = data->vbuttons[i];
-                            if (vbutton.buttonRect.IsEmpty())
-                                break;
-
-                            if (vbutton.buttonRect.Contains(x, y)) {
-                                isKeyEvent = true;
-                                data->keyCode = vbutton.keyCode;
-                                break;
-                            }
-                        }
-                    }
-                    data->mtDown = true;
-
-                    if (isKeyEvent) {
-                        maybeSendKeyEvent(data->keyCode, data->mtDown,
-                                          event->time);
-                    } else {
-                        sendMouseEvent(NS_MOUSE_BUTTON_DOWN, event->time,
-                                       data->mtX, data->mtY);
-                    }
-                } else if (!data->keyCode) {
-                    sendMouseEvent(NS_MOUSE_MOVE, event->time,
-                                   data->mtX, data->mtY);
-                    data->mtDown = true;
-                }
-
-                data->mtState = FdHandler::MT_START;
-
-                break;
-            default:
-                VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
-                            event->type, event->code, event->value);
-
-            }
-        } else
-            VERBOSE_LOG("Got unknown mt event type 0x%04x with code 0x%04x and value %d",
-                        event->type, event->code, event->value);
-    }
+void
+GeckoInputDispatcher::notifySwitch(nsecs_t when,
+                                   int32_t switchCode,
+                                   int32_t switchValue,
+                                   uint32_t policyFlags)
+{
 }
 
-static void
-singleTouchHandler(int fd, FdHandler *data)
-{
-    // The Linux's input documentation (Documentation/input/input.txt)
-    // says that we'll always read a multiple of sizeof(input_event) bytes here.
-    input_event events[16];
-    int event_count = read(fd, events, sizeof(events));
-    if (event_count < 0) {
-        LOG("Error reading in singleTouchHandler");
-        return;
-    }
-    MOZ_ASSERT(event_count % sizeof(input_event) == 0);
-
-    event_count /= sizeof(struct input_event);
-
-    for (int i = 0; i < event_count; i++) {
-        input_event *event = &events[i];
 
-        if (event->type == EV_KEY) {
-            switch (event->code) {
-            case BTN_TOUCH:
-                data->mtDown = event->value;
-                break;
-            default:
-                maybeSendKeyEvent(*event);
-            }
-        } else if (event->type == EV_ABS) {
-            switch (event->code) {
-            case ABS_X:
-                data->mtX = event->value;
-                break;
-            case ABS_Y:
-                data->mtY = event->value;
-                break;
-            default:
-                LOG("Got unknown st abs event type 0x%04x with code 0x%04x and value %d",
-                    event->type, event->code, event->value);
-            }
-        } else if (event->type == EV_SYN) {
-            if (data->mtState == FdHandler::MT_START) {
-                MOZ_ASSERT(data->mtDown);
-                sendMouseEvent(NS_MOUSE_BUTTON_DOWN, event->time,
-                               data->mtX, data->mtY);
-                data->mtState = FdHandler::MT_COLLECT;
-            } else if (data->mtDown) {
-                MOZ_ASSERT(data->mtDown);
-                sendMouseEvent(NS_MOUSE_MOVE, event->time,
-                               data->mtX, data->mtY);
-            } else {
-                MOZ_ASSERT(!data->mtDown);
-                sendMouseEvent(NS_MOUSE_BUTTON_UP, event->time,
-                                   data->mtX, data->mtY);
-                data->mtDown = false;
-                data->mtState = FdHandler::MT_START;
-            }
-        }
-    }
+int32_t
+GeckoInputDispatcher::injectInputEvent(const InputEvent* event,
+                                       int32_t injectorPid,
+                                       int32_t injectorUid,
+                                       int32_t syncMode,
+                                       int32_t timeoutMillis)
+{
+    return INPUT_EVENT_INJECTION_SUCCEEDED;
+}
+
+void
+GeckoInputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows)
+{
 }
 
-static void
-keyHandler(int fd, FdHandler *data)
+void
+GeckoInputDispatcher::setFocusedApplication(const InputApplication* inputApplication)
 {
-    input_event events[16];
-    ssize_t bytesRead = read(fd, events, sizeof(events));
-    if (bytesRead < 0) {
-        LOG("Error reading in keyHandler");
-        return;
-    }
-    MOZ_ASSERT(bytesRead % sizeof(input_event) == 0);
+}
+
+void
+GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
+{
+}
 
-    for (unsigned int i = 0; i < bytesRead / sizeof(struct input_event); i++) {
-        const input_event &e = events[i];
+status_t
+GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
+                                           bool monitor)
+{
+    return OK;
+}
 
-        if (e.type == EV_SYN) {
-            // Ignore this event; it just signifies that a key was pressed.
-            continue;
-        }
-
-        maybeSendKeyEvent(e);
-    }
+status_t
+GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel)
+{
+    return OK;
 }
 
 nsAppShell::nsAppShell()
     : mNativeCallbackRequest(false)
     , mHandlers()
 {
     gAppShell = this;
 }
 
 nsAppShell::~nsAppShell()
 {
+    status_t result = mReaderThread->requestExitAndWait();
+    if (result)
+        LOG("Could not stop reader thread - %d", result);
     gAppShell = NULL;
 }
 
 nsresult
 nsAppShell::Init()
 {
     nsresult rv = nsBaseAppShell::Init();
     NS_ENSURE_SUCCESS(rv, rv);
@@ -564,62 +588,25 @@ nsAppShell::Init()
     NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED);
 
     int ret = pipe2(signalfds, O_NONBLOCK);
     NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED);
 
     rv = AddFdHandler(signalfds[0], pipeHandler, "");
     NS_ENSURE_SUCCESS(rv, rv);
 
-    DIR *dir = opendir("/dev/input");
-    NS_ENSURE_TRUE(dir, NS_ERROR_UNEXPECTED);
-
-#define IS_BIT_SET(bit, flags) (flags[bit >> 3] & (1 << (bit & 0x7)))
-
-    struct dirent *entry;
-    while ((entry = readdir(dir))) {
-        char entryName[64];
-        char entryPath[MAXPATHLEN];
-        if (snprintf(entryPath, sizeof(entryPath),
-                     "/dev/input/%s", entry->d_name) < 0) {
-            LOG("Couldn't generate path while enumerating input devices!");
-            continue;
-        }
-        int fd = open(entryPath, O_RDONLY);
-        if (ioctl(fd, EVIOCGNAME(sizeof(entryName)), entryName) >= 0)
-            LOG("Found device %s - %s", entry->d_name, entryName);
-        else
-            continue;
-
-        FdHandlerCallback handlerFunc = NULL;
+    mEventHub = new EventHub();
+    mReaderPolicy = new GeckoInputReaderPolicy();
+    mDispatcher = new GeckoInputDispatcher();
 
-        char flags[(NS_MAX(ABS_MAX, KEY_MAX) + 1) / 8];
-        if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(flags)), flags) >= 0 &&
-            IS_BIT_SET(ABS_MT_POSITION_X, flags)) {
+    mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
+    mReaderThread = new InputReaderThread(mReader);
 
-            LOG("Found multitouch input device");
-            handlerFunc = multitouchHandler;
-        } else if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(flags)), flags) >= 0 &&
-                   IS_BIT_SET(ABS_X, flags)) {
-            LOG("Found single touch input device");
-            handlerFunc = singleTouchHandler;
-        } else if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(flags)), flags) >= 0) {
-            LOG("Found key input device");
-            handlerFunc = keyHandler;
-        }
-
-        // Register the handler, if we have one.
-        if (!handlerFunc)
-            continue;
-
-        rv = AddFdHandler(fd, handlerFunc, entryName);
-        if (NS_FAILED(rv))
-            LOG("Failed to add fd to epoll fd");
-    }
-
+    status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
+    NS_ENSURE_FALSE(result, NS_ERROR_UNEXPECTED);
     return rv;
 }
 
 nsresult
 nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc,
                          const char* deviceName)
 {
     epoll_event event = {
@@ -650,16 +637,18 @@ nsAppShell::ProcessNextNativeEvent(bool 
 
     int event_count;
     if ((event_count = epoll_wait(epollfd, events, 16,  mayWait ? -1 : 0)) <= 0)
         return true;
 
     for (int i = 0; i < event_count; i++)
         mHandlers[events[i].data.u32].run();
 
+    mDispatcher->dispatchOnce();
+
     // NativeEventCallback always schedules more if it needs it
     // so we can coalesce these.
     // See the implementation in nsBaseAppShell.cpp for more info
     if (mNativeCallbackRequest) {
         mNativeCallbackRequest = false;
         NativeEventCallback();
     }
 
--- a/widget/gonk/nsAppShell.h
+++ b/widget/gonk/nsAppShell.h
@@ -33,94 +33,59 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsAppShell_h
 #define nsAppShell_h
 
+#include <queue>
+
+#include "mozilla/Mutex.h"
 #include "nsBaseAppShell.h"
 #include "nsRect.h"
 #include "nsTArray.h"
 
+#include "utils/RefBase.h"
+
 namespace mozilla {
 bool ProcessNextEvent();
 void NotifyEvent();
 }
 
 extern bool gDrawRequest;
 
 class FdHandler;
 typedef void(*FdHandlerCallback)(int, FdHandler *);
 
 class FdHandler {
 public:
     FdHandler()
-        : mtState(MT_START)
-        , keyCode(0)
-        , mtDown(false)
-        , calibrated(false)
     {
         memset(name, 0, sizeof(name));
     }
 
     int fd;
     char name[64];
     FdHandlerCallback func;
-    enum mtStates {
-        MT_START,
-        MT_COLLECT,
-        MT_IGNORE
-    } mtState;
-    int mtX, mtY;
-    int mtMajor;
-    int keyCode;
-    bool mtDown;
-    // FIXME/bug 712973: we should be using libui here instead of
-    // recreating all that logic ourselves.  Please don't extend the
-    // hacks here further than what's below.
-    bool calibrated;
-    // Multitouch events are delivered to us in "input space", which
-    // is a coordinate space defined by the multitouch device driver.
-    // The coordinate space has top-left at P_min = <inputMinX,
-    // inputMinY> when in normal-portrait orientation.  The input
-    // device and the screen might have different resolutions.  The
-    // resolution difference is Scale = <inputToScreenScaleX,
-    // inputToScreenScaleY>.  So going from input to screen space
-    // (when in normal portrait orientation) is an affine transform
-    // defined by
-    //
-    //   P_screen = Scale * (P_input - P_min)
-    //
-    int inputMinX, inputMinY;
-    float inputToScreenScaleX, inputToScreenScaleY;
-    // Some touch devices use virtual buttons instead of hardware
-    // buttons.  When the device uses vbuttons, we convert touch
-    // events into key events of type |keyCode| when the start of the
-    // touch is within |buttonRect|.  |buttonRect| must be disjoint
-    // from the screen rect.
-    static const size_t kMaxVButtons = 4;
-    struct VButton {
-        nsIntRect buttonRect;   // in screen space
-        int keyCode;
-    } vbuttons[kMaxVButtons];
-
     void run()
     {
         func(fd, this);
     }
+};
 
-    int inputXToScreenX(int inputX) {
-        return inputToScreenScaleX * (inputX - inputMinX);
-    }
-    int inputYToScreenY(int inputY) {
-        return inputToScreenScaleY * (inputY - inputMinY);
-    }
-};
+namespace android {
+class EventHub;
+class InputReader;
+class InputReaderThread;
+}
+
+class GeckoInputReaderPolicy;
+class GeckoInputDispatcher;
 
 class nsAppShell : public nsBaseAppShell {
 public:
     nsAppShell();
 
     nsresult Init();
     virtual bool ProcessNextNativeEvent(bool maywait);
 
@@ -133,12 +98,18 @@ protected:
 
 private:
     nsresult AddFdHandler(int fd, FdHandlerCallback handlerFunc,
                           const char* deviceName);
 
     // This is somewhat racy but is perfectly safe given how the callback works
     bool mNativeCallbackRequest;
     nsTArray<FdHandler> mHandlers;
+
+    android::sp<android::EventHub>               mEventHub;
+    android::sp<GeckoInputReaderPolicy> mReaderPolicy;
+    android::sp<GeckoInputDispatcher>   mDispatcher;
+    android::sp<android::InputReader>            mReader;
+    android::sp<android::InputReaderThread>      mReaderThread;
 };
 
 #endif /* nsAppShell_h */