First stab at attaching native event dispatching.

Provides the basic infrastructure for a
NativeActivity's native code to get an object representing
its event stream that can be used to read input events.

Still work to do, probably some API changes, and reasonable
default key handling (so that for example back will still
work).

Change-Id: I6db891bc35dc9683181d7708eaed552b955a077e
diff --git a/api/current.xml b/api/current.xml
index a21f42b..2266257 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26306,6 +26306,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<implements name="android.view.InputConsumer.Callback">
+</implements>
 <implements name="android.view.SurfaceHolder.Callback">
 </implements>
 <constructor name="NativeActivity"
@@ -26316,6 +26318,32 @@
  visibility="public"
 >
 </constructor>
+<method name="onInputConsumerCreated"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="consumer" type="android.view.InputConsumer">
+</parameter>
+</method>
+<method name="onInputConsumerDestroyed"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="consumer" type="android.view.InputConsumer">
+</parameter>
+</method>
 <method name="surfaceChanged"
  return="void"
  abstract="false"
@@ -172813,6 +172841,49 @@
 </parameter>
 </constructor>
 </class>
+<class name="InputConsumer"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</class>
+<interface name="InputConsumer.Callback"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onInputConsumerCreated"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="consumer" type="android.view.InputConsumer">
+</parameter>
+</method>
+<method name="onInputConsumerDestroyed"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="consumer" type="android.view.InputConsumer">
+</parameter>
+</method>
+</interface>
 <class name="KeyCharacterMap"
  extends="java.lang.Object"
  abstract="false"
@@ -187266,6 +187337,19 @@
 <parameter name="event" type="android.view.MotionEvent">
 </parameter>
 </method>
+<method name="takeInputChannel"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="callback" type="android.view.InputConsumer.Callback">
+</parameter>
+</method>
 <method name="takeKeyEvents"
  return="void"
  abstract="true"
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index fd20b71..973ad60 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -6,6 +6,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
+import android.view.InputChannel;
+import android.view.InputConsumer;
 import android.view.SurfaceHolder;
 
 import java.io.File;
@@ -14,7 +16,8 @@
  * Convenience for implementing an activity that will be implemented
  * purely in native code.  That is, a game (or game-like thing).
  */
-public class NativeActivity extends Activity implements SurfaceHolder.Callback {
+public class NativeActivity extends Activity implements SurfaceHolder.Callback,
+        InputConsumer.Callback {
     public static final String META_DATA_LIB_NAME = "android.app.lib_name";
     
     private int mNativeHandle;
@@ -33,6 +36,8 @@
     private native void onSurfaceChangedNative(int handle, SurfaceHolder holder,
             int format, int width, int height);
     private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder);
+    private native void onInputChannelCreatedNative(int handle, InputChannel channel);
+    private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -40,6 +45,7 @@
         ActivityInfo ai;
         
         getWindow().takeSurface(this);
+        getWindow().takeInputChannel(this);
         
         try {
             ai = getPackageManager().getActivityInfo(
@@ -138,4 +144,12 @@
     public void surfaceDestroyed(SurfaceHolder holder) {
         onSurfaceDestroyedNative(mNativeHandle, holder);
     }
+    
+    public void onInputConsumerCreated(InputConsumer consumer) {
+        onInputChannelCreatedNative(mNativeHandle, consumer.getInputChannel());
+    }
+    
+    public void onInputConsumerDestroyed(InputConsumer consumer) {
+        onInputChannelDestroyedNative(mNativeHandle, consumer.getInputChannel());
+    }
 }
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index e5ebc69..e24c3c9 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -22,8 +22,9 @@
 
 /**
  * An input channel specifies the file descriptors used to send input events to
- * a window in another process.  It is Parcelable so that it can be transmitted
- * to the ViewRoot through a Binder transaction as part of registering the Window.
+ * a window in another process.  It is Parcelable so that it can be sent
+ * to the process that is to receive events.  Only one thread should be reading
+ * from an InputChannel at a time.
  * @hide
  */
 public final class InputChannel implements Parcelable {
diff --git a/core/java/android/view/InputConsumer.java b/core/java/android/view/InputConsumer.java
new file mode 100644
index 0000000..63b26c6
--- /dev/null
+++ b/core/java/android/view/InputConsumer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+package android.view;
+
+/**
+ * Handle for consuming raw input events.
+ */
+public class InputConsumer {
+    public static interface Callback {
+        void onInputConsumerCreated(InputConsumer consumer);
+        void onInputConsumerDestroyed(InputConsumer consumer);
+    }
+
+    final InputChannel mChannel;
+    
+    /** @hide */
+    public InputConsumer(InputChannel channel) {
+        mChannel = channel;
+    }
+    
+    /** @hide */
+    public InputChannel getInputChannel() {
+        return mChannel;
+    }
+}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index a41c690d..8984b74 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -154,7 +154,9 @@
 
     final View.AttachInfo mAttachInfo;
     InputChannel mInputChannel;
-
+    InputConsumer.Callback mInputConsumerCallback;
+    InputConsumer mInputConsumer;
+    
     final Rect mTempRect; // used in the transaction to not thrash the heap.
     final Rect mVisRect; // used to retrieve visible rect of focused view.
 
@@ -555,8 +557,17 @@
                 }
 
                 if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                            Looper.myQueue());
+                    if (view instanceof RootViewSurfaceTaker) {
+                        mInputConsumerCallback =
+                            ((RootViewSurfaceTaker)view).willYouTakeTheInputConsumer();
+                    }
+                    if (mInputConsumerCallback != null) {
+                        mInputConsumer = new InputConsumer(mInputChannel);
+                        mInputConsumerCallback.onInputConsumerCreated(mInputConsumer);
+                    } else {
+                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                                Looper.myQueue());
+                    }
                 }
                 
                 view.assignParent(this);
@@ -1736,7 +1747,12 @@
 
         if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
             if (mInputChannel != null) {
-                InputQueue.unregisterInputChannel(mInputChannel);
+                if (mInputConsumerCallback != null) {
+                    mInputConsumerCallback.onInputConsumerDestroyed(mInputConsumer);
+                    mInputConsumerCallback = null;
+                } else {
+                    InputQueue.unregisterInputChannel(mInputChannel);
+                }
                 mInputChannel.dispose();
                 mInputChannel = null;
             }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 234deba..b00d33d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -481,6 +481,13 @@
     public abstract void takeSurface(SurfaceHolder.Callback callback);
     
     /**
+     * Take ownership of this window's InputChannel.  The window will no
+     * longer read and dispatch input events from the channel; it is your
+     * responsibility to do so.
+     */
+    public abstract void takeInputChannel(InputConsumer.Callback callback);
+    
+    /**
      * Return whether this window is being displayed with a floating style
      * (based on the {@link android.R.attr#windowIsFloating} attribute in
      * the style/theme).
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index fcb1645..991266a 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -1,5 +1,6 @@
 package com.android.internal.view;
 
+import android.view.InputConsumer;
 import android.view.SurfaceHolder;
 
 /** hahahah */
@@ -8,4 +9,5 @@
     void setSurfaceType(int type);
     void setSurfaceFormat(int format);
     void setSurfaceKeepScreenOn(boolean keepOn);
+    InputConsumer.Callback willYouTakeTheInputConsumer();
 }
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index f2ab134..5e5e47e 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -18,8 +18,10 @@
 #include <utils/Log.h>
 
 #include "JNIHelp.h"
+#include "android_view_InputChannel.h"
 #include <android_runtime/AndroidRuntime.h>
 #include <android/native_activity.h>
+#include <ui/InputTransport.h>
 
 #include <dlfcn.h>
 
@@ -33,9 +35,13 @@
         dlhandle = _dlhandle;
         createActivityFunc = _createFunc;
         surface = NULL;
+        inputChannel = NULL;
+        nativeInputQueue = NULL;
     }
     
     ~NativeCode() {
+        setSurface(NULL);
+        setInputChannel(NULL);
         if (callbacks.onDestroy != NULL) {
             callbacks.onDestroy(&activity);
         }
@@ -55,6 +61,31 @@
         }
     }
     
+    status_t setInputChannel(jobject _channel) {
+        if (inputChannel != NULL) {
+            delete nativeInputQueue;
+            activity.env->DeleteGlobalRef(inputChannel);
+        }
+        inputChannel = NULL;
+        nativeInputQueue = NULL;
+        if (_channel != NULL) {
+            inputChannel = activity.env->NewGlobalRef(_channel);
+            sp<InputChannel> ic =
+                    android_view_InputChannel_getInputChannel(activity.env, _channel);
+            if (ic != NULL) {
+                nativeInputQueue = new input_queue_t(ic);
+                if (nativeInputQueue->getConsumer().initialize() != android::OK) {
+                    delete nativeInputQueue;
+                    nativeInputQueue = NULL;
+                    return UNKNOWN_ERROR;
+                }
+            } else {
+                return UNKNOWN_ERROR;
+            }
+        }
+        return OK;
+    }
+    
     android_activity_t activity;
     android_activity_callbacks_t callbacks;
     
@@ -62,6 +93,8 @@
     android_activity_create_t* createActivityFunc;
     
     jobject surface;
+    jobject inputChannel;
+    struct input_queue_t* nativeInputQueue;
 };
 
 static jint
@@ -217,6 +250,38 @@
     }
 }
 
+static void
+onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
+{
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        status_t err = code->setInputChannel(channel);
+        if (err != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                    "Error setting input channel");
+            return;
+        }
+        if (code->callbacks.onInputQueueCreated != NULL) {
+            code->callbacks.onInputQueueCreated(&code->activity,
+                    code->nativeInputQueue);
+        }
+    }
+}
+
+static void
+onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
+{
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->nativeInputQueue != NULL
+                && code->callbacks.onInputQueueDestroyed != NULL) {
+            code->callbacks.onInputQueueDestroyed(&code->activity,
+                    code->nativeInputQueue);
+        }
+        code->setInputChannel(NULL);
+    }
+}
+
 static const JNINativeMethod g_methods[] = {
     { "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native },
     { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native },
@@ -230,6 +295,8 @@
     { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native },
     { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native },
     { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native },
+    { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
+    { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
 };
 
 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
@@ -248,4 +315,4 @@
         g_methods, NELEM(g_methods));
 }
 
-}
+} // namespace android
diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h
index ac1defb..fa2d282 100644
--- a/core/jni/android_view_InputChannel.h
+++ b/core/jni/android_view_InputChannel.h
@@ -19,9 +19,9 @@
 
 #include "jni.h"
 
-namespace android {
+#include <ui/InputTransport.h>
 
-class InputChannel;
+namespace android {
 
 typedef void (*InputChannelObjDisposeCallback)(JNIEnv* env, jobject inputChannelObj,
         const sp<InputChannel>& inputChannel, void* data);
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 979d6e8..32f85b3 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -40,6 +40,11 @@
  */
 #define MAX_POINTERS 10
 
+/*
+ * Declare a concrete type for the NDK's input event forward declaration.
+ */
+struct input_event_t { };
+
 namespace android {
 
 /*
@@ -128,8 +133,6 @@
 /*
  * Input events.
  */
-struct input_event_t { };
-
 class InputEvent : public input_event_t {
 public:
     virtual ~InputEvent() { }
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 7b182f3..d6bded6 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -330,4 +330,24 @@
 
 } // namespace android
 
+/*
+ * NDK input queue API.
+ */
+struct input_queue_t {
+public:
+    /* Creates a consumer associated with an input channel. */
+    explicit input_queue_t(const android::sp<android::InputChannel>& channel);
+
+    /* Destroys the consumer and releases its input channel. */
+    ~input_queue_t();
+
+    inline android::InputConsumer& getConsumer() { return mConsumer; }
+    
+    android::status_t consume(android::InputEvent** event);
+    
+private:
+    android::InputConsumer mConsumer;
+    android::PreallocatedInputEventFactory mInputEventFactory;
+};
+
 #endif // _UI_INPUT_TRANSPORT_H
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0e6f2f5..4121b5a 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -88,166 +88,3 @@
 }
 
 } // namespace android
-
-// NDK APIs
-
-using android::InputEvent;
-using android::KeyEvent;
-using android::MotionEvent;
-
-int32_t input_event_get_type(const input_event_t* event) {
-    return reinterpret_cast<const InputEvent*>(event)->getType();
-}
-
-int32_t input_event_get_device_id(const input_event_t* event) {
-    return reinterpret_cast<const InputEvent*>(event)->getDeviceId();
-}
-
-int32_t input_event_get_nature(const input_event_t* event) {
-    return reinterpret_cast<const InputEvent*>(event)->getNature();
-}
-
-int32_t key_event_get_action(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getAction();
-}
-
-int32_t key_event_get_flags(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getFlags();
-}
-
-int32_t key_event_get_key_code(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getKeyCode();
-}
-
-int32_t key_event_get_scan_code(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getScanCode();
-}
-
-int32_t key_event_get_meta_state(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getMetaState();
-}
-int32_t key_event_get_repeat_count(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getRepeatCount();
-}
-
-int64_t key_event_get_down_time(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getDownTime();
-}
-
-int64_t key_event_get_event_time(const input_event_t* key_event) {
-    return reinterpret_cast<const KeyEvent*>(key_event)->getEventTime();
-}
-
-int32_t motion_event_get_action(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getAction();
-}
-
-int32_t motion_event_get_meta_state(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getMetaState();
-}
-
-int32_t motion_event_get_edge_flags(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getEdgeFlags();
-}
-
-int64_t motion_event_get_down_time(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getDownTime();
-}
-
-int64_t motion_event_get_event_time(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getEventTime();
-}
-
-float motion_event_get_x_offset(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getXOffset();
-}
-
-float motion_event_get_y_offset(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getYOffset();
-}
-
-float motion_event_get_x_precision(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getXPrecision();
-}
-
-float motion_event_get_y_precision(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getYPrecision();
-}
-
-size_t motion_event_get_pointer_count(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getPointerCount();
-}
-
-int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index);
-}
-
-float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
-}
-
-float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getRawY(pointer_index);
-}
-
-float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getX(pointer_index);
-}
-
-float motion_event_get_y(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getY(pointer_index);
-}
-
-float motion_event_get_pressure(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getPressure(pointer_index);
-}
-
-float motion_event_get_size(const input_event_t* motion_event, size_t pointer_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getSize(pointer_index);
-}
-
-size_t motion_event_get_history_size(const input_event_t* motion_event) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistorySize();
-}
-
-int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalEventTime(
-            history_index);
-}
-
-float motion_event_get_historical_raw_x(input_event_t* motion_event, size_t pointer_index,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalRawX(
-            pointer_index, history_index);
-}
-
-float motion_event_get_historical_raw_y(input_event_t* motion_event, size_t pointer_index,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalRawY(
-            pointer_index, history_index);
-}
-
-float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalX(
-            pointer_index, history_index);
-}
-
-float motion_event_get_historical_y(input_event_t* motion_event, size_t pointer_index,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalY(
-            pointer_index, history_index);
-}
-
-float motion_event_get_historical_pressure(input_event_t* motion_event, size_t pointer_index,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalPressure(
-            pointer_index, history_index);
-}
-
-float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
-        size_t history_index) {
-    return reinterpret_cast<const MotionEvent*>(motion_event)->getHistoricalSize(
-            pointer_index, history_index);
-}
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 86bbd37..b2842d0 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -686,3 +686,22 @@
 }
 
 } // namespace android
+
+// --- input_queue_t ---
+
+using android::InputEvent;
+using android::InputChannel;
+using android::InputConsumer;
+using android::sp;
+using android::status_t;
+
+input_queue_t::input_queue_t(const sp<InputChannel>& channel) :
+        mConsumer(channel) {
+}
+
+input_queue_t::~input_queue_t() {
+}
+
+status_t input_queue_t::consume(InputEvent** event) {
+    return mConsumer.consume(&mInputEventFactory, event);
+}
diff --git a/native/android/Android.mk b/native/android/Android.mk
new file mode 100644
index 0000000..8c621b6
--- /dev/null
+++ b/native/android/Android.mk
@@ -0,0 +1,26 @@
+BASE_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# our source files
+#
+LOCAL_SRC_FILES:= \
+    activity.cpp \
+    input.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libandroid_runtime \
+    libcutils \
+    libutils \
+    libbinder \
+    libui
+
+LOCAL_C_INCLUDES += \
+    frameworks/base/native/include \
+    frameworks/base/core/jni/android \
+    dalvik/libnativehelper/include/nativehelper
+
+LOCAL_MODULE:= libandroid
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/native/android/activity.cpp b/native/android/activity.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/native/android/activity.cpp
diff --git a/native/android/input.cpp b/native/android/input.cpp
new file mode 100644
index 0000000..38d8567
--- /dev/null
+++ b/native/android/input.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "input"
+#include <utils/Log.h>
+
+#include <android/input.h>
+#include <ui/Input.h>
+#include <ui/InputTransport.h>
+
+#include <poll.h>
+
+using android::InputEvent;
+using android::KeyEvent;
+using android::MotionEvent;
+
+int32_t input_event_get_type(const input_event_t* event) {
+    return static_cast<const InputEvent*>(event)->getType();
+}
+
+int32_t input_event_get_device_id(const input_event_t* event) {
+    return static_cast<const InputEvent*>(event)->getDeviceId();
+}
+
+int32_t input_event_get_nature(const input_event_t* event) {
+    return static_cast<const InputEvent*>(event)->getNature();
+}
+
+int32_t key_event_get_action(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getAction();
+}
+
+int32_t key_event_get_flags(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getFlags();
+}
+
+int32_t key_event_get_key_code(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getKeyCode();
+}
+
+int32_t key_event_get_scan_code(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getScanCode();
+}
+
+int32_t key_event_get_meta_state(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getMetaState();
+}
+int32_t key_event_get_repeat_count(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getRepeatCount();
+}
+
+int64_t key_event_get_down_time(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getDownTime();
+}
+
+int64_t key_event_get_event_time(const input_event_t* key_event) {
+    return static_cast<const KeyEvent*>(key_event)->getEventTime();
+}
+
+int32_t motion_event_get_action(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getAction();
+}
+
+int32_t motion_event_get_meta_state(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getMetaState();
+}
+
+int32_t motion_event_get_edge_flags(const input_event_t* motion_event) {
+    return reinterpret_cast<const MotionEvent*>(motion_event)->getEdgeFlags();
+}
+
+int64_t motion_event_get_down_time(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getDownTime();
+}
+
+int64_t motion_event_get_event_time(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getEventTime();
+}
+
+float motion_event_get_x_offset(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getXOffset();
+}
+
+float motion_event_get_y_offset(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getYOffset();
+}
+
+float motion_event_get_x_precision(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getXPrecision();
+}
+
+float motion_event_get_y_precision(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getYPrecision();
+}
+
+size_t motion_event_get_pointer_count(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getPointerCount();
+}
+
+int32_t motion_event_get_pointer_id(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getPointerId(pointer_index);
+}
+
+float motion_event_get_raw_x(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getRawX(pointer_index);
+}
+
+float motion_event_get_raw_y(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getRawY(pointer_index);
+}
+
+float motion_event_get_x(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getX(pointer_index);
+}
+
+float motion_event_get_y(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getY(pointer_index);
+}
+
+float motion_event_get_pressure(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getPressure(pointer_index);
+}
+
+float motion_event_get_size(const input_event_t* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getSize(pointer_index);
+}
+
+size_t motion_event_get_history_size(const input_event_t* motion_event) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistorySize();
+}
+
+int64_t motion_event_get_historical_event_time(input_event_t* motion_event,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalEventTime(
+            history_index);
+}
+
+float motion_event_get_historical_raw_x(input_event_t* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalRawX(
+            pointer_index, history_index);
+}
+
+float motion_event_get_historical_raw_y(input_event_t* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalRawY(
+            pointer_index, history_index);
+}
+
+float motion_event_get_historical_x(input_event_t* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalX(
+            pointer_index, history_index);
+}
+
+float motion_event_get_historical_y(input_event_t* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalY(
+            pointer_index, history_index);
+}
+
+float motion_event_get_historical_pressure(input_event_t* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalPressure(
+            pointer_index, history_index);
+}
+
+float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalSize(
+            pointer_index, history_index);
+}
+
+int input_queue_get_fd(input_queue_t* queue) {
+    return queue->getConsumer().getChannel()->getReceivePipeFd();
+}
+
+int input_queue_has_events(input_queue_t* queue) {
+    struct pollfd pfd;
+    
+    pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd();
+    pfd.events = POLLIN;
+    pfd.revents = 0;
+    
+    int nfd = poll(&pfd, 1, 0);
+    if (nfd <= 0) return nfd;
+    return pfd.revents == POLLIN ? 1 : -1;
+}
+
+int32_t input_queue_get_event(input_queue_t* queue, input_event_t** outEvent) {
+    *outEvent = NULL;
+    
+    int32_t res = queue->getConsumer().receiveDispatchSignal();
+    if (res != android::OK) {
+        LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
+                queue->getConsumer().getChannel()->getName().string(), res);
+        return -1;
+    }
+    
+    InputEvent* myEvent = NULL;
+    res = queue->consume(&myEvent);
+    if (res != android::OK) {
+        LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
+                queue->getConsumer().getChannel()->getName().string(), res);
+        queue->getConsumer().sendFinishedSignal();
+        return -1;
+    }
+    
+    *outEvent = myEvent;
+    return 0;
+}
+
+void input_queue_finish_event(input_queue_t* queue, input_event_t* event,
+        int handled) {
+    int32_t res = queue->getConsumer().sendFinishedSignal();
+    if (res != android::OK) {
+        LOGW("Failed to send finished signal on channel '%s'.  status=%d",
+                queue->getConsumer().getChannel()->getName().string(), res);
+    }
+}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 193cbf3cb..2441af0 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -523,6 +523,42 @@
 float motion_event_get_historical_size(input_event_t* motion_event, size_t pointer_index,
         size_t history_index);
 
+/*
+ * Input queue
+ *
+ * An input queue is the facility through which you retrieve input
+ * events.
+ */
+struct input_queue_t;
+typedef struct input_queue_t input_queue_t;
+
+/*
+ * Return a file descriptor for the queue, which you
+ * can use to determine if there are events available.  This
+ * is typically used with select() or poll() to multiplex
+ * with other kinds of events.
+ */
+int input_queue_get_fd(input_queue_t* queue);
+
+/*
+ * Returns true if there are one or more events available in the
+ * input queue.  Returns 1 if the queue has events; 0 if
+ * it does not have events; and a negative value if there is an error.
+ */
+int input_queue_has_events(input_queue_t* queue);
+
+/*
+ * Returns the next available event from the queue.  Returns a negative
+ * value if no events are available or an error has occurred.
+ */
+int32_t input_queue_get_event(input_queue_t* queue, input_event_t** outEvent);
+
+/*
+ * Report that dispatching has finished with the given event.
+ * This must be called after receiving an event with input_queue_get_event().
+ */
+void input_queue_finish_event(input_queue_t* queue, input_event_t* event, int handled);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index 328a4b5..a58a7d2 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -23,6 +23,8 @@
 
 #include <jni.h>
 
+#include <android/input.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -144,6 +146,19 @@
      * returning from here.
      */
     void (*onSurfaceDestroyed)(android_activity_t* activity, android_surface_t* surface);
+    
+    /**
+     * The input queue for this native activity's window has been created.
+     * You can use the given input queue to start retrieving input events.
+     */
+    void (*onInputQueueCreated)(android_activity_t* activity, input_queue_t* queue);
+    
+    /**
+     * The input queue for this native activity's window is being destroyed.
+     * You should no longer try to reference this object upon returning from this
+     * function.
+     */
+    void (*onInputQueueDestroyed)(android_activity_t* activity, input_queue_t* queue);
 
     /**
      * The system is running low on memory.  Use this callback to release
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 0cb0efc..7877611 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -56,6 +56,7 @@
 import android.util.SparseArray;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
+import android.view.InputConsumer;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -70,6 +71,7 @@
 import android.view.VolumePanel;
 import android.view.Window;
 import android.view.WindowManager;
+import android.view.InputConsumer.Callback;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
@@ -108,6 +110,8 @@
     SurfaceHolder.Callback mTakeSurfaceCallback;
     BaseSurfaceHolder mSurfaceHolder;
     
+    InputConsumer.Callback mTakeInputChannelCallback;
+    
     private boolean mIsFloating;
 
     private LayoutInflater mLayoutInflater;
@@ -251,6 +255,10 @@
         mTakeSurfaceCallback = callback;
     }
     
+    public void takeInputChannel(InputConsumer.Callback callback) {
+        mTakeInputChannelCallback = callback;
+    }
+    
     @Override
     public boolean isFloating() {
         return mIsFloating;
@@ -2037,6 +2045,10 @@
             return mFeatureId < 0 ? mTakeSurfaceCallback : null;
         }
         
+        public InputConsumer.Callback willYouTakeTheInputConsumer() {
+            return mFeatureId < 0 ? mTakeInputChannelCallback : null;
+        }
+        
         public void setSurfaceType(int type) {
             PhoneWindow.this.setType(type);
         }