Merge "Fix swap of sessionId and output in audio effect API." into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 5d71cad..7a86d05 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4717,6 +4717,17 @@
  visibility="public"
 >
 </field>
+<field name="immersive"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="inAnimation"
  type="int"
  transient="false"
@@ -5916,17 +5927,6 @@
  visibility="public"
 >
 </field>
-<field name="kraken_resource_pad64"
- type="int"
- transient="false"
- volatile="false"
- value="16843457"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="kraken_resource_pad7"
  type="int"
  transient="false"
@@ -154519,6 +154519,21 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<method name="setPackageObbPath"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
 </class>
 <class name="MockResources"
  extends="android.content.res.Resources"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fc9bcf7..63bbf9c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2657,6 +2657,15 @@
             return PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         }
 
+        @Override
+        public void setPackageObbPath(String packageName, String path) {
+            try {
+                mPM.setPackageObbPath(packageName, path);
+            } catch (RemoteException e) {
+                // Should never happen!
+            }
+        }
+
         private final ContextImpl mContext;
         private final IPackageManager mPM;
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9939478..160a481 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -319,4 +319,6 @@
 
     boolean setInstallLocation(int loc);
     int getInstallLocation();
+
+    void setPackageObbPath(String packageName, String path);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a5b419..15a446b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2193,4 +2193,17 @@
      */
     public abstract void movePackage(
             String packageName, IPackageMoveObserver observer, int flags);
+
+    /**
+     * Sets the Opaque Binary Blob (OBB) file location.
+     * <p>
+     * NOTE: The existence or format of this file is not currently checked, but
+     * it may be in the future.
+     * 
+     * @param packageName Name of the package with which to associate the .obb
+     *            file
+     * @param path Path on the filesystem to the .obb file
+     * @hide
+     */
+    public abstract void setPackageObbPath(String packageName, String path);
 }
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 0a2899f..1100886 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -535,6 +535,7 @@
      * application does not need a particular callback, a null can be passed
      * instead of a callback method.
      *
+     * This method is only valid after {@link #startPreview()} has been called.
      * This method will stop the preview. Applications should not call {@link
      * #stopPreview()} before this. After jpeg callback is received,
      * applications can call {@link #startPreview()} to restart the preview.
@@ -562,6 +563,7 @@
      * application does not need a particular callback, a null can be passed
      * instead of a callback method.
      *
+     * This method is only valid after {@link #startPreview()} has been called.
      * This method will stop the preview. Applications should not call {@link
      * #stopPreview()} before this. After jpeg callback is received,
      * applications can call {@link #startPreview()} to restart the preview.
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 249ad62..6f12f19 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -216,20 +216,7 @@
             @Override
             public void handleTouch(MotionEvent event, Runnable finishedCallback) {
                 try {
-                    synchronized (mLock) {
-                        if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                            if (mPendingMove != null) {
-                                mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                                mPendingMove.recycle();
-                            }
-                            mPendingMove = event;
-                        } else {
-                            mPendingMove = null;
-                        }
-                        Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
-                                event);
-                        mCaller.sendMessage(msg);
-                    }
+                    dispatchPointer(event);
                 } finally {
                     finishedCallback.run();
                 }
@@ -238,26 +225,6 @@
         
         final BaseIWindow mWindow = new BaseIWindow() {
             @Override
-            public boolean onDispatchPointer(MotionEvent event, long eventTime,
-                    boolean callWhenDone) {
-                synchronized (mLock) {
-                    if (event.getAction() == MotionEvent.ACTION_MOVE) {
-                        if (mPendingMove != null) {
-                            mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
-                            mPendingMove.recycle();
-                        }
-                        mPendingMove = event;
-                    } else {
-                        mPendingMove = null;
-                    }
-                    Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT,
-                            event);
-                    mCaller.sendMessage(msg);
-                }
-                return false;
-            }
-            
-            @Override
             public void resized(int w, int h, Rect coveredInsets,
                     Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
                 Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED,
@@ -466,6 +433,22 @@
          */
         public void onSurfaceDestroyed(SurfaceHolder holder) {
         }
+        
+        private void dispatchPointer(MotionEvent event) {
+            synchronized (mLock) {
+                if (event.getAction() == MotionEvent.ACTION_MOVE) {
+                    if (mPendingMove != null) {
+                        mCaller.removeMessages(MSG_TOUCH_EVENT, mPendingMove);
+                        mPendingMove.recycle();
+                    }
+                    mPendingMove = event;
+                } else {
+                    mPendingMove = null;
+                }
+                Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event);
+                mCaller.sendMessage(msg);
+            }
+        }
 
         void updateSurface(boolean forceRelayout, boolean forceReport) {
             if (mDestroyed) {
@@ -523,10 +506,8 @@
                                 mInputChannel);
                         mCreated = true;
 
-                        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                            InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                                    Looper.myQueue());
-                        }
+                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                                Looper.myQueue());
                     }
                     
                     mSurfaceHolder.mSurfaceLock.lock();
@@ -770,10 +751,8 @@
                     if (DEBUG) Log.v(TAG, "Removing window and destroying surface "
                             + mSurfaceHolder.getSurface() + " of: " + this);
                     
-                    if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                        if (mInputChannel != null) {
-                            InputQueue.unregisterInputChannel(mInputChannel);
-                        }
+                    if (mInputChannel != null) {
+                        InputQueue.unregisterInputChannel(mInputChannel);
                     }
                     
                     mSession.remove(mWindow);
@@ -782,13 +761,11 @@
                 mSurfaceHolder.mSurface.release();
                 mCreated = false;
                 
-                if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    // Dispose the input channel after removing the window so the Window Manager
-                    // doesn't interpret the input channel being closed as an abnormal termination.
-                    if (mInputChannel != null) {
-                        mInputChannel.dispose();
-                        mInputChannel = null;
-                    }
+                // Dispose the input channel after removing the window so the Window Manager
+                // doesn't interpret the input channel being closed as an abnormal termination.
+                if (mInputChannel != null) {
+                    mInputChannel.dispose();
+                    mInputChannel = null;
                 }
             }
         }
@@ -841,7 +818,7 @@
 
         public void dispatchPointer(MotionEvent event) {
             if (mEngine != null) {
-                mEngine.mWindow.onDispatchPointer(event, event.getEventTime(), false);
+                mEngine.dispatchPointer(event);
             }
         }
         
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3b09808..921018a 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -46,9 +46,6 @@
 
     void resized(int w, int h, in Rect coveredInsets, in Rect visibleInsets,
             boolean reportDraw, in Configuration newConfig);
-    void dispatchKey(in KeyEvent event);
-    void dispatchPointer(in MotionEvent event, long eventTime, boolean callWhenDone);
-    void dispatchTrackball(in MotionEvent event, long eventTime, boolean callWhenDone);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
 
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 4647fb4..7f10b76 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -109,10 +109,6 @@
     void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
     
     void finishDrawing(IWindow window);
-
-    void finishKey(IWindow window);
-    MotionEvent getPendingPointerMove(IWindow window);
-    MotionEvent getPendingTrackballMove(IWindow window);
     
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
diff --git a/core/java/android/view/RawInputEvent.java b/core/java/android/view/RawInputEvent.java
deleted file mode 100644
index 3bbfea8..0000000
--- a/core/java/android/view/RawInputEvent.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-/**
- * @hide
- * This really belongs in services.jar; WindowManagerPolicy should go there too.
- */
-public class RawInputEvent {
-    // Event class as defined by EventHub.
-    public static final int CLASS_KEYBOARD = 0x00000001;
-    public static final int CLASS_ALPHAKEY = 0x00000002;
-    public static final int CLASS_TOUCHSCREEN = 0x00000004;
-    public static final int CLASS_TRACKBALL = 0x00000008;
-    public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;
-    public static final int CLASS_DPAD = 0x00000020;
-    
-    // More special classes for QueuedEvent below.
-    public static final int CLASS_CONFIGURATION_CHANGED = 0x10000000;
-    
-    // Event types.
-
-    public static final int EV_SYN = 0x00;
-    public static final int EV_KEY = 0x01;
-    public static final int EV_REL = 0x02;
-    public static final int EV_ABS = 0x03;
-    public static final int EV_MSC = 0x04;
-    public static final int EV_SW = 0x05;
-    public static final int EV_LED = 0x11;
-    public static final int EV_SND = 0x12;
-    public static final int EV_REP = 0x14;
-    public static final int EV_FF = 0x15;
-    public static final int EV_PWR = 0x16;
-    public static final int EV_FF_STATUS = 0x17;
-
-    // Platform-specific event types.
-    
-    public static final int EV_DEVICE_ADDED = 0x10000000;
-    public static final int EV_DEVICE_REMOVED = 0x20000000;
-    
-    // Special key (EV_KEY) scan codes for pointer buttons.
-
-    public static final int BTN_FIRST = 0x100;
-
-    public static final int BTN_MISC = 0x100;
-    public static final int BTN_0 = 0x100;
-    public static final int BTN_1 = 0x101;
-    public static final int BTN_2 = 0x102;
-    public static final int BTN_3 = 0x103;
-    public static final int BTN_4 = 0x104;
-    public static final int BTN_5 = 0x105;
-    public static final int BTN_6 = 0x106;
-    public static final int BTN_7 = 0x107;
-    public static final int BTN_8 = 0x108;
-    public static final int BTN_9 = 0x109;
-
-    public static final int BTN_MOUSE = 0x110;
-    public static final int BTN_LEFT = 0x110;
-    public static final int BTN_RIGHT = 0x111;
-    public static final int BTN_MIDDLE = 0x112;
-    public static final int BTN_SIDE = 0x113;
-    public static final int BTN_EXTRA = 0x114;
-    public static final int BTN_FORWARD = 0x115;
-    public static final int BTN_BACK = 0x116;
-    public static final int BTN_TASK = 0x117;
-
-    public static final int BTN_JOYSTICK = 0x120;
-    public static final int BTN_TRIGGER = 0x120;
-    public static final int BTN_THUMB = 0x121;
-    public static final int BTN_THUMB2 = 0x122;
-    public static final int BTN_TOP = 0x123;
-    public static final int BTN_TOP2 = 0x124;
-    public static final int BTN_PINKIE = 0x125;
-    public static final int BTN_BASE = 0x126;
-    public static final int BTN_BASE2 = 0x127;
-    public static final int BTN_BASE3 = 0x128;
-    public static final int BTN_BASE4 = 0x129;
-    public static final int BTN_BASE5 = 0x12a;
-    public static final int BTN_BASE6 = 0x12b;
-    public static final int BTN_DEAD = 0x12f;
-
-    public static final int BTN_GAMEPAD = 0x130;
-    public static final int BTN_A = 0x130;
-    public static final int BTN_B = 0x131;
-    public static final int BTN_C = 0x132;
-    public static final int BTN_X = 0x133;
-    public static final int BTN_Y = 0x134;
-    public static final int BTN_Z = 0x135;
-    public static final int BTN_TL = 0x136;
-    public static final int BTN_TR = 0x137;
-    public static final int BTN_TL2 = 0x138;
-    public static final int BTN_TR2 = 0x139;
-    public static final int BTN_SELECT = 0x13a;
-    public static final int BTN_START = 0x13b;
-    public static final int BTN_MODE = 0x13c;
-    public static final int BTN_THUMBL = 0x13d;
-    public static final int BTN_THUMBR = 0x13e;
-
-    public static final int BTN_DIGI = 0x140;
-    public static final int BTN_TOOL_PEN = 0x140;
-    public static final int BTN_TOOL_RUBBER = 0x141;
-    public static final int BTN_TOOL_BRUSH = 0x142;
-    public static final int BTN_TOOL_PENCIL = 0x143;
-    public static final int BTN_TOOL_AIRBRUSH = 0x144;
-    public static final int BTN_TOOL_FINGER = 0x145;
-    public static final int BTN_TOOL_MOUSE = 0x146;
-    public static final int BTN_TOOL_LENS = 0x147;
-    public static final int BTN_TOUCH = 0x14a;
-    public static final int BTN_STYLUS = 0x14b;
-    public static final int BTN_STYLUS2 = 0x14c;
-    public static final int BTN_TOOL_DOUBLETAP = 0x14d;
-    public static final int BTN_TOOL_TRIPLETAP = 0x14e;
-
-    public static final int BTN_WHEEL = 0x150;
-    public static final int BTN_GEAR_DOWN = 0x150;
-    public static final int BTN_GEAR_UP = 0x151;
-
-    public static final int BTN_LAST = 0x15f;
-
-    // Relative axes (EV_REL) scan codes.
-
-    public static final int REL_X = 0x00;
-    public static final int REL_Y = 0x01;
-    public static final int REL_Z = 0x02;
-    public static final int REL_RX = 0x03;
-    public static final int REL_RY = 0x04;
-    public static final int REL_RZ = 0x05;
-    public static final int REL_HWHEEL = 0x06;
-    public static final int REL_DIAL = 0x07;
-    public static final int REL_WHEEL = 0x08;
-    public static final int REL_MISC = 0x09;
-    public static final int REL_MAX = 0x0f;
-
-    // Absolute axes (EV_ABS) scan codes.
-
-    public static final int ABS_X = 0x00;
-    public static final int ABS_Y = 0x01;
-    public static final int ABS_Z = 0x02;
-    public static final int ABS_RX = 0x03;
-    public static final int ABS_RY = 0x04;
-    public static final int ABS_RZ = 0x05;
-    public static final int ABS_THROTTLE = 0x06;
-    public static final int ABS_RUDDER = 0x07;
-    public static final int ABS_WHEEL = 0x08;
-    public static final int ABS_GAS = 0x09;
-    public static final int ABS_BRAKE = 0x0a;
-    public static final int ABS_HAT0X = 0x10;
-    public static final int ABS_HAT0Y = 0x11;
-    public static final int ABS_HAT1X = 0x12;
-    public static final int ABS_HAT1Y = 0x13;
-    public static final int ABS_HAT2X = 0x14;
-    public static final int ABS_HAT2Y = 0x15;
-    public static final int ABS_HAT3X = 0x16;
-    public static final int ABS_HAT3Y = 0x17;
-    public static final int ABS_PRESSURE = 0x18;
-    public static final int ABS_DISTANCE = 0x19;
-    public static final int ABS_TILT_X = 0x1a;
-    public static final int ABS_TILT_Y = 0x1b;
-    public static final int ABS_TOOL_WIDTH = 0x1c;
-    public static final int ABS_VOLUME = 0x20;
-    public static final int ABS_MISC = 0x28;
-    public static final int ABS_MT_TOUCH_MAJOR = 0x30;
-    public static final int ABS_MT_TOUCH_MINOR = 0x31;
-    public static final int ABS_MT_WIDTH_MAJOR = 0x32;
-    public static final int ABS_MT_WIDTH_MINOR = 0x33;
-    public static final int ABS_MT_ORIENTATION = 0x34;
-    public static final int ABS_MT_POSITION_X = 0x35;
-    public static final int ABS_MT_POSITION_Y = 0x36;
-    public static final int ABS_MT_TOOL_TYPE = 0x37;
-    public static final int ABS_MT_BLOB_ID = 0x38;
-    public static final int ABS_MAX = 0x3f;
-
-    // Switch events
-    public static final int SW_LID = 0x00;
-
-    public static final int SYN_REPORT = 0;
-    public static final int SYN_CONFIG = 1;
-    public static final int SYN_MT_REPORT = 2;
-    
-    public int deviceId;
-    public int type;
-    public int scancode;
-    public int keycode;
-    public int flags;
-    public int value;
-    public long when;
-}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d1a0f75..e4d1ae1 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -625,41 +625,6 @@
             }
         }
 
-        public void dispatchKey(KeyEvent event) {
-            SurfaceView surfaceView = mSurfaceView.get();
-            if (surfaceView != null) {
-                //Log.w("SurfaceView", "Unexpected key event in surface: " + event);
-                if (surfaceView.mSession != null && surfaceView.mSurface != null) {
-                    try {
-                        surfaceView.mSession.finishKey(surfaceView.mWindow);
-                    } catch (RemoteException ex) {
-                    }
-                }
-            }
-        }
-
-        public void dispatchPointer(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            Log.w("SurfaceView", "Unexpected pointer event in surface: " + event);
-            //if (mSession != null && mSurface != null) {
-            //    try {
-            //        //mSession.finishKey(mWindow);
-            //    } catch (RemoteException ex) {
-            //    }
-            //}
-        }
-
-        public void dispatchTrackball(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            Log.w("SurfaceView", "Unexpected trackball event in surface: " + event);
-            //if (mSession != null && mSurface != null) {
-            //    try {
-            //        //mSession.finishKey(mWindow);
-            //    } catch (RemoteException ex) {
-            //    }
-            //}
-        }
-
         public void dispatchAppVisibility(boolean visible) {
             // The point of SurfaceView is to let the app control the surface.
         }
@@ -686,7 +651,6 @@
     private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
         
         private static final String LOG_TAG = "SurfaceHolder";
-        private int mSaveCount;
         
         public boolean isCreating() {
             return mIsCreating;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 1dc82e8..e980b17 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -556,18 +556,16 @@
                         "Unable to add window -- unknown error code " + res);
                 }
 
-                if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (view instanceof RootViewSurfaceTaker) {
-                        mInputQueueCallback =
-                            ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
-                    }
-                    if (mInputQueueCallback != null) {
-                        mInputQueue = new InputQueue(mInputChannel);
-                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
-                    } else {
-                        InputQueue.registerInputChannel(mInputChannel, mInputHandler,
-                                Looper.myQueue());
-                    }
+                if (view instanceof RootViewSurfaceTaker) {
+                    mInputQueueCallback =
+                        ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
+                }
+                if (mInputQueueCallback != null) {
+                    mInputQueue = new InputQueue(mInputChannel);
+                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
+                } else {
+                    InputQueue.registerInputChannel(mInputChannel, mInputHandler,
+                            Looper.myQueue());
                 }
                 
                 view.assignParent(this);
@@ -1745,16 +1743,12 @@
         }
         mSurface.release();
 
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            if (mInputChannel != null) {
-                if (mInputQueueCallback != null) {
-                    mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
-                    mInputQueueCallback = null;
-                } else {
-                    InputQueue.unregisterInputChannel(mInputChannel);
-                }
-                mInputChannel.dispose();
-                mInputChannel = null;
+        if (mInputChannel != null) {
+            if (mInputQueueCallback != null) {
+                mInputQueueCallback.onInputQueueDestroyed(mInputQueue);
+                mInputQueueCallback = null;
+            } else {
+                InputQueue.unregisterInputChannel(mInputChannel);
             }
         }
         
@@ -1763,13 +1757,11 @@
         } catch (RemoteException e) {
         }
         
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            // Dispose the input channel after removing the window so the Window Manager
-            // doesn't interpret the input channel being closed as an abnormal termination.
-            if (mInputChannel != null) {
-                mInputChannel.dispose();
-                mInputChannel = null;
-            }
+        // Dispose the input channel after removing the window so the Window Manager
+        // doesn't interpret the input channel being closed as an abnormal termination.
+        if (mInputChannel != null) {
+            mInputChannel.dispose();
+            mInputChannel = null;
         }
     }
 
@@ -1869,105 +1861,22 @@
             deliverKeyEvent((KeyEvent)msg.obj, true);
             break;
         case DISPATCH_POINTER: {
-            MotionEvent event = (MotionEvent)msg.obj;
-            boolean callWhenDone = msg.arg1 != 0;
-            
-            if (event == null) {
-                long timeBeforeGettingEvents;
-                if (MEASURE_LATENCY) {
-                    timeBeforeGettingEvents = System.nanoTime();
-                }
-
-                event = getPendingPointerMotionEvent();
-
-                if (MEASURE_LATENCY && event != null) {
-                    lt.sample("9 Client got events      ", System.nanoTime() - event.getEventTimeNano());
-                    lt.sample("8 Client getting events  ", timeBeforeGettingEvents - event.getEventTimeNano());
-                }
-                callWhenDone = false;
-            }
-            if (event != null && mTranslator != null) {
-                mTranslator.translateEventInScreenToAppWindow(event);
-            }
+            MotionEvent event = (MotionEvent) msg.obj;
             try {
-                boolean handled;
-                if (mView != null && mAdded && event != null) {
-
-                    // enter touch mode on the down
-                    boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
-                    if (isDown) {
-                        ensureTouchMode(true);
-                    }
-                    if(Config.LOGV) {
-                        captureMotionLog("captureDispatchPointer", event);
-                    }
-                    if (mCurScrollY != 0) {
-                        event.offsetLocation(0, mCurScrollY);
-                    }
-                    if (MEASURE_LATENCY) {
-                        lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
-                    }
-                    handled = mView.dispatchTouchEvent(event);
-                    if (MEASURE_LATENCY) {
-                        lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
-                    }
-                    if (!handled && isDown) {
-                        int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
-
-                        final int edgeFlags = event.getEdgeFlags();
-                        int direction = View.FOCUS_UP;
-                        int x = (int)event.getX();
-                        int y = (int)event.getY();
-                        final int[] deltas = new int[2];
-
-                        if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
-                            direction = View.FOCUS_DOWN;
-                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                                deltas[0] = edgeSlop;
-                                x += edgeSlop;
-                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                                deltas[0] = -edgeSlop;
-                                x -= edgeSlop;
-                            }
-                        } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
-                            direction = View.FOCUS_UP;
-                            if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                                deltas[0] = edgeSlop;
-                                x += edgeSlop;
-                            } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                                deltas[0] = -edgeSlop;
-                                x -= edgeSlop;
-                            }
-                        } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
-                            direction = View.FOCUS_RIGHT;
-                        } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
-                            direction = View.FOCUS_LEFT;
-                        }
-
-                        if (edgeFlags != 0 && mView instanceof ViewGroup) {
-                            View nearest = FocusFinder.getInstance().findNearestTouchable(
-                                    ((ViewGroup) mView), x, y, direction, deltas);
-                            if (nearest != null) {
-                                event.offsetLocation(deltas[0], deltas[1]);
-                                event.setEdgeFlags(0);
-                                mView.dispatchTouchEvent(event);
-                            }
-                        }
-                    }
-                }
+                deliverPointerEvent(event);
             } finally {
-                if (callWhenDone) {
-                    finishMotionEvent();
-                }
-                recycleMotionEvent(event);
+                event.recycle();
                 if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!");
-                // Let the exception fall through -- the looper will catch
-                // it and take care of the bad app for us.
             }
         } break;
-        case DISPATCH_TRACKBALL:
-            deliverTrackballEvent((MotionEvent)msg.obj, msg.arg1 != 0);
-            break;
+        case DISPATCH_TRACKBALL: {
+            MotionEvent event = (MotionEvent) msg.obj;
+            try {
+                deliverTrackballEvent(event);
+            } finally {
+                event.recycle();
+            }
+        } break;
         case DISPATCH_APP_VISIBILITY:
             handleAppVisibility(msg.arg1 != 0);
             break;
@@ -2101,61 +2010,12 @@
     }
     
     private void finishKeyEvent(KeyEvent event) {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            if (mFinishedCallback != null) {
-                mFinishedCallback.run();
-                mFinishedCallback = null;
-            }
-        } else {
-            try {
-                sWindowSession.finishKey(mWindow);
-            } catch (RemoteException e) {
-            }
+        if (mFinishedCallback != null) {
+            mFinishedCallback.run();
+            mFinishedCallback = null;
         }
     }
     
-    private void finishMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            sWindowSession.finishKey(mWindow);
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void recycleMotionEvent(MotionEvent event) {
-        if (event != null) {
-            event.recycle();
-        }
-    }
-    
-    private MotionEvent getPendingPointerMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            return sWindowSession.getPendingPointerMove(mWindow);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    private MotionEvent getPendingTrackballMotionEvent() {
-        if (WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH) {
-            throw new IllegalStateException("Should not be reachable with native input dispatch.");
-        }
-        
-        try {
-            return sWindowSession.getPendingTrackballMove(mWindow);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-    
-    
     /**
      * Something in the current window tells us we need to change the touch mode.  For
      * example, we are not in touch mode, and the user touches the screen.
@@ -2277,42 +2137,95 @@
         return false;
     }
 
-
-    private void deliverTrackballEvent(MotionEvent event, boolean callWhenDone) {
-        if (event == null) {
-            event = getPendingTrackballMotionEvent();
-            callWhenDone = false;
+    private void deliverPointerEvent(MotionEvent event) {
+        if (mTranslator != null) {
+            mTranslator.translateEventInScreenToAppWindow(event);
         }
+        
+        boolean handled;
+        if (mView != null && mAdded) {
 
+            // enter touch mode on the down
+            boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
+            if (isDown) {
+                ensureTouchMode(true);
+            }
+            if(Config.LOGV) {
+                captureMotionLog("captureDispatchPointer", event);
+            }
+            if (mCurScrollY != 0) {
+                event.offsetLocation(0, mCurScrollY);
+            }
+            if (MEASURE_LATENCY) {
+                lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano());
+            }
+            handled = mView.dispatchTouchEvent(event);
+            if (MEASURE_LATENCY) {
+                lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano());
+            }
+            if (!handled && isDown) {
+                int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
+
+                final int edgeFlags = event.getEdgeFlags();
+                int direction = View.FOCUS_UP;
+                int x = (int)event.getX();
+                int y = (int)event.getY();
+                final int[] deltas = new int[2];
+
+                if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
+                    direction = View.FOCUS_DOWN;
+                    if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                        deltas[0] = edgeSlop;
+                        x += edgeSlop;
+                    } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                        deltas[0] = -edgeSlop;
+                        x -= edgeSlop;
+                    }
+                } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
+                    direction = View.FOCUS_UP;
+                    if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                        deltas[0] = edgeSlop;
+                        x += edgeSlop;
+                    } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                        deltas[0] = -edgeSlop;
+                        x -= edgeSlop;
+                    }
+                } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
+                    direction = View.FOCUS_RIGHT;
+                } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
+                    direction = View.FOCUS_LEFT;
+                }
+
+                if (edgeFlags != 0 && mView instanceof ViewGroup) {
+                    View nearest = FocusFinder.getInstance().findNearestTouchable(
+                            ((ViewGroup) mView), x, y, direction, deltas);
+                    if (nearest != null) {
+                        event.offsetLocation(deltas[0], deltas[1]);
+                        event.setEdgeFlags(0);
+                        mView.dispatchTouchEvent(event);
+                    }
+                }
+            }
+        }
+    }
+
+    private void deliverTrackballEvent(MotionEvent event) {
         if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
 
         boolean handled = false;
-        try {
-            if (event == null) {
-                handled = true;
-            } else if (mView != null && mAdded) {
-                handled = mView.dispatchTrackballEvent(event);
-                if (!handled) {
-                    // we could do something here, like changing the focus
-                    // or something?
-                }
-            }
-        } finally {
+        if (mView != null && mAdded) {
+            handled = mView.dispatchTrackballEvent(event);
             if (handled) {
-                if (callWhenDone) {
-                    finishMotionEvent();
-                }
-                recycleMotionEvent(event);
                 // If we reach this, we delivered a trackball event to mView and
                 // mView consumed it. Because we will not translate the trackball
                 // event into a key event, touch mode will not exit, so we exit
                 // touch mode here.
                 ensureTouchMode(false);
-                //noinspection ReturnInsideFinallyBlock
                 return;
             }
-            // Let the exception fall through -- the looper will catch
-            // it and take care of the bad app for us.
+            
+            // Otherwise we could do something here, like changing the focus
+            // or something?
         }
 
         final TrackballAxis x = mTrackballAxisX;
@@ -2327,95 +2240,86 @@
             mLastTrackballTime = curTime;
         }
 
-        try {
-            final int action = event.getAction();
-            final int metastate = event.getMetaState();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                    x.reset(2);
-                    y.reset(2);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
-                            0, metastate), false);
-                    break;
-                case MotionEvent.ACTION_UP:
-                    x.reset(2);
-                    y.reset(2);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
-                            0, metastate), false);
-                    break;
-            }
+        final int action = event.getAction();
+        final int metastate = event.getMetaState();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                x.reset(2);
+                y.reset(2);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER,
+                        0, metastate), false);
+                break;
+            case MotionEvent.ACTION_UP:
+                x.reset(2);
+                y.reset(2);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER,
+                        0, metastate), false);
+                break;
+        }
 
-            if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
-                    + x.step + " dir=" + x.dir + " acc=" + x.acceleration
-                    + " move=" + event.getX()
-                    + " / Y=" + y.position + " step="
-                    + y.step + " dir=" + y.dir + " acc=" + y.acceleration
-                    + " move=" + event.getY());
-            final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
-            final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
+        if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + x.position + " step="
+                + x.step + " dir=" + x.dir + " acc=" + x.acceleration
+                + " move=" + event.getX()
+                + " / Y=" + y.position + " step="
+                + y.step + " dir=" + y.dir + " acc=" + y.acceleration
+                + " move=" + event.getY());
+        final float xOff = x.collect(event.getX(), event.getEventTime(), "X");
+        final float yOff = y.collect(event.getY(), event.getEventTime(), "Y");
 
-            // Generate DPAD events based on the trackball movement.
-            // We pick the axis that has moved the most as the direction of
-            // the DPAD.  When we generate DPAD events for one axis, then the
-            // other axis is reset -- we don't want to perform DPAD jumps due
-            // to slight movements in the trackball when making major movements
-            // along the other axis.
-            int keycode = 0;
-            int movement = 0;
-            float accel = 1;
-            if (xOff > yOff) {
-                movement = x.generate((2/event.getXPrecision()));
-                if (movement != 0) {
-                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
-                            : KeyEvent.KEYCODE_DPAD_LEFT;
-                    accel = x.acceleration;
-                    y.reset(2);
-                }
-            } else if (yOff > 0) {
-                movement = y.generate((2/event.getYPrecision()));
-                if (movement != 0) {
-                    keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
-                            : KeyEvent.KEYCODE_DPAD_UP;
-                    accel = y.acceleration;
-                    x.reset(2);
-                }
+        // Generate DPAD events based on the trackball movement.
+        // We pick the axis that has moved the most as the direction of
+        // the DPAD.  When we generate DPAD events for one axis, then the
+        // other axis is reset -- we don't want to perform DPAD jumps due
+        // to slight movements in the trackball when making major movements
+        // along the other axis.
+        int keycode = 0;
+        int movement = 0;
+        float accel = 1;
+        if (xOff > yOff) {
+            movement = x.generate((2/event.getXPrecision()));
+            if (movement != 0) {
+                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT
+                        : KeyEvent.KEYCODE_DPAD_LEFT;
+                accel = x.acceleration;
+                y.reset(2);
             }
+        } else if (yOff > 0) {
+            movement = y.generate((2/event.getYPrecision()));
+            if (movement != 0) {
+                keycode = movement > 0 ? KeyEvent.KEYCODE_DPAD_DOWN
+                        : KeyEvent.KEYCODE_DPAD_UP;
+                accel = y.acceleration;
+                x.reset(2);
+            }
+        }
 
-            if (keycode != 0) {
-                if (movement < 0) movement = -movement;
-                int accelMovement = (int)(movement * accel);
-                if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
-                        + " accelMovement=" + accelMovement
-                        + " accel=" + accel);
-                if (accelMovement > movement) {
-                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                            + keycode);
-                    movement--;
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_MULTIPLE, keycode,
-                            accelMovement-movement, metastate), false);
-                }
-                while (movement > 0) {
-                    if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
-                            + keycode);
-                    movement--;
-                    curTime = SystemClock.uptimeMillis();
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
-                    deliverKeyEvent(new KeyEvent(curTime, curTime,
-                            KeyEvent.ACTION_UP, keycode, 0, metastate), false);
-                }
-                mLastTrackballTime = curTime;
+        if (keycode != 0) {
+            if (movement < 0) movement = -movement;
+            int accelMovement = (int)(movement * accel);
+            if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+                    + " accelMovement=" + accelMovement
+                    + " accel=" + accel);
+            if (accelMovement > movement) {
+                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
+                        + keycode);
+                movement--;
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_MULTIPLE, keycode,
+                        accelMovement-movement, metastate), false);
             }
-        } finally {
-            if (callWhenDone) {
-                finishMotionEvent();
-                recycleMotionEvent(event);
+            while (movement > 0) {
+                if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
+                        + keycode);
+                movement--;
+                curTime = SystemClock.uptimeMillis();
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_DOWN, keycode, 0, event.getMetaState()), false);
+                deliverKeyEvent(new KeyEvent(curTime, curTime,
+                        KeyEvent.ACTION_UP, keycode, 0, metastate), false);
             }
-            // Let the exception fall through -- the looper will catch
-            // it and take care of the bad app for us.
+            mLastTrackballTime = curTime;
         }
     }
 
@@ -2862,45 +2766,20 @@
     private final InputHandler mInputHandler = new InputHandler() {
         public void handleKey(KeyEvent event, Runnable finishedCallback) {
             mFinishedCallback = finishedCallback;
-            
-            if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                //noinspection ConstantConditions
-                if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
-                    if (Config.LOGD) Log.d("keydisp",
-                            "===================================================");
-                    if (Config.LOGD) Log.d("keydisp", "Focused view Hierarchy is:");
-                    debug();
 
-                    if (Config.LOGD) Log.d("keydisp",
-                            "===================================================");
-                }
-            }
-
-            Message msg = obtainMessage(DISPATCH_KEY);
-            msg.obj = event;
-
-            if (LOCAL_LOGV) Log.v(
-                "ViewRoot", "sending key " + event + " to " + mView);
-
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchKey(event);
         }
 
         public void handleTouch(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            Message msg = obtainMessage(DISPATCH_POINTER);
-            msg.obj = event;
-            msg.arg1 = 0;
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchPointer(event);
         }
 
         public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            Message msg = obtainMessage(DISPATCH_TRACKBALL);
-            msg.obj = event;
-            msg.arg1 = 0;
-            sendMessageAtTime(msg, event.getEventTime());
+            dispatchTrackball(event);
         }
     };
 
@@ -2927,22 +2806,18 @@
         sendMessageAtTime(msg, event.getEventTime());
     }
 
-    public void dispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
+    public void dispatchPointer(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_POINTER);
         msg.obj = event;
-        msg.arg1 = callWhenDone ? 1 : 0;
-        sendMessageAtTime(msg, eventTime);
+        sendMessageAtTime(msg, event.getEventTime());
     }
 
-    public void dispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
+    public void dispatchTrackball(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_TRACKBALL);
         msg.obj = event;
-        msg.arg1 = callWhenDone ? 1 : 0;
-        sendMessageAtTime(msg, eventTime);
+        sendMessageAtTime(msg, event.getEventTime());
     }
-
+    
     public void dispatchAppVisibility(boolean visible) {
         Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
         msg.arg1 = visible ? 1 : 0;
@@ -3073,56 +2948,11 @@
         }
     }
 
-    class EventCompletion extends Handler {
-        final IWindow mWindow;
-        final KeyEvent mKeyEvent;
-        final boolean mIsPointer;
-        final MotionEvent mMotionEvent;
-
-        EventCompletion(Looper looper, IWindow window, KeyEvent key,
-                boolean isPointer, MotionEvent motion) {
-            super(looper);
-            mWindow = window;
-            mKeyEvent = key;
-            mIsPointer = isPointer;
-            mMotionEvent = motion;
-            sendEmptyMessage(0);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (mKeyEvent != null) {
-                finishKeyEvent(mKeyEvent);
-           } else if (mIsPointer) {
-                boolean didFinish;
-                MotionEvent event = mMotionEvent;
-                if (event == null) {
-                    event = getPendingPointerMotionEvent();
-                    didFinish = true;
-                } else {
-                    didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
-                }
-                if (!didFinish) {
-                    finishMotionEvent();
-                }
-            } else {
-                MotionEvent event = mMotionEvent;
-                if (event == null) {
-                    event = getPendingTrackballMotionEvent();
-                } else {
-                    finishMotionEvent();
-                }
-            }
-        }
-    }
-
     static class W extends IWindow.Stub {
         private final WeakReference<ViewRoot> mViewRoot;
-        private final Looper mMainLooper;
 
         public W(ViewRoot viewRoot, Context context) {
             mViewRoot = new WeakReference<ViewRoot>(viewRoot);
-            mMainLooper = context.getMainLooper();
         }
 
         public void resized(int w, int h, Rect coveredInsets,
@@ -3134,40 +2964,6 @@
             }
         }
 
-        public void dispatchKey(KeyEvent event) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {
-                viewRoot.dispatchKey(event);
-            } else {
-                Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!");
-                viewRoot.new EventCompletion(mMainLooper, this, event, false, null);
-            }
-        }
-
-        public void dispatchPointer(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {                
-                if (MEASURE_LATENCY) {
-                    // Note: eventTime is in milliseconds
-                    ViewRoot.lt.sample("* ViewRoot b4 dispatchPtr", System.nanoTime() - eventTime * 1000000);
-                }
-                viewRoot.dispatchPointer(event, eventTime, callWhenDone);
-            } else {
-                viewRoot.new EventCompletion(mMainLooper, this, null, true, event);
-            }
-        }
-
-        public void dispatchTrackball(MotionEvent event, long eventTime,
-                boolean callWhenDone) {
-            final ViewRoot viewRoot = mViewRoot.get();
-            if (viewRoot != null) {
-                viewRoot.dispatchTrackball(event, eventTime, callWhenDone);
-            } else {
-                viewRoot.new EventCompletion(mMainLooper, this, null, false, event);
-            }
-        }
-
         public void dispatchAppVisibility(boolean visible) {
             final ViewRoot viewRoot = mViewRoot.get();
             if (viewRoot != null) {
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index be1f6d2..33757f0 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -78,12 +78,6 @@
     public final static int FLAG_BRIGHT_HERE = 0x20000000;
 
     public final static boolean WATCH_POINTER = false;
-    
-    /**
-     * Temporary flag added during the transition to the new native input dispatcher.
-     * This will be removed when the old input dispatch code is deleted.
-     */
-    public final static boolean ENABLE_NATIVE_INPUT_DISPATCH = true;
 
     // flags for interceptKeyTq
     /**
@@ -555,23 +549,26 @@
     public Animation createForceHideEnterAnimation();
     
     /**
-     * Called from the key queue thread before a key is dispatched to the
-     * input thread.
+     * Called from the input reader thread before a key is enqueued.
      *
      * <p>There are some actions that need to be handled here because they
      * affect the power state of the device, for example, the power keys.
      * Generally, it's best to keep as little as possible in the queue thread
      * because it's the most fragile.
+     * @param whenNanos The event time in uptime nanoseconds.
+     * @param keyCode The key code.
+     * @param down True if the key is down.
+     * @param policyFlags The policy flags associated with the key.
+     * @param isScreenOn True if the screen is already on
      *
-     * @param event the raw input event as read from the driver
-     * @param screenIsOn true if the screen is already on
      * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
      *          {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
      */
-    public int interceptKeyTq(RawInputEvent event, boolean screenIsOn);
+    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
+            boolean isScreenOn);
     
     /**
-     * Called from the input thread before a key is dispatched to a window.
+     * Called from the input dispatcher thread before a key is dispatched to a window.
      *
      * <p>Allows you to define
      * behavior for keys that can not be overridden by applications or redirect
@@ -583,16 +580,17 @@
      * 
      * @param win The window that currently has focus.  This is where the key
      *            event will normally go.
-     * @param code Key code.
-     * @param metaKeys bit mask of meta keys that are held.
-     * @param down Is this a key press (true) or release (false)?
+     * @param action The key event action.
+     * @param flags The key event flags.
+     * @param keyCode The key code.
+     * @param metaState bit mask of meta keys that are held.
      * @param repeatCount Number of times a key down has repeated.
-     * @param flags event's flags.
+     * @param policyFlags The policy flags associated with the key.
      * @return Returns true if the policy consumed the event and it should
      * not be further dispatched.
      */
-    public boolean interceptKeyTi(WindowState win, int code,
-                               int metaKeys, boolean down, int repeatCount, int flags);
+    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
+            int keyCode, int metaState, int repeatCount, int policyFlags);
 
     /**
      * Called when layout of the windows is about to start.
@@ -701,85 +699,15 @@
      * Return whether the screen is currently on.
      */
     public boolean isScreenOn();
-    
+
     /**
-     * Perform any initial processing of a low-level input event before the
-     * window manager handles special keys and generates a high-level event
-     * that is dispatched to the application.
-     * 
-     * @param event The input event that has occurred.
-     * 
-     * @return Return true if you have consumed the event and do not want
-     * further processing to occur; return false for normal processing.
+     * Tell the policy that the lid switch has changed state.
+     * @param whenNanos The time when the change occurred in uptime nanoseconds.
+     * @param lidOpen True if the lid is now open.
      */
-    public boolean preprocessInputEventTq(RawInputEvent event);
-    
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
     
     /**
-     * Determine whether a given key code is used to cause an app switch
-     * to occur (most often the HOME key, also often ENDCALL).  If you return
-     * true, then the system will go into a special key processing state
-     * where it drops any pending events that it cans and adjusts timeouts to
-     * try to get to this key as quickly as possible.
-     * 
-     * <p>Note that this function is called from the low-level input queue
-     * thread, with either/or the window or input lock held; be very careful
-     * about what you do here.  You absolutely should never acquire a lock
-     * that you would ever hold elsewhere while calling out into the window
-     * manager or view hierarchy.
-     * 
-     * @param keycode The key that should be checked for performing an
-     * app switch before delivering to the application.
-     * 
-     * @return Return true if this is an app switch key and special processing
-     * should happen; return false for normal processing.
-     */
-    public boolean isAppSwitchKeyTqTiLwLi(int keycode);
-    
-    /**
-     * Determine whether a given key code is used for movement within a UI,
-     * and does not generally cause actions to be performed (normally the DPAD
-     * movement keys, NOT the DPAD center press key).  This is called
-     * when {@link #isAppSwitchKeyTiLi} returns true to remove any pending events
-     * in the key queue that are not needed to switch applications.
-     * 
-     * <p>Note that this function is called from the low-level input queue
-     * thread; be very careful about what you do here.
-     * 
-     * @param keycode The key that is waiting to be delivered to the
-     * application.
-     * 
-     * @return Return true if this is a purely navigation key and can be
-     * dropped without negative consequences; return false to keep it.
-     */
-    public boolean isMovementKeyTi(int keycode);
-    
-    /**
-     * Given the current state of the world, should this relative movement
-     * wake up the device?
-     * 
-     * @param device The device the movement came from.
-     * @param classes The input classes associated with the device.
-     * @param event The input event that occurred.
-     * @return
-     */
-    public boolean isWakeRelMovementTq(int device, int classes,
-            RawInputEvent event);
-    
-    /**
-     * Given the current state of the world, should this absolute movement
-     * wake up the device?
-     * 
-     * @param device The device the movement came from.
-     * @param classes The input classes associated with the device.
-     * @param event The input event that occurred.
-     * @return
-     */
-    public boolean isWakeAbsMovementTq(int device, int classes,
-            RawInputEvent event);
-    
-    /**
      * Tell the policy if anyone is requesting that keyguard not come on.
      *
      * @param enabled Whether keyguard can be on or not.  does not actually
@@ -852,18 +780,6 @@
     public void enableScreenAfterBoot();
     
     /**
-     * Returns true if the user's cheek has been pressed against the phone. This is 
-     * determined by comparing the event's size attribute with a threshold value.
-     * For example for a motion event like down or up or move, if the size exceeds
-     * the threshold, it is considered as cheek press.
-     * @param ev the motion event generated when the cheek is pressed 
-     * against the phone
-     * @return Returns true if the user's cheek has been pressed against the phone
-     * screen resulting in an invalid motion event
-     */
-    public boolean isCheekPressedAgainstScreen(MotionEvent ev);
-    
-    /**
      * Called every time the window manager is dispatching a pointer event.
      */
     public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY);
@@ -876,13 +792,6 @@
     public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always);
     
     /**
-     * A special function that is called from the very low-level input queue
-     * to provide feedback to the user.  Currently only called for virtual
-     * keys.
-     */
-    public void keyFeedbackFromInput(KeyEvent event);
-    
-    /**
      * Called when we have stopped keeping the screen on because a window
      * requesting this is no longer visible.
      */
diff --git a/core/java/android/widget/CursorTreeAdapter.java b/core/java/android/widget/CursorTreeAdapter.java
index 7b9b7bd..3fadf4c 100644
--- a/core/java/android/widget/CursorTreeAdapter.java
+++ b/core/java/android/widget/CursorTreeAdapter.java
@@ -134,14 +134,16 @@
     /**
      * Sets the group Cursor.
      * 
-     * @param cursor The Cursor to set for the group.
+     * @param cursor The Cursor to set for the group. If there is an existing cursor 
+     * it will be closed.
      */
     public void setGroupCursor(Cursor cursor) {
         mGroupCursorHelper.changeCursor(cursor, false);
     }
     
     /**
-     * Sets the children Cursor for a particular group.
+     * Sets the children Cursor for a particular group. If there is an existing cursor
+     * it will be closed.
      * <p>
      * This is useful when asynchronously querying to prevent blocking the UI.
      * 
@@ -476,7 +478,7 @@
             
             mCursor.unregisterContentObserver(mContentObserver);
             mCursor.unregisterDataSetObserver(mDataSetObserver);
-            mCursor.deactivate();
+            mCursor.close();
             mCursor = null;
         }
         
diff --git a/core/java/android/widget/SimpleCursorTreeAdapter.java b/core/java/android/widget/SimpleCursorTreeAdapter.java
index a1c65f0..a033542 100644
--- a/core/java/android/widget/SimpleCursorTreeAdapter.java
+++ b/core/java/android/widget/SimpleCursorTreeAdapter.java
@@ -38,6 +38,10 @@
  * binding can be found, an {@link IllegalStateException} is thrown.
  */
 public abstract class SimpleCursorTreeAdapter extends ResourceCursorTreeAdapter {
+    
+    /** The name of the columns that contain the data to display for a group. */
+    private String[] mGroupFromNames;
+    
     /** The indices of columns that contain data to display for a group. */
     private int[] mGroupFrom;
     /**
@@ -46,6 +50,9 @@
      */
     private int[] mGroupTo;
 
+    /** The name of the columns that contain the data to display for a child. */
+    private String[] mChildFromNames;
+    
     /** The indices of columns that contain data to display for a child. */
     private int[] mChildFrom;
     /**
@@ -171,38 +178,12 @@
 
     private void init(String[] groupFromNames, int[] groupTo, String[] childFromNames,
             int[] childTo) {
+        
+        mGroupFromNames = groupFromNames;
         mGroupTo = groupTo;
         
+        mChildFromNames = childFromNames;
         mChildTo = childTo;
-        
-        // Get the group cursor column indices, the child cursor column indices will come
-        // when needed
-        initGroupFromColumns(groupFromNames);
-        
-        // Get a temporary child cursor to init the column indices
-        if (getGroupCount() > 0) {
-            MyCursorHelper tmpCursorHelper = getChildrenCursorHelper(0, true);
-            if (tmpCursorHelper != null) {
-                initChildrenFromColumns(childFromNames, tmpCursorHelper.getCursor());
-                deactivateChildrenCursorHelper(0);
-            }
-        }
-    }
-    
-    private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
-        for (int i = fromColumnNames.length - 1; i >= 0; i--) {
-            fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
-        }
-    }
-    
-    private void initGroupFromColumns(String[] groupFromNames) {
-        mGroupFrom = new int[groupFromNames.length];
-        initFromColumns(mGroupCursorHelper.getCursor(), groupFromNames, mGroupFrom);
-    }
-
-    private void initChildrenFromColumns(String[] childFromNames, Cursor childCursor) {
-        mChildFrom = new int[childFromNames.length];
-        initFromColumns(childCursor, childFromNames, mChildFrom);
     }
     
     /**
@@ -257,13 +238,29 @@
         }
     }
     
+    private void initFromColumns(Cursor cursor, String[] fromColumnNames, int[] fromColumns) {
+        for (int i = fromColumnNames.length - 1; i >= 0; i--) {
+            fromColumns[i] = cursor.getColumnIndexOrThrow(fromColumnNames[i]);
+        }
+    }
+    
     @Override
     protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
+        if (mChildFrom == null) {
+            mChildFrom = new int[mChildFromNames.length];
+            initFromColumns(cursor, mChildFromNames, mChildFrom);
+        }
+        
         bindView(view, context, cursor, mChildFrom, mChildTo);
     }
 
     @Override
     protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
+        if (mGroupFrom == null) {
+            mGroupFrom = new int[mGroupFromNames.length];
+            initFromColumns(cursor, mGroupFromNames, mGroupFrom);
+        }
+        
         bindView(view, context, cursor, mGroupFrom, mGroupTo);
     }
 
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index b13d656..4da74e6 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -43,59 +43,6 @@
         }
     }
 
-    public void dispatchKey(KeyEvent event) {
-        try {
-            mSession.finishKey(this);
-        } catch (RemoteException ex) {
-        }
-    }
-
-    public boolean onDispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        event.recycle();
-        return false;
-    }
-    
-    public void dispatchPointer(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        try {
-            if (event == null) {
-                event = mSession.getPendingPointerMove(this);
-                onDispatchPointer(event, eventTime, false);
-            } else if (callWhenDone) {
-                if (!onDispatchPointer(event, eventTime, true)) {
-                    mSession.finishKey(this);
-                }
-            } else {
-                onDispatchPointer(event, eventTime, false);
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
-    public boolean onDispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        event.recycle();
-        return false;
-    }
-    
-    public void dispatchTrackball(MotionEvent event, long eventTime,
-            boolean callWhenDone) {
-        try {
-            if (event == null) {
-                event = mSession.getPendingTrackballMove(this);
-                onDispatchTrackball(event, eventTime, false);
-            } else if (callWhenDone) {
-                if (!onDispatchTrackball(event, eventTime, true)) {
-                    mSession.finishKey(this);
-                }
-            } else {
-                onDispatchTrackball(event, eventTime, false);
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     public void dispatchAppVisibility(boolean visible) {
     }
 
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 961f806..847b5a5 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -53,7 +53,7 @@
 NativeMessageQueue::NativeMessageQueue() {
     mPollLoop = PollLoop::getForThread();
     if (mPollLoop == NULL) {
-        mPollLoop = new PollLoop();
+        mPollLoop = new PollLoop(false);
         PollLoop::setForThread(mPollLoop);
     }
 }
@@ -62,7 +62,7 @@
 }
 
 bool NativeMessageQueue::pollOnce(int timeoutMillis) {
-    return mPollLoop->pollOnce(timeoutMillis);
+    return mPollLoop->pollOnce(timeoutMillis) != PollLoop::POLL_TIMEOUT;
 }
 
 void NativeMessageQueue::wake() {
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 27cb763..6c13da6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1246,6 +1246,7 @@
   <public type="attr" name="logo" id="0x010102be" />
   <public type="attr" name="xlargeScreens" id="0x010102bf" />
   <public type="attr" name="heavyWeight" id="0x010102c0" />
+  <public type="attr" name="immersive" id="0x010102c1" />
   <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
   
   <public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
new file mode 100644
index 0000000..81b4ff6
--- /dev/null
+++ b/docs/html/sdk/download.jd
@@ -0,0 +1,4 @@
+sdk.redirect=true
+
+@jd:body
+
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index f5558ab..1a42e7f 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -48,6 +48,9 @@
 how to update ADT to the latest version or how to uninstall it, if necessary.
 </p>
 
+<p class="caution"><strong>Caution:</strong> There are known issues with the ADT plugin running with
+Eclipse 3.6. Please stay on 3.5 until further notice.</p>
+
 <h2 id="notes">Revisions</h2>
 
 <p>The sections below provide notes about successive releases of
diff --git a/docs/html/sdk/requirements.jd b/docs/html/sdk/requirements.jd
index cb9cdf3..d710b8e 100644
--- a/docs/html/sdk/requirements.jd
+++ b/docs/html/sdk/requirements.jd
@@ -23,6 +23,9 @@
 <h4 style="margin-top:.25em"><em>Eclipse IDE</em></h4>
     <ul>
       <li>Eclipse 3.4 (Ganymede) or 3.5 (Galileo)
+         <p class="caution"><strong>Caution:</strong> There are known issues with the ADT plugin
+running with Eclipse 3.6. Please stay on 3.5 until further notice.</p>
+      </li>
       <li>Eclipse <a href="http://www.eclipse.org/jdt">JDT</a> plugin (included
 in most Eclipse IDE packages) </li>
       <li>If you need to install or update Eclipse, you can download it from <a
diff --git a/include/media/EffectBassBoostApi.h b/include/media/EffectBassBoostApi.h
new file mode 100644
index 0000000..b24a5f4
--- /dev/null
+++ b/include/media/EffectBassBoostApi.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTBASSBOOSTAPI_H_
+#define ANDROID_EFFECTBASSBOOSTAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_BASSBOOST_ = { 0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_BASSBOOST = &SL_IID_BASSBOOST_;
+
+/* enumerated parameter settings for BassBoost effect */
+typedef enum
+{
+    BASSBOOST_PARAM_STRENGTH_SUPPORTED,
+    BASSBOOST_PARAM_STRENGTH
+} t_bassboost_params;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTBASSBOOSTAPI_H_*/
diff --git a/include/media/EffectReverbApi.h b/include/media/EffectEnvironmentalReverbApi.h
similarity index 79%
rename from include/media/EffectReverbApi.h
rename to include/media/EffectEnvironmentalReverbApi.h
index 6371adb..d490f71 100644
--- a/include/media/EffectReverbApi.h
+++ b/include/media/EffectEnvironmentalReverbApi.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_EFFECTREVERBAPI_H_
-#define ANDROID_EFFECTREVERBAPI_H_
+#ifndef ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
+#define ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_
 
 #include <media/EffectApi.h>
 
@@ -27,14 +27,9 @@
 static const effect_uuid_t SL_IID_ENVIRONMENTALREVERB_ = { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x6, 0x83, 0x9e } };
 const effect_uuid_t * const SL_IID_ENVIRONMENTALREVERB = &SL_IID_ENVIRONMENTALREVERB_;
 
-static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
-const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
-
-/* enumerated parameter settings for Reverb effect */
+/* enumerated parameter settings for environmental reverb effect */
 typedef enum
 {
-    REVERB_PARAM_BYPASS,
-    REVERB_PARAM_PRESET,
     // Parameters below are as defined in OpenSL ES specification for environmental reverb interface
     REVERB_PARAM_ROOM_LEVEL,            // in millibels,    range -6000 to 0
     REVERB_PARAM_ROOM_HF_LEVEL,         // in millibels,    range -4000 to 0
@@ -46,17 +41,9 @@
     REVERB_PARAM_REVERB_DELAY,          // in milliseconds, range 0 to 65
     REVERB_PARAM_DIFFUSION,             // in permilles,    range 0 to 1000
     REVERB_PARAM_DENSITY,               // in permilles,    range 0 to 1000
-    REVERB_PARAM_PROPERTIES
-} t_reverb_params;
-
-
-typedef enum
-{
-    REVERB_PRESET_LARGE_HALL,
-    REVERB_PRESET_HALL,
-    REVERB_PRESET_CHAMBER,
-    REVERB_PRESET_ROOM,
-} t_reverb_presets;
+    REVERB_PARAM_PROPERTIES,
+    REVERB_PARAM_BYPASS
+} t_env_reverb_params;
 
 //t_reverb_properties is equal to SLEnvironmentalReverbSettings defined in OpenSL ES specification.
 typedef struct s_reverb_properties {
@@ -79,4 +66,4 @@
 #endif
 
 
-#endif /*ANDROID_EFFECTREVERBAPI_H_*/
+#endif /*ANDROID_EFFECTENVIRONMENTALREVERBAPI_H_*/
diff --git a/include/media/EffectPresetReverbApi.h b/include/media/EffectPresetReverbApi.h
new file mode 100644
index 0000000..34ffffe
--- /dev/null
+++ b/include/media/EffectPresetReverbApi.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTPRESETREVERBAPI_H_
+#define ANDROID_EFFECTPRESETREVERBAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+
+static const effect_uuid_t SL_IID_PRESETREVERB_ = { 0x47382d60, 0xddd8, 0x11db, 0xbf3a, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_PRESETREVERB = &SL_IID_PRESETREVERB_;
+
+/* enumerated parameter settings for preset reverb effect */
+typedef enum
+{
+    REVERB_PARAM_PRESET
+} t_preset_reverb_params;
+
+
+typedef enum
+{
+    REVERB_PRESET_NONE,
+    REVERB_PRESET_SMALLROOM,
+    REVERB_PRESET_MEDIUMROOM,
+    REVERB_PRESET_LARGEROOM,
+    REVERB_PRESET_MEDIUMHALL,
+    REVERB_PRESET_LARGEHALL,
+    REVERB_PRESET_PLATE
+} t_reverb_presets;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTPRESETREVERBAPI_H_*/
diff --git a/include/media/EffectVirtualizerApi.h b/include/media/EffectVirtualizerApi.h
new file mode 100644
index 0000000..601c384
--- /dev/null
+++ b/include/media/EffectVirtualizerApi.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_EFFECTVIRTUALIZERAPI_H_
+#define ANDROID_EFFECTVIRTUALIZERAPI_H_
+
+#include <media/EffectApi.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+// TODO: include OpenSLES_IID.h instead
+static const effect_uuid_t SL_IID_VIRTUALIZER_ = { 0x37cc2c00, 0xdddd, 0x11db, 0x8577, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
+const effect_uuid_t * const SL_IID_VIRTUALIZER = &SL_IID_VIRTUALIZER_;
+
+/* enumerated parameter settings for virtualizer effect */
+typedef enum
+{
+    VIRTUALIZER_PARAM_STRENGTH_SUPPORTED,
+    VIRTUALIZER_PARAM_STRENGTH
+} t_virtualizer_params;
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+
+#endif /*ANDROID_EFFECTVIRTUALIZERAPI_H_*/
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 497965c..5e9e368 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -48,6 +48,7 @@
     virtual status_t close() = 0;
     virtual status_t reset() = 0;
     virtual status_t getMaxAmplitude(int *max) = 0;
+    virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
 
 private:
     MediaRecorderBase(const MediaRecorderBase &);
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index c04105e..f75d80d 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -52,6 +52,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     status_t doStop();
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 781da35..03c8112 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -250,7 +250,13 @@
         nsecs_t downTime;
 
         struct CurrentVirtualKeyState {
-            bool down;
+            enum Status {
+                STATUS_UP,
+                STATUS_DOWN,
+                STATUS_CANCELED
+            };
+
+            Status status;
             nsecs_t downTime;
             int32_t keyCode;
             int32_t scanCode;
@@ -295,6 +301,7 @@
         void calculatePointerIds();
 
         bool isPointInsideDisplay(int32_t x, int32_t y) const;
+        const InputDevice::VirtualKey* findVirtualKeyHit() const;
     };
 
     InputDevice(int32_t id, uint32_t classes, String8 name);
@@ -390,11 +397,9 @@
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
-    /* Provides feedback for a virtual key.
+    /* Provides feedback for a virtual key down.
      */
-    virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-            int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
+    virtual void virtualKeyDownFeedback() = 0;
 
     /* Intercepts a key event.
      * The policy can use this method as an opportunity to perform power management functions
diff --git a/include/utils/ObbFile.h b/include/utils/ObbFile.h
new file mode 100644
index 0000000..075927c
--- /dev/null
+++ b/include/utils/ObbFile.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#ifndef OBBFILE_H_
+#define OBBFILE_H_
+
+#include <stdint.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class ObbFile : public RefBase {
+protected:
+    virtual ~ObbFile();
+
+public:
+    ObbFile();
+
+    bool readFrom(const char* filename);
+    bool readFrom(int fd);
+    bool writeTo(const char* filename);
+    bool writeTo(int fd);
+
+    const char* getFileName() const {
+        return mFileName;
+    }
+
+    const String8 getPackageName() const {
+        return mPackageName;
+    }
+
+    int32_t getVersion() const {
+        return mVersion;
+    }
+
+    void setPackageName(String8 packageName) {
+        mPackageName = packageName;
+    }
+
+    void setVersion(int32_t version) {
+        mVersion = version;
+    }
+
+    static inline uint32_t get4LE(const unsigned char* buf) {
+        return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+    }
+
+    static inline void put4LE(unsigned char* buf, uint32_t val) {
+        buf[0] = val & 0xFF;
+        buf[1] = (val >> 8) & 0xFF;
+        buf[2] = (val >> 16) & 0xFF;
+        buf[3] = (val >> 24) & 0xFF;
+    }
+
+private:
+    /* Package name this ObbFile is associated with */
+    String8 mPackageName;
+
+    /* Package version this ObbFile is associated with */
+    int32_t mVersion;
+
+    const char* mFileName;
+
+    size_t mFileSize;
+
+    unsigned char* mReadBuf;
+
+    bool parseObbFile(int fd);
+};
+
+}
+#endif /* OBBFILE_H_ */
diff --git a/include/utils/PollLoop.h b/include/utils/PollLoop.h
index b3651ca..81230e8 100644
--- a/include/utils/PollLoop.h
+++ b/include/utils/PollLoop.h
@@ -42,7 +42,7 @@
     virtual ~PollLoop();
 
 public:
-    PollLoop();
+    PollLoop(bool allowNonCallbacks);
 
     /**
      * A callback that it to be invoked when an event occurs on a file descriptor.
@@ -54,6 +54,12 @@
      */
     typedef bool (*Callback)(int fd, int events, void* data);
 
+    enum {
+        POLL_CALLBACK = ALOOPER_POLL_CALLBACK,
+        POLL_TIMEOUT = ALOOPER_POLL_TIMEOUT,
+        POLL_ERROR = ALOOPER_POLL_ERROR,
+    };
+    
     /**
      * Performs a single call to poll() with optional timeout in milliseconds.
      * Invokes callbacks for all file descriptors on which an event occurred.
@@ -61,16 +67,25 @@
      * If the timeout is zero, returns immediately without blocking.
      * If the timeout is negative, waits indefinitely until awoken.
      *
-     * Returns true if a callback was invoked or if the loop was awoken by wake().
-     * Returns false if a timeout or error occurred.
+     * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
      *
-     * This method must only be called on the main thread.
+     * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+     * timeout expired.
+     *
+     * Returns ALOPER_POLL_ERROR if an error occurred.
+     *
+     * Returns a value >= 0 containing a file descriptor if it has data
+     * and it has no callback function (requiring the caller here to handle it).
+     * In this (and only this) case outEvents and outData will contain the poll
+     * events and data associated with the fd.
+     *
+     * This method must only be called on the thread owning the PollLoop.
      * This method blocks until either a file descriptor is signalled, a timeout occurs,
      * or wake() is called.
      * This method does not return until it has finished invoking the appropriate callbacks
      * for all file descriptors that were signalled.
      */
-    bool pollOnce(int timeoutMillis);
+    int32_t pollOnce(int timeoutMillis, int* outEvents = NULL, void** outData = NULL);
 
     /**
      * Wakes the loop asynchronously.
@@ -81,6 +96,12 @@
     void wake();
 
     /**
+     * Control whether this PollLoop instance allows using IDs instead
+     * of callbacks.
+     */
+    bool getAllowNonCallbacks() const;
+    
+    /**
      * Sets the callback for a file descriptor, replacing the existing one, if any.
      * It is an error to call this method with events == 0 or callback == NULL.
      *
@@ -95,7 +116,8 @@
     /**
      * Like setCallback(), but for the NDK callback function.
      */
-    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback, void* data);
+    void setLooperCallback(int fd, int events, ALooper_callbackFunc* callback,
+            void* data);
     
     /**
      * Removes the callback for a file descriptor, if one exists.
@@ -141,7 +163,9 @@
         ALooper_callbackFunc* looperCallback;
         void* data;
     };
-
+    
+    const bool mAllowNonCallbacks;
+    
     Mutex mLock;
     bool mPolling;
     uint32_t mWaiters;
@@ -155,7 +179,9 @@
     Vector<RequestedCallback> mRequestedCallbacks;
 
     Vector<PendingCallback> mPendingCallbacks; // used privately by pollOnce
-
+    Vector<PendingCallback> mPendingFds;       // used privately by pollOnce
+    size_t mPendingFdsPos;
+    
     void openWakePipe();
     void closeWakePipe();
 
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 8f6d1fe..f809cba 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -54,7 +54,7 @@
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
     mPolicy(policy) {
-    mPollLoop = new PollLoop();
+    mPollLoop = new PollLoop(false);
 
     mInboundQueue.head.refCount = -1;
     mInboundQueue.head.type = EventEntry::TYPE_SENTINEL;
@@ -299,14 +299,13 @@
     uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
     if (entry->refCount == 1) {
         entry->eventTime = currentTime;
-        entry->downTime = currentTime;
         entry->policyFlags = policyFlags;
         entry->repeatCount += 1;
     } else {
         KeyEntry* newEntry = mAllocator.obtainKeyEntry(currentTime,
                 entry->deviceId, entry->nature, policyFlags,
                 entry->action, entry->flags, entry->keyCode, entry->scanCode,
-                entry->metaState, entry->repeatCount + 1, currentTime);
+                entry->metaState, entry->repeatCount + 1, entry->downTime);
 
         mKeyRepeatState.lastKeyEntry = newEntry;
         mAllocator.releaseKeyEntry(entry);
@@ -314,6 +313,10 @@
         entry = newEntry;
     }
 
+    if (entry->repeatCount == 1) {
+        entry->flags |= KEY_EVENT_FLAG_LONG_PRESS;
+    }
+
     mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 899027c..fced15c 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -189,7 +189,7 @@
 void InputDevice::TouchScreenState::reset() {
     lastTouch.clear();
     downTime = 0;
-    currentVirtualKey.down = false;
+    currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
 
     for (uint32_t i = 0; i < MAX_POINTERS; i++) {
         averagingTouchFilter.historyStart[i] = 0;
@@ -746,6 +746,29 @@
         && y <= parameters.yAxis.maxValue;
 }
 
+const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
+    int32_t x = currentTouch.pointers[0].x;
+    int32_t y = currentTouch.pointers[0].y;
+    for (size_t i = 0; i < virtualKeys.size(); i++) {
+        const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
+
+#if DEBUG_VIRTUAL_KEYS
+        LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
+                "left=%d, top=%d, right=%d, bottom=%d",
+                x, y,
+                virtualKey.keyCode, virtualKey.scanCode,
+                virtualKey.hitLeft, virtualKey.hitTop,
+                virtualKey.hitRight, virtualKey.hitBottom);
+#endif
+
+        if (virtualKey.isHit(x, y)) {
+            return & virtualKey;
+        }
+    }
+
+    return NULL;
+}
+
 
 // --- InputDevice::SingleTouchScreenState ---
 
@@ -1269,81 +1292,76 @@
 
 bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
         InputDevice* device, uint32_t policyFlags) {
-    if (device->touchScreen.currentVirtualKey.down) {
+    switch (device->touchScreen.currentVirtualKey.status) {
+    case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED:
         if (device->touchScreen.currentTouch.pointerCount == 0) {
-            // Pointer went up while virtual key was down.  Send key up event.
-            device->touchScreen.currentVirtualKey.down = false;
+            // Pointer went up after virtual key canceled.
+            device->touchScreen.currentVirtualKey.status =
+                    InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
+        }
+        return true; // consumed
 
+    case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN:
+        if (device->touchScreen.currentTouch.pointerCount == 0) {
+            // Pointer went up while virtual key was down.
+            device->touchScreen.currentVirtualKey.status =
+                    InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
 #if DEBUG_VIRTUAL_KEYS
             LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
                     device->touchScreen.currentVirtualKey.keyCode,
                     device->touchScreen.currentVirtualKey.scanCode);
 #endif
-
             dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
                     KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
             return true; // consumed
         }
 
-        int32_t x = device->touchScreen.currentTouch.pointers[0].x;
-        int32_t y = device->touchScreen.currentTouch.pointers[0].y;
-        if (device->touchScreen.isPointInsideDisplay(x, y)
-                || device->touchScreen.currentTouch.pointerCount != 1) {
-            // Pointer moved inside the display area or another pointer also went down.
-            // Send key cancellation.
-            device->touchScreen.currentVirtualKey.down = false;
-
-#if DEBUG_VIRTUAL_KEYS
-            LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
-                    device->touchScreen.currentVirtualKey.keyCode,
-                    device->touchScreen.currentVirtualKey.scanCode);
-#endif
-
-            dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
-                    KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
-                            | KEY_EVENT_FLAG_CANCELED);
-
-            // Clear the last touch data so we will consider the pointer as having just been
-            // pressed down when generating subsequent motion events.
-            device->touchScreen.lastTouch.clear();
-            return false; // not consumed
+        if (device->touchScreen.currentTouch.pointerCount == 1) {
+            const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
+            if (virtualKey
+                    && virtualKey->keyCode == device->touchScreen.currentVirtualKey.keyCode) {
+                // Pointer is still within the space of the virtual key.
+                return true; // consumed
+            }
         }
-    } else if (device->touchScreen.currentTouch.pointerCount == 1
-            && device->touchScreen.lastTouch.pointerCount == 0) {
-        int32_t x = device->touchScreen.currentTouch.pointers[0].x;
-        int32_t y = device->touchScreen.currentTouch.pointers[0].y;
-        for (size_t i = 0; i < device->touchScreen.virtualKeys.size(); i++) {
-            const InputDevice::VirtualKey& virtualKey = device->touchScreen.virtualKeys[i];
 
+        // Pointer left virtual key area or another pointer also went down.
+        // Send key cancellation.
+        device->touchScreen.currentVirtualKey.status =
+                InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED;
 #if DEBUG_VIRTUAL_KEYS
-            LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
-                    "left=%d, top=%d, right=%d, bottom=%d",
-                    x, y,
-                    virtualKey.keyCode, virtualKey.scanCode,
-                    virtualKey.hitLeft, virtualKey.hitTop,
-                    virtualKey.hitRight, virtualKey.hitBottom);
+        LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
+                device->touchScreen.currentVirtualKey.keyCode,
+                device->touchScreen.currentVirtualKey.scanCode);
 #endif
+        dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
+                KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
+                        | KEY_EVENT_FLAG_CANCELED);
+        return true; // consumed
 
-            if (virtualKey.isHit(x, y)) {
-                device->touchScreen.currentVirtualKey.down = true;
+    default:
+        if (device->touchScreen.currentTouch.pointerCount == 1
+                && device->touchScreen.lastTouch.pointerCount == 0) {
+            // Pointer just went down.  Check for virtual key hit.
+            const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
+            if (virtualKey) {
+                device->touchScreen.currentVirtualKey.status =
+                        InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN;
                 device->touchScreen.currentVirtualKey.downTime = when;
-                device->touchScreen.currentVirtualKey.keyCode = virtualKey.keyCode;
-                device->touchScreen.currentVirtualKey.scanCode = virtualKey.scanCode;
-
+                device->touchScreen.currentVirtualKey.keyCode = virtualKey->keyCode;
+                device->touchScreen.currentVirtualKey.scanCode = virtualKey->scanCode;
 #if DEBUG_VIRTUAL_KEYS
-                    LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
-                            device->touchScreen.currentVirtualKey.keyCode,
-                            device->touchScreen.currentVirtualKey.scanCode);
+                LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
+                        device->touchScreen.currentVirtualKey.keyCode,
+                        device->touchScreen.currentVirtualKey.scanCode);
 #endif
-
                 dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_DOWN,
                         KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
                 return true; // consumed
             }
         }
+        return false; // not consumed
     }
-
-    return false; // not consumed
 }
 
 void InputReader::dispatchVirtualKey(nsecs_t when,
@@ -1356,8 +1374,9 @@
     nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
     int32_t metaState = globalMetaState();
 
-    mPolicy->virtualKeyFeedback(when, device->id, keyEventAction, keyEventFlags,
-            keyCode, scanCode, metaState, downTime);
+    if (keyEventAction == KEY_EVENT_ACTION_DOWN) {
+        mPolicy->virtualKeyDownFeedback();
+    }
 
     int32_t policyActions = mPolicy->interceptKey(when, device->id,
             keyEventAction == KEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
@@ -1852,7 +1871,7 @@
         uint32_t flags;
         if (mEventHub->scancodeToKeycode(device->id, virtualKey.scanCode,
                 & keyCode, & flags)) {
-            LOGI("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+            LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
             device->touchScreen.virtualKeys.pop(); // drop the key
             continue;
         }
@@ -1933,7 +1952,8 @@
     for (size_t i = 0; i < mDevices.size(); i++) {
         InputDevice* device = mDevices.valueAt(i);
         if (device->isTouchScreen()) {
-            if (device->touchScreen.currentVirtualKey.down) {
+            if (device->touchScreen.currentVirtualKey.status
+                    == InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN) {
                 keyCode = device->touchScreen.currentVirtualKey.keyCode;
                 scanCode = device->touchScreen.currentVirtualKey.scanCode;
             }
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 7d4524a..2bb42ab 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -26,6 +26,7 @@
 	Debug.cpp \
 	FileMap.cpp \
 	Flattenable.cpp \
+	ObbFile.cpp \
 	Pool.cpp \
 	RefBase.cpp \
 	ResourceTypes.cpp \
@@ -65,6 +66,11 @@
 endif
 endif
 
+ifeq ($(HOST_OS),darwin)
+# MacOS doesn't have lseek64. However, off_t is 64-bit anyway.
+LOCAL_CFLAGS += -DOFF_T_IS_64_BIT
+endif
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp
new file mode 100644
index 0000000..3a4a03a
--- /dev/null
+++ b/libs/utils/ObbFile.cpp
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "ObbFile"
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+
+//#define DEBUG 1
+
+#define kFooterTagSize 8  /* last two 32-bit integers */
+
+#define kFooterMinSize 21 /* 32-bit signature version
+                           * 32-bit package version
+                           * 32-bit package name size
+                           * 1-character package name
+                           * 32-bit footer size
+                           * 32-bit footer marker
+                           */
+
+#define kMaxBufSize    32768 /* Maximum file read buffer */
+
+#define kSignature     0x01059983U /* ObbFile signature */
+
+#define kSigVersion    1 /* We only know about signature version 1 */
+
+/* offsets in version 1 of the header */
+#define kPackageVersionOffset 4
+#define kPackageNameLenOffset 8
+#define kPackageNameOffset    12
+
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
+/*
+ * Work around situations where off_t is 64-bit and use off64_t in
+ * situations where it's 32-bit.
+ */
+#ifdef OFF_T_IS_64_BIT
+#define my_lseek64 lseek
+typedef off_t my_off64_t;
+#else
+#define my_lseek64 lseek64
+typedef off64_t my_off64_t;
+#endif
+
+namespace android {
+
+ObbFile::ObbFile() :
+        mVersion(-1) {
+}
+
+ObbFile::~ObbFile() {
+}
+
+bool ObbFile::readFrom(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_RDONLY);
+    if (fd < 0) {
+        goto out;
+    }
+    success = readFrom(fd);
+    close(fd);
+
+out:
+    if (!success) {
+        LOGW("failed to read from %s\n", filename);
+    }
+    return success;
+}
+
+bool ObbFile::readFrom(int fd)
+{
+    if (fd < 0) {
+        LOGW("failed to read file\n");
+        return false;
+    }
+
+    return parseObbFile(fd);
+}
+
+bool ObbFile::parseObbFile(int fd)
+{
+    my_off64_t fileLength = my_lseek64(fd, 0, SEEK_END);
+
+    if (fileLength < kFooterMinSize) {
+        if (fileLength < 0) {
+            LOGW("error seeking in ObbFile: %s\n", strerror(errno));
+        } else {
+            LOGW("file is only %lld (less than %d minimum)\n", fileLength, kFooterMinSize);
+        }
+        return false;
+    }
+
+    ssize_t actual;
+    size_t footerSize;
+
+    {
+        my_lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
+
+        char *footer = new char[kFooterTagSize];
+        actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
+        if (actual != kFooterTagSize) {
+            LOGW("couldn't read footer signature: %s\n", strerror(errno));
+            return false;
+        }
+
+        unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
+        if (fileSig != kSignature) {
+            LOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
+                    kSignature, fileSig);
+            return false;
+        }
+
+        footerSize = get4LE((unsigned char*)footer);
+        if (footerSize > (size_t)fileLength - kFooterTagSize
+                || footerSize > kMaxBufSize) {
+            LOGW("claimed footer size is too large (0x%08lx; file size is 0x%08llx)\n",
+                    footerSize, fileLength);
+            return false;
+        }
+    }
+
+    my_off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
+    if (my_lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
+        LOGW("seek %lld failed: %s\n", fileOffset, strerror(errno));
+        return false;
+    }
+
+    size_t readAmount = kMaxBufSize;
+    if (readAmount > footerSize)
+        readAmount = footerSize;
+
+    char* scanBuf = (char*)malloc(readAmount);
+    if (scanBuf == NULL) {
+        LOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
+        return false;
+    }
+
+    actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, readAmount));
+    // readAmount is guaranteed to be less than kMaxBufSize
+    if (actual != (ssize_t)readAmount) {
+        LOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
+        free(scanBuf);
+        return false;
+    }
+
+#ifdef DEBUG
+    for (int i = 0; i < readAmount; ++i) {
+        LOGI("char: 0x%02x", scanBuf[i]);
+    }
+#endif
+
+    uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
+    if (sigVersion != kSigVersion) {
+        LOGW("Unsupported ObbFile version %d\n", sigVersion);
+        free(scanBuf);
+        return false;
+    }
+
+    mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
+
+    uint32_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
+    if (packageNameLen <= 0
+            || packageNameLen > (footerSize - kPackageNameOffset)) {
+        LOGW("bad ObbFile package name length (0x%08x)\n", packageNameLen);
+        free(scanBuf);
+        return false;
+    }
+
+    char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
+    mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
+
+    free(scanBuf);
+    return true;
+}
+
+bool ObbFile::writeTo(const char* filename)
+{
+    int fd;
+    bool success = false;
+
+    fd = ::open(filename, O_WRONLY);
+    if (fd < 0) {
+        goto out;
+    }
+    success = writeTo(fd);
+    close(fd);
+
+out:
+    if (!success) {
+        LOGW("failed to write to %s: %s\n", filename, strerror(errno));
+    }
+    return success;
+}
+
+bool ObbFile::writeTo(int fd)
+{
+    if (fd < 0) {
+        return false;
+    }
+
+    if (mPackageName.size() == 0 || mVersion == -1) {
+        LOGW("tried to write uninitialized ObbFile data");
+        return false;
+    }
+
+    unsigned char intBuf[sizeof(uint32_t)+1];
+    memset(&intBuf, 0, sizeof(intBuf));
+
+    put4LE(intBuf, kSigVersion);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write signature version: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, mVersion);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write package version");
+        return false;
+    }
+
+    size_t packageNameLen = mPackageName.size();
+    put4LE(intBuf, packageNameLen);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write package name length: %s", strerror(errno));
+        return false;
+    }
+
+    if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
+        LOGW("couldn't write package name: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, 3*sizeof(uint32_t) + packageNameLen);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write footer size: %s", strerror(errno));
+        return false;
+    }
+
+    put4LE(intBuf, kSignature);
+    if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
+        LOGW("couldn't write footer magic signature: %s", strerror(errno));
+        return false;
+    }
+
+    return true;
+}
+
+}
diff --git a/libs/utils/PollLoop.cpp b/libs/utils/PollLoop.cpp
index 58fe141..f740fa0 100644
--- a/libs/utils/PollLoop.cpp
+++ b/libs/utils/PollLoop.cpp
@@ -25,8 +25,9 @@
 static bool gHaveTLS = false;
 static pthread_key_t gTLS = 0;
 
-PollLoop::PollLoop() :
-        mPolling(false), mWaiters(0) {
+PollLoop::PollLoop(bool allowNonCallbacks) :
+        mAllowNonCallbacks(allowNonCallbacks), mPolling(false),
+        mWaiters(0), mPendingFdsPos(0) {
     openWakePipe();
 }
 
@@ -106,7 +107,18 @@
     //       method is currently only called by the destructor.
 }
 
-bool PollLoop::pollOnce(int timeoutMillis) {
+int32_t PollLoop::pollOnce(int timeoutMillis, int* outEvents, void** outData) {
+    // If there are still pending fds from the last call, dispatch those
+    // first, to avoid an earlier fd from starving later ones.
+    const size_t pendingFdsCount = mPendingFds.size();
+    if (mPendingFdsPos < pendingFdsCount) {
+        const PendingCallback& pending = mPendingFds.itemAt(mPendingFdsPos);
+        mPendingFdsPos++;
+        if (outEvents != NULL) *outEvents = pending.events;
+        if (outData != NULL) *outData = pending.data;
+        return pending.fd;
+    }
+    
     mLock.lock();
     while (mWaiters != 0) {
         mResume.wait(mLock);
@@ -114,7 +126,7 @@
     mPolling = true;
     mLock.unlock();
 
-    bool result;
+    int32_t result;
     size_t requestedCount = mRequestedFds.size();
 
 #if DEBUG_POLL_AND_WAKE
@@ -131,7 +143,7 @@
 #if DEBUG_POLL_AND_WAKE
         LOGD("%p ~ pollOnce - timeout", this);
 #endif
-        result = false;
+        result = POLL_TIMEOUT;
         goto Done;
     }
 
@@ -143,7 +155,7 @@
         if (errno != EINTR) {
             LOGW("Poll failed with an unexpected error, errno=%d", errno);
         }
-        result = false;
+        result = POLL_ERROR;
         goto Done;
     }
 
@@ -156,38 +168,44 @@
 #endif
 
     mPendingCallbacks.clear();
+    mPendingFds.clear();
+    mPendingFdsPos = 0;
+    if (outEvents != NULL) *outEvents = 0;
+    if (outData != NULL) *outData = NULL;
+    
+    result = POLL_CALLBACK;
     for (size_t i = 0; i < requestedCount; i++) {
         const struct pollfd& requestedFd = mRequestedFds.itemAt(i);
 
         short revents = requestedFd.revents;
         if (revents) {
             const RequestedCallback& requestedCallback = mRequestedCallbacks.itemAt(i);
-            Callback callback = requestedCallback.callback;
-            ALooper_callbackFunc* looperCallback = requestedCallback.looperCallback;
+            PendingCallback pending;
+            pending.fd = requestedFd.fd;
+            pending.events = revents;
+            pending.callback = requestedCallback.callback;
+            pending.looperCallback = requestedCallback.looperCallback;
+            pending.data = requestedCallback.data;
 
-            if (callback || looperCallback) {
-                PendingCallback pendingCallback;
-                pendingCallback.fd = requestedFd.fd;
-                pendingCallback.events = requestedFd.revents;
-                pendingCallback.callback = callback;
-                pendingCallback.looperCallback = looperCallback;
-                pendingCallback.data = requestedCallback.data;
-                mPendingCallbacks.push(pendingCallback);
-            } else {
-                if (requestedFd.fd == mWakeReadPipeFd) {
-#if DEBUG_POLL_AND_WAKE
-                    LOGD("%p ~ pollOnce - awoken", this);
-#endif
-                    char buffer[16];
-                    ssize_t nRead;
-                    do {
-                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
-                    } while (nRead == sizeof(buffer));
+            if (pending.callback || pending.looperCallback) {
+                mPendingCallbacks.push(pending);
+            } else if (pending.fd != mWakeReadPipeFd) {
+                if (result == POLL_CALLBACK) {
+                    result = pending.fd;
+                    if (outEvents != NULL) *outEvents = pending.events;
+                    if (outData != NULL) *outData = pending.data;
                 } else {
-#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
-                    LOGD("%p ~ pollOnce - fd %d has no callback!", this, requestedFd.fd);
-#endif
+                    mPendingFds.push(pending);
                 }
+            } else {
+#if DEBUG_POLL_AND_WAKE
+                LOGD("%p ~ pollOnce - awoken", this);
+#endif
+                char buffer[16];
+                ssize_t nRead;
+                do {
+                    nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
+                } while (nRead == sizeof(buffer));
             }
 
             respondedCount -= 1;
@@ -196,7 +214,6 @@
             }
         }
     }
-    result = true;
 
 Done:
     mLock.lock();
@@ -206,7 +223,7 @@
     }
     mLock.unlock();
 
-    if (result) {
+    if (result == POLL_CALLBACK || result >= 0) {
         size_t pendingCount = mPendingCallbacks.size();
         for (size_t i = 0; i < pendingCount; i++) {
             const PendingCallback& pendingCallback = mPendingCallbacks.itemAt(i);
@@ -247,6 +264,10 @@
     }
 }
 
+bool PollLoop::getAllowNonCallbacks() const {
+    return mAllowNonCallbacks;
+}
+
 void PollLoop::setCallback(int fd, int events, Callback callback, void* data) {
     setCallbackCommon(fd, events, callback, NULL, data);
 }
@@ -263,12 +284,18 @@
     LOGD("%p ~ setCallback - fd=%d, events=%d", this, fd, events);
 #endif
 
-    if (! events || (! callback && ! looperCallback)) {
-        LOGE("Invalid attempt to set a callback with no selected poll events or no callback.");
+    if (! events) {
+        LOGE("Invalid attempt to set a callback with no selected poll events.");
         removeCallback(fd);
         return;
     }
 
+    if (! callback && ! looperCallback && ! mAllowNonCallbacks) {
+        LOGE("Invalid attempt to set NULL callback but not allowed.");
+        removeCallback(fd);
+        return;
+    }
+    
     wakeAndLock();
 
     struct pollfd requestedFd;
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 92ebfd7c..f1b8cd5 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -3,6 +3,7 @@
 include $(CLEAR_VARS)
 
 test_src_files := \
+	ObbFile_test.cpp \
 	PollLoop_test.cpp
 
 shared_libraries := \
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp
new file mode 100644
index 0000000..05aaf08
--- /dev/null
+++ b/libs/utils/tests/ObbFile_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ObbFile_test"
+#include <utils/Log.h>
+#include <utils/ObbFile.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+#define TEST_FILENAME "/test.obb"
+
+class ObbFileTest : public testing::Test {
+protected:
+    sp<ObbFile> mObbFile;
+    char* mExternalStorage;
+    char* mFileName;
+
+    virtual void SetUp() {
+        mObbFile = new ObbFile();
+        mExternalStorage = getenv("EXTERNAL_STORAGE");
+
+        const int totalLen = strlen(mExternalStorage) + strlen(TEST_FILENAME) + 1;
+        mFileName = new char[totalLen];
+        snprintf(mFileName, totalLen, "%s%s", mExternalStorage, TEST_FILENAME);
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ObbFileTest, ReadFailure) {
+	EXPECT_FALSE(mObbFile->readFrom(-1))
+			<< "No failure on invalid file descriptor";
+}
+
+TEST_F(ObbFileTest, WriteThenRead) {
+    const char* packageName = "com.example.obbfile";
+    const int32_t versionNum = 1;
+
+    mObbFile->setPackageName(String8(packageName));
+    mObbFile->setVersion(versionNum);
+
+    EXPECT_TRUE(mObbFile->writeTo(mFileName))
+            << "couldn't write to fake .obb file";
+
+    mObbFile = new ObbFile();
+
+    EXPECT_TRUE(mObbFile->readFrom(mFileName))
+            << "couldn't read from fake .obb file";
+
+    EXPECT_EQ(versionNum, mObbFile->getVersion())
+			<< "version didn't come out the same as it went in";
+    const char* currentPackageName = mObbFile->getPackageName().string();
+    EXPECT_STREQ(packageName, currentPackageName)
+			<< "package name didn't come out the same as it went in";
+}
+
+}
diff --git a/libs/utils/tests/PollLoop_test.cpp b/libs/utils/tests/PollLoop_test.cpp
index 4848c0f..02f1808 100644
--- a/libs/utils/tests/PollLoop_test.cpp
+++ b/libs/utils/tests/PollLoop_test.cpp
@@ -87,7 +87,7 @@
     sp<PollLoop> mPollLoop;
 
     virtual void SetUp() {
-        mPollLoop = new PollLoop();
+        mPollLoop = new PollLoop(false);
     }
 
     virtual void TearDown() {
@@ -98,26 +98,26 @@
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndNotAwoken_WaitsForTimeoutAndReturnsFalse) {
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenBeforeWaiting_ImmediatelyReturnsTrue) {
     mPollLoop->wake();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. zero because wake() was called before waiting";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because loop was awoken";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenNonZeroTimeoutAndAwokenWhileWaiting_PromptlyReturnsTrue) {
@@ -125,24 +125,24 @@
     delayedWake->run();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal wake delay";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because loop was awoken";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because loop was awoken";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoRegisteredFDs_ImmediatelyReturnsFalse) {
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
 }
 
 TEST_F(PollLoopTest, PollOnce_WhenZeroTimeoutAndNoSignalledFDs_ImmediatelyReturnsFalse) {
@@ -152,13 +152,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not have been invoked because FD was not signalled";
 }
@@ -171,13 +171,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -193,13 +193,13 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not have been invoked because FD was not signalled";
 }
@@ -212,15 +212,15 @@
     handler.setCallback(mPollLoop, pipe.receiveFd, POLL_IN);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should be approx. zero";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -238,15 +238,15 @@
     delayedWriteSignal->run();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(1000);
+    int32_t result = mPollLoop->pollOnce(1000);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal signal delay";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked exactly once";
     EXPECT_EQ(pipe.receiveFd, handler.fd)
@@ -264,15 +264,15 @@
     mPollLoop->removeCallback(pipe.receiveFd);
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal timeout because FD was no longer registered";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(0, handler.callbackCount)
             << "callback should not be invoked";
 }
@@ -287,15 +287,15 @@
     pipe.writeSignal();
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(0);
+    int32_t result = mPollLoop->pollOnce(0);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal zero because FD was already signalled";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should be invoked";
 
@@ -310,8 +310,8 @@
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. equal zero because timeout was zero";
-    EXPECT_FALSE(result)
-            << "pollOnce result should be false because timeout occurred";
+    EXPECT_EQ(result, PollLoop::POLL_TIMEOUT)
+            << "pollOnce result should be POLL_TIMEOUT";
     EXPECT_EQ(1, handler.callbackCount)
             << "callback should not be invoked this time";
 }
@@ -351,15 +351,15 @@
     pipe.writeSignal(); // would cause FD to be considered signalled
 
     StopWatch stopWatch("pollOnce");
-    bool result = mPollLoop->pollOnce(100);
+    int32_t result = mPollLoop->pollOnce(100);
     int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
 
     ASSERT_EQ(OK, pipe.readSignal())
             << "signal should actually have been written";
     EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
             << "elapsed time should approx. zero because FD was already signalled";
-    EXPECT_TRUE(result)
-            << "pollOnce result should be true because FD was signalled";
+    EXPECT_EQ(result, PollLoop::POLL_CALLBACK)
+            << "pollOnce result should be POLL_CALLBACK because FD was signalled";
     EXPECT_EQ(0, handler1.callbackCount)
             << "original handler callback should not be invoked because it was replaced";
     EXPECT_EQ(1, handler2.callbackCount)
diff --git a/media/java/android/media/BassBoost.java b/media/java/android/media/BassBoost.java
new file mode 100644
index 0000000..ef4ce05
--- /dev/null
+++ b/media/java/android/media/BassBoost.java
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * Bass boost is an audio effect to boost or amplify low frequencies of the sound. It is comparable
+ * to an simple equalizer but limited to one band amplification in the low frequency range.
+ * <p>An application creates a BassBoost object to instantiate and control a bass boost engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the BassBoost implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLBassBoostItf interface. Please refer to this specification for more details.
+ * <p>To attach the BassBoost to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the BassBoost. If the audio session ID 0
+ * is specified, the BassBoost applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class BassBoost extends AudioEffect {
+
+    private final static String TAG = "BassBoost";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectBassBoostApi.h
+    /**
+     * Is strength parameter supported by bass boost engine. Parameter ID for getParameter().
+     */
+    public static final int PARAM_STRENGTH_SUPPORTED = 0;
+    /**
+     * Bass boost effect strength. Parameter ID for
+     * {@link android.media.BassBoost.OnParameterChangeListener}
+     */
+    public static final int PARAM_STRENGTH = 1;
+
+    /**
+     * Indicates if strength parameter is supported by the bass boost engine
+     */
+    private boolean mStrengthSupported = false;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the BassBoost
+     * engine. As the same engine can be shared by several applications, this parameter indicates
+     * how much the requesting application needs control of effect parameters. The normal priority
+     * is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the BassBoost will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the BassBoost will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public BassBoost(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_BASS_BOOST, EFFECT_TYPE_NULL, priority, audioSession);
+
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+        mStrengthSupported = (value[0] != 0);
+    }
+
+    /**
+     * Indicates whether setting strength is supported. If this method returns false, only one
+     * strength is supported and the setStrength() method always rounds to that value.
+     * @return true is strength parameter is supported, false otherwise
+     */
+    public boolean getStrengthSupported() {
+       return mStrengthSupported;
+    }
+
+    /**
+     * Sets the strength of the bass boost effect. If the implementation does not support per mille
+     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+     * supported value. You can use the {@link #getRoundedStrength()} method to query the
+     * (possibly rounded) value that was actually set.
+     * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setStrength(short strength)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_STRENGTH, strength));
+    }
+
+    /**
+     * Gets the current strength of the effect.
+     * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+     * mille designates the mildest effect and 1000 per mille the strongest
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoundedStrength()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the BassBoost when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * BassBoost engine.
+         * @param effect the BassBoost on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(BassBoost effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(BassBoost.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/EnvironmentalReverb.java b/media/java/android/media/EnvironmentalReverb.java
new file mode 100644
index 0000000..88230fc
--- /dev/null
+++ b/media/java/android/media/EnvironmentalReverb.java
@@ -0,0 +1,504 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The EnvironmentalReverb class allows an application to control each reverb engine property in a
+ * global reverb environment and is more suitable for games. For basic control, more suitable for
+ * music applications, it is recommended to use the
+ // TODO when PresetReverb is unhidden
+ // {_at_link android.media.PresetReverb} class.
+ * <p>An application creates a EnvironmentalReverb object to instantiate and control a reverb engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the EnvironmentalReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLEnvironmentalReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The EnvironmentalReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling
+ * audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class EnvironmentalReverb extends AudioEffect {
+
+    private final static String TAG = "EnvironmentalReverb";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectEnvironmentalReverbApi.h
+
+    /**
+     * Room level. Parameter ID for
+     * {@link android.media.EnvironmentalReverb.OnParameterChangeListener}
+     */
+    public static final int PARAM_ROOM_LEVEL = 0;
+    /**
+     * Room HF level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_ROOM_HF_LEVEL = 1;
+    /**
+     * Decay time. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DECAY_TIME = 2;
+    /**
+     * Decay HF ratio. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DECAY_HF_RATIO = 3;
+    /**
+     * Early reflections level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REFLECTIONS_LEVEL = 4;
+    /**
+     * Early reflections delay. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REFLECTIONS_DELAY = 5;
+    /**
+     * Reverb level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REVERB_LEVEL = 6;
+    /**
+     * Reverb delay. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_REVERB_DELAY = 7;
+    /**
+     * Diffusion. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DIFFUSION = 8;
+    /**
+     * Density. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_DENSITY = 9;
+
+    /**
+     * Registered listener for parameter changes
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super
+     * class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the
+     * EnvironmentalReverb engine. As the same engine can be shared by several applications, this
+     * parameter indicates how much the requesting application needs control of effect parameters.
+     * The normal priority is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the EnvironmentalReverb will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the EnvironmentalReverb will apply to the output mix.
+     *  As the EnvironmentalReverb is an auxiliary effect it is recommended to instantiate it on
+     *  audio session 0 and to attach it to the MediaPLayer auxiliary output.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public EnvironmentalReverb(int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_ENV_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+        Log.e(TAG, "contructor");
+    }
+
+    /**
+     * Sets the master volume level of the environmental reverb effect.
+     * @param room Room level in millibels. The valid range is [-9000, 0].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setRoomLevel(short room)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(room);
+        checkStatus(setParameter(PARAM_ROOM_LEVEL, param));
+    }
+
+    /**
+     * Gets the master volume level of the environmental reverb effect.
+     * @return the room level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoomLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_ROOM_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the volume level at 5 kHz relative to the volume level at low frequencies of the
+     * overall reverb effect.
+     * <p>This controls a low-pass filter that will reduce the level of the high-frequency.
+     * @param roomHF High frequency attenuation level in millibels. The valid range is [-9000, 0].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setRoomHFLevel(short roomHF)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(roomHF);
+        checkStatus(setParameter(PARAM_ROOM_HF_LEVEL, param));
+    }
+
+    /**
+     * Gets the room HF level.
+     * @return the room HF level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoomHFLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_ROOM_HF_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the time taken for the level of reverberation to decay by 60 dB.
+     * @param decayTime Decay time in milliseconds. The valid range is [100, 20000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDecayTime(int decayTime)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(decayTime);
+        checkStatus(setParameter(PARAM_DECAY_TIME, param));
+    }
+
+    /**
+     * Gets the decay time.
+     * @return the decay time in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getDecayTime()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_DECAY_TIME, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the ratio of high frequency decay time (at 5 kHz) relative to the decay time at low
+     * frequencies.
+     * @param decayHFRatio High frequency decay ratio using a permille scale. The valid range is
+     * [100, 2000]. A ratio of 1000 indicates that all frequencies decay at the same rate.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDecayHFRatio(short decayHFRatio)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(decayHFRatio);
+        checkStatus(setParameter(PARAM_DECAY_HF_RATIO, param));
+    }
+
+    /**
+     * Gets the ratio of high frequency decay time (at 5 kHz) relative to low frequencies.
+     * @return the decay HF ration. See {@link #setDecayHFRatio(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDecayHFRatio()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DECAY_HF_RATIO, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the volume level of the early reflections.
+     * <p>This level is combined with the overall room level
+     * (set using {@link #setRoomLevel(short)}).
+     * @param reflectionsLevel Reflection level in millibels. The valid range is [-9000, 1000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReflectionsLevel(short reflectionsLevel)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(reflectionsLevel);
+        checkStatus(setParameter(PARAM_REFLECTIONS_LEVEL, param));
+    }
+
+    /**
+     * Gets the volume level of the early reflections.
+     * @return the early reflections level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getReflectionsLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_REFLECTIONS_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the delay time for the early reflections.
+     * <p>This method sets the time between when the direct path is heard and when the first
+     * reflection is heard.
+     * @param reflectionsDelay Reflections delay in milliseconds. The valid range is [0, 300].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReflectionsDelay(int reflectionsDelay)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(reflectionsDelay);
+        checkStatus(setParameter(PARAM_REFLECTIONS_DELAY, param));
+    }
+
+    /**
+     * Gets the reflections delay.
+     * @return the early reflections delay in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getReflectionsDelay()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_REFLECTIONS_DELAY, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the volume level of the late reverberation.
+     * <p>This level is combined with the overall room level (set using {@link #setRoomLevel(short)}).
+     * @param reverbLevel Reverb level in millibels. The valid range is [-9000, 2000].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReverbLevel(short reverbLevel)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(reverbLevel);
+        checkStatus(setParameter(PARAM_REVERB_LEVEL, param));
+    }
+
+    /**
+     * Gets the reverb level.
+     * @return the reverb level in millibels.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getReverbLevel()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_REVERB_LEVEL, param));
+        return byteArrayToShort(param);
+    }
+
+    /**
+     * Sets the time between the first reflection and the reverberation.
+     * @param reverbDelay Reverb delay in milliseconds. The valid range is [0, 100].
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setReverbDelay(int reverbDelay)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = intToByteArray(reverbDelay);
+        checkStatus(setParameter(PARAM_REVERB_DELAY, param));
+    }
+
+    /**
+     * Gets the reverb delay.
+     * @return the reverb delay in milliseconds.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getReverbDelay()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[4];
+        checkStatus(getParameter(PARAM_REVERB_DELAY, param));
+        return byteArrayToInt(param);
+    }
+
+    /**
+     * Sets the echo density in the late reverberation decay.
+     * <p>The scale should approximately map linearly to the perceived change in reverberation.
+     * @param diffusion Diffusion specified using a permille scale. The diffusion valid range is
+     * [0, 1000]. A value of 1000 o/oo indicates a smooth reverberation decay.
+     * Values below this level give a more <i>grainy</i> character.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDiffusion(short diffusion)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(diffusion);
+        checkStatus(setParameter(PARAM_DIFFUSION, param));
+    }
+
+    /**
+     * Gets diffusion level.
+     * @return the diffusion level. See {@link #setDiffusion(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDiffusion()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DIFFUSION, param));
+        return byteArrayToShort(param);
+    }
+
+
+    /**
+     * Controls the modal density of the late reverberation decay.
+     * <p> The scale should approximately map linearly to the perceived change in reverberation.
+     * A lower density creates a hollow sound that is useful for simulating small reverberation
+     * spaces such as bathrooms.
+     * @param density Density specified using a permille scale. The valid range is [0, 1000].
+     * A value of 1000 o/oo indicates a natural sounding reverberation. Values below this level
+     * produce a more colored effect.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setDensity(short density)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = shortToByteArray(density);
+        checkStatus(setParameter(PARAM_DENSITY, param));
+    }
+
+    /**
+     * Gets the density level.
+     * @return the density level. See {@link #setDiffusion(short)} for units.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getDensity()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        byte[] param = new byte[2];
+        checkStatus(getParameter(PARAM_DENSITY, param));
+        return byteArrayToShort(param);
+    }
+
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the EnvironmentalReverb
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * EnvironmentalReverb engine.
+         * @param effect the EnvironmentalReverb on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_ROOM_LEVEL} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(EnvironmentalReverb effect, int status, int param, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                int v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = (int)byteArrayToShort(value, 0);
+                } else if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(EnvironmentalReverb.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/Equalizer.java b/media/java/android/media/Equalizer.java
new file mode 100644
index 0000000..082f694
--- /dev/null
+++ b/media/java/android/media/Equalizer.java
@@ -0,0 +1,443 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An Equalizer is used to alter the frequency response of a particular music source or of the main
+ * output mix.
+ * <p>An application creates an Equalizer object to instantiate and control an Equalizer engine
+ * in the audio framework. The application can either simply use predefined presets or have a more
+ * precise control of the gain in each frequency band controlled by the equalizer.
+ * <p>The methods, parameter types and units exposed by the Equalizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLEqualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Equalizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Equalizer. If the audio session ID 0
+ * is specified, the Equalizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Equalizer extends AudioEffect {
+
+    private final static String TAG = "Equalizer";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectEqualizerApi.h
+    /**
+     * Number of bands. Parameter ID for {@link android.media.Equalizer.OnParameterChangeListener}
+     */
+    public static final int PARAM_NUM_BANDS = 0;
+    /**
+     * Band level range. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_LEVEL_RANGE = 1;
+    /**
+     * Band level. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_BAND_LEVEL = 2;
+    /**
+     * Band center frequency. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_CENTER_FREQ = 3;
+    /**
+     * Band frequency range. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_BAND_FREQ_RANGE = 4;
+    /**
+     * Band for a given frequency. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_BAND = 5;
+    /**
+     * Current preset. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_CURRENT_PRESET = 6;
+    /**
+     * Request number of presets. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_NUM_OF_PRESETS = 7;
+    /**
+     * Request preset name. Parameter ID for OnParameterChangeListener
+     */
+    public static final int PARAM_GET_PRESET_NAME = 8;
+    /**
+     * maximum size for perset name
+     */
+    public static final int PARAM_STRING_SIZE_MAX = 32;
+
+    /**
+     * Number of presets implemented by Equalizer engine
+     */
+    private int mNumPresets;
+    /**
+     * Names of presets implemented by Equalizer engine
+     */
+    private String[] mPresetNames;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the Equalizer
+     * engine. As the same engine can be shared by several applications, this parameter indicates
+     * how much the requesting application needs control of effect parameters. The normal priority
+     * is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the Equalizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Equalizer will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public Equalizer(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_EQUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        mNumPresets = (int)getNumberOfPresets();
+
+        if (mNumPresets != 0) {
+            mPresetNames = new String[mNumPresets];
+            byte[] value = new byte[PARAM_STRING_SIZE_MAX];
+            int[] param = new int[2];
+            param[0] = PARAM_GET_PRESET_NAME;
+            for (int i = 0; i < mNumPresets; i++) {
+                param[1] = i;
+                checkStatus(getParameter(param, value));
+                int length = 0;
+                while (value[length] != 0) length++;
+                try {
+                    mPresetNames[i] = new String(value, 0, length, "ISO-8859-1");
+                    Log.e(TAG, "preset #: "+i+" name: "+mPresetNames[i]+" length: "+length);
+                } catch (java.io.UnsupportedEncodingException e) {
+                    Log.e(TAG, "preset name decode error");
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the number of frequency bands supported by the Equalizer engine.
+     * @return the number of bands
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getNumberOfBands()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_NUM_BANDS;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Gets the level range for use by {@link #setBandLevel(int,short)}. The level is expressed in
+     * milliBel.
+     * @return the band level range in an array of short integers. The first element is the lower
+     * limit of the range, the second element the upper limit.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short[] getBandLevelRange()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        int[] value = new int[2];
+        param[0] = PARAM_LEVEL_RANGE;
+        checkStatus(getParameter(param, value));
+
+        short[] result = new short[2];
+
+        result[0] = (short)value[0];
+        result[1] = (short)value[1];
+
+        return result;
+    }
+
+    /**
+     * Sets the given equalizer band to the given gain value.
+     * @param band Frequency band that will have the new gain. The numbering of the bands starts
+     * from 0 and ends at (number of bands - 1). See @see #getNumberOfBands().
+     * @param level New gain in millibels that will be set to the given band. getBandLevelRange()
+     * will define the maximum and minimum values.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setBandLevel(int band, short level)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] value = new int[1];
+
+        param[0] = PARAM_BAND_LEVEL;
+        param[1] = band;
+        value[0] = (int)level;
+        checkStatus(setParameter(param, value));
+    }
+
+    /**
+     * Gets the gain set for the given equalizer band.
+     * @param band Frequency band whose gain is requested. The numbering of the bands starts
+     * from 0 and ends at (number of bands - 1).
+     * @return Gain in millibels of the given band.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getBandLevel(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_BAND_LEVEL;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return (short)result[0];
+    }
+
+
+    /**
+     * Gets the center frequency of the given band.
+     * @param band Frequency band whose center frequency is requested. The numbering of the bands
+     * starts from 0 and ends at (number of bands - 1).
+     * @return The center frequency in milliHertz
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getCenterFreq(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_CENTER_FREQ;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return result[0];
+    }
+
+    /**
+     * Gets the frequency range of the given frequency band.
+     * @param band Frequency band whose frequency range is requested. The numbering of the bands
+     * starts from 0 and ends at (number of bands - 1).
+     * @return The frequency range in millHertz in an array of integers. The first element is the
+     * lower limit of the range, the second element the upper limit.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int[] getBandFreqRange(int band)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[2];
+        param[0] = PARAM_BAND_FREQ_RANGE;
+        param[1] = band;
+        checkStatus(getParameter(param, result));
+
+        return result;
+    }
+
+    /**
+     * Gets the band that has the most effect on the given frequency.
+     * @param frequency Frequency in milliHertz which is to be equalized via the returned band.
+     * @return Frequency band that has most effect on the given frequency.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public int getBand(int frequency)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[2];
+        int[] result = new int[1];
+
+        param[0] = PARAM_GET_BAND;
+        param[1] = frequency;
+        checkStatus(getParameter(param, result));
+
+        return result[0];
+    }
+
+    /**
+     * Gets current preset.
+     * @return Preset that is set at the moment.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getCurrentPreset()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_CURRENT_PRESET;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Sets the equalizer according to the given preset.
+     * @param preset New preset that will be taken into use. The valid range is [0,
+     * number of presets-1]. See {@see #getNumberOfPresets()}.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void usePreset(short preset)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_CURRENT_PRESET, preset));
+    }
+
+    /**
+     * Gets the total number of presets the equalizer supports. The presets will have indices
+     * [0, number of presets-1].
+     * @return The number of presets the equalizer supports.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getNumberOfPresets()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_GET_NUM_OF_PRESETS;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * Gets the preset name based on the index.
+     * @param preset Index of the preset. The valid range is [0, number of presets-1].
+     * @return A string containing the name of the given preset.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public String getPresetName(short preset)
+    {
+        if (preset >= 0 && preset < mNumPresets) {
+            return mPresetNames[preset];
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the Equalizer when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * Equalizer engine.
+         * @param effect the Equalizer on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param1 ID of the modified parameter. See {@link #PARAM_BAND_LEVEL} ...
+         * @param param2 additional parameter qualifier (e.g the band for band level parameter).
+         * @param value the new parameter value.
+         */
+        void onParameterChange(Equalizer effect, int status, int param1, int param2, int value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p1 = -1;
+                int p2 = -1;
+                int v = -1;
+
+                if (param.length >= 4) {
+                    p1 = byteArrayToInt(param, 0);
+                    if (param.length >= 8) {
+                        p2 = byteArrayToInt(param, 4);
+                    }
+                }
+                if (value.length == 2) {
+                    v = (int)byteArrayToShort(value, 0);;
+                } else if (value.length == 4) {
+                    v = byteArrayToInt(value, 0);
+                }
+
+                if (p1 != -1 && v != -1) {
+                    l.onParameterChange(Equalizer.this, status, p1, p2, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+
+}
diff --git a/media/java/android/media/PresetReverb.java b/media/java/android/media/PresetReverb.java
new file mode 100644
index 0000000..83a01a4
--- /dev/null
+++ b/media/java/android/media/PresetReverb.java
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * A sound generated within a room travels in many directions. The listener first hears the
+ * direct sound from the source itself. Later, he or she hears discrete echoes caused by sound
+ * bouncing off nearby walls, the ceiling and the floor. As sound waves arrive after
+ * undergoing more and more reflections, individual reflections become indistinguishable and
+ * the listener hears continuous reverberation that decays over time.
+ * Reverb is vital for modeling a listener's environment. It can be used in music applications
+ * to simulate music being played back in various environments, or in games to immerse the
+ * listener within the game's environment.
+ * The PresetReverb class allows an application to configure the global reverb using a reverb preset.
+ * This is primarily used for adding some reverb in a music playback context. Applications
+ * requiring control over a more advanced environmental reverb are advised to use the
+ // TODO when EnvironmentalReverb is unhidden
+ // {_at_link android.media.EnvironmentalReverb} class.
+ * <p>An application creates a PresetReverb object to instantiate and control a reverb engine in the
+ * audio framework.
+ * <p>The methods, parameter types and units exposed by the PresetReverb implementation are
+ * directly mapping those defined by the OpenSL ES 1.0.1 Specification
+ * (http://www.khronos.org/opensles/) for the SLPresetReverbItf interface.
+ * Please refer to this specification for more details.
+ * <p>The PresetReverb is an output mix auxiliary effect and should be created on
+ * Audio session 0. In order for a MediaPlayer or AudioTrack to be fed into this effect,
+ * they must be explicitely attached to it and a send level must be specified. Use the effect ID
+ * returned by getId() method to designate this particular effect when attaching it to the
+ * MediaPlayer or AudioTrack.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class PresetReverb extends AudioEffect {
+
+    private final static String TAG = "PresetReverb";
+
+    // These constants must be synchronized with those in
+    // frameworks/base/include/media/EffectPresetReverbApi.h
+
+    /**
+     * Preset. Parameter ID for
+     * {@link android.media.PresetReverb.OnParameterChangeListener}
+     */
+    public static final int PARAM_PRESET = 0;
+
+    /**
+     * Room level. Parameter ID for
+     * {@link android.media.PresetReverb.OnParameterChangeListener}
+     */
+    public static final int PRESET_NONE        = 0;
+    public static final int PRESET_SMALLROOM   = 1;
+    public static final int PRESET_MEDIUMROOM  = 2;
+    public static final int PRESET_LARGEROOM   = 3;
+    public static final int PRESET_MEDIUMHALL  = 4;
+    public static final int PRESET_LARGEHALL   = 5;
+    public static final int PRESET_PLATE       = 6;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the
+     * PresetReverb engine. As the same engine can be shared by several applications, this
+     * parameter indicates how much the requesting application needs control of effect parameters.
+     * The normal priority is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the PresetReverb will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the PresetReverb will apply to the output mix.
+     *  As the PresetReverb is an auxiliary effect it is recommended to instantiate it on
+     *  audio session 0 and to attach it to the MediaPLayer auxiliary output.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public PresetReverb(int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_PRESET_REVERB, EFFECT_TYPE_NULL, priority, audioSession);
+        Log.e(TAG, "contructor");
+    }
+
+    /**
+     *  Enables a preset on the reverb.
+     *  <p>The reverb PRESET_NONE disables any reverb from the current output but does not free the
+     *  resources associated with the reverb. For an application to signal to the implementation
+     *  to free the resources, it must call the release() method.
+     * @param preset This must be one of the the preset constants defined in this class.
+     * e.g. {@link #PRESET_SMALLROOM}
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setPreset(short preset)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_PRESET, preset));
+    }
+
+    /**
+     * Gets current reverb preset.
+     * @return Preset that is set at the moment.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getPreset()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        int[] param = new int[1];
+        param[0] = PARAM_PRESET;
+        short[] value = new short[1];
+        checkStatus(getParameter(param, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the PresetReverb
+     * when a parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * PresetReverb engine.
+         * @param effect the PresetReverb on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_PRESET} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(PresetReverb effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(PresetReverb.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/java/android/media/Virtualizer.java b/media/java/android/media/Virtualizer.java
new file mode 100644
index 0000000..9f71297
--- /dev/null
+++ b/media/java/android/media/Virtualizer.java
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import android.media.AudioEffect;
+
+/**
+ * An audio virtualizer is a general name for an effect to spatialize audio channels. The exact
+ * behavior of this effect is dependent on the number of audio input channels and the types and
+ * number of audio output channels of the device. For example, in the case of a stereo input and
+ * stereo headphone output, a stereo widening effect is used when this effect is turned on.
+ * <p>An application creates a Virtualizer object to instantiate and control a virtualizer engine
+ * in the audio framework.
+ * <p>The methods, parameter types and units exposed by the Virtualizer implementation are directly
+ * mapping those defined by the OpenSL ES 1.0.1 Specification (http://www.khronos.org/opensles/)
+ * for the SLVirtualizerItf interface. Please refer to this specification for more details.
+ * <p>To attach the Virtualizer to a particular AudioTrack or MediaPlayer, specify the audio session
+ * ID of this AudioTrack or MediaPlayer when constructing the Virtualizer. If the audio session ID 0
+ * is specified, the Virtualizer applies to the main audio output mix.
+ // TODO when AudioEffect is unhidden
+ // <p> See {_at_link android.media.AudioEffect} class for more details on controlling audio effects.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Virtualizer extends AudioEffect {
+
+    private final static String TAG = "Virtualizer";
+
+    // These constants must be synchronized with those in frameworks/base/include/media/EffectVirtualizerApi.h
+    /**
+     * Is strength parameter supported by virtualizer engine. Parameter ID for getParameter().
+     */
+    public static final int PARAM_STRENGTH_SUPPORTED = 0;
+    /**
+     * Virtualizer effect strength. Parameter ID for
+     * {@link android.media.Virtualizer.OnParameterChangeListener}
+     */
+    public static final int PARAM_STRENGTH = 1;
+
+    /**
+     * Indicates if strength parameter is supported by the virtualizer engine
+     */
+    private boolean mStrengthSupported = false;
+
+    /**
+     * Registered listener for parameter changes.
+     */
+    private OnParameterChangeListener mParamListener = null;
+
+    /**
+     * Listener used internally to to receive raw parameter change event from AudioEffect super class
+     */
+    private BaseParameterListener mBaseParamListener = null;
+
+    /**
+     * Lock for access to mParamListener
+     */
+    private final Object mParamListenerLock = new Object();
+
+    /**
+     * Class constructor.
+     * @param priority the priority level requested by the application for controlling the Virtualizer
+     * engine. As the same engine can be shared by several applications, this parameter indicates
+     * how much the requesting application needs control of effect parameters. The normal priority
+     * is 0, above normal is a positive number, below normal a negative number.
+     * @param audioSession  System wide unique audio session identifier. If audioSession
+     *  is not 0, the Virtualizer will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the Virtualizer will apply to the output mix.
+     *
+     * @throws java.lang.IllegalStateException
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+    public Virtualizer(int priority, int audioSession)
+    throws IllegalStateException, IllegalArgumentException,
+           UnsupportedOperationException, RuntimeException {
+        super(EFFECT_TYPE_VIRTUALIZER, EFFECT_TYPE_NULL, priority, audioSession);
+
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH_SUPPORTED, value));
+        mStrengthSupported = (value[0] != 0);
+    }
+
+    /**
+     * Indicates whether setting strength is supported. If this method returns false, only one
+     * strength is supported and the setStrength() method always rounds to that value.
+     * @return true is strength parameter is supported, false otherwise
+     */
+    public boolean getStrengthSupported() {
+       return mStrengthSupported;
+    }
+
+    /**
+     * Sets the strength of the virtualizer effect. If the implementation does not support per mille
+     * accuracy for setting the strength, it is allowed to round the given strength to the nearest
+     * supported value. You can use the {@link #getRoundedStrength()} method to query the
+     * (possibly rounded) value that was actually set.
+     * @param strength Strength of the effect. The valid range for strength strength is [0, 1000],
+     * where 0 per mille designates the mildest effect and 1000 per mille designates the strongest.
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public void setStrength(short strength)
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        checkStatus(setParameter(PARAM_STRENGTH, strength));
+    }
+
+    /**
+     * Gets the current strength of the effect.
+     * @return The strength of the effect. The valid range for strength is [0, 1000], where 0 per
+     * mille designates the mildest effect and 1000 per mille the strongest
+     * @throws IllegalStateException
+     * @throws IllegalArgumentException
+     * @throws UnsupportedOperationException
+     */
+    public short getRoundedStrength()
+    throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+        short[] value = new short[1];
+        checkStatus(getParameter(PARAM_STRENGTH, value));
+        return value[0];
+    }
+
+    /**
+     * The OnParameterChangeListener interface defines a method called by the Virtualizer when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Method called when a parameter value has changed. The method is called only if the
+         * parameter was changed by another application having the control of the same
+         * Virtualizer engine.
+         * @param effect the Virtualizer on which the interface is registered.
+         * @param status status of the set parameter operation.
+         // TODO when AudioEffect is unhidden
+         // See {_at_link android.media.AudioEffect#setParameter(byte[], byte[])}.
+         * @param param ID of the modified parameter. See {@link #PARAM_STRENGTH} ...
+         * @param value the new parameter value.
+         */
+        void onParameterChange(Virtualizer effect, int status, int param, short value);
+    }
+
+    /**
+     * Listener used internally to receive unformatted parameter change events from AudioEffect
+     * super class.
+     */
+    private class BaseParameterListener implements AudioEffect.OnParameterChangeListener {
+        private BaseParameterListener() {
+
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            OnParameterChangeListener l = null;
+
+            synchronized (mParamListenerLock) {
+                if (mParamListener != null) {
+                    l = mParamListener;
+                }
+            }
+            if (l != null) {
+                int p = -1;
+                short v = -1;
+
+                if (param.length == 4) {
+                    p = byteArrayToInt(param, 0);
+                }
+                if (value.length == 2) {
+                    v = byteArrayToShort(value, 0);
+                }
+                if (p != -1 && v != -1) {
+                    l.onParameterChange(Virtualizer.this, status, p, v);
+                }
+            }
+        }
+    }
+
+    /**
+     * Registers an OnParameterChangeListener interface.
+     * @param listener OnParameterChangeListener interface registered
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mParamListenerLock) {
+            if (mParamListener == null) {
+                mParamListener = listener;
+                mBaseParamListener = new BaseParameterListener();
+                super.setParameterListener(mBaseParamListener);
+            }
+        }
+    }
+}
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index ada252c..5c87f23 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -57,7 +57,7 @@
 
 // Google auxiliary preset reverb UUID: 63909320-53a6-11df-bdbd-0002a5d5c51b
 static const effect_descriptor_t gAuxPresetReverbDescriptor = {
-        {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0x63909320, 0x53a6, 0x11df, 0xbdbd, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_API_VERSION,
         EFFECT_FLAG_TYPE_AUXILIARY,
@@ -69,7 +69,7 @@
 
 // Google insert preset reverb UUID: d93dc6a0-6342-11df-b128-0002a5d5c51b
 static const effect_descriptor_t gInsertPresetReverbDescriptor = {
-        {0x47382d60, 0xddd8, 0x4763, 0x11db, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0xd93dc6a0, 0x6342, 0x11df, 0xb128, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_API_VERSION,
         EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST,
@@ -196,7 +196,7 @@
     pReverb = (reverb_object_t*) &pRvbModule->context;
 
     //if bypassed or the preset forces the signal to be completely dry
-    if (pReverb->m_bBypass) {
+    if (pReverb->m_bBypass != 0) {
         if (inBuffer->raw != outBuffer->raw) {
             int16_t smp;
             pSrc = inBuffer->s16;
@@ -520,7 +520,7 @@
         pReverb->m_bUseNoise = true;
 
         // for debugging purposes, allow bypass
-        pReverb->m_bBypass = false;
+        pReverb->m_bBypass = 0;
 
         pReverb->m_nNextRoom = 1;
 
@@ -662,248 +662,254 @@
     int32_t temp2;
     size_t size;
 
-    if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-    if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case REVERB_PARAM_ROOM_LEVEL:
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-    case REVERB_PARAM_DECAY_HF_RATIO:
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-    case REVERB_PARAM_REVERB_LEVEL:
-    case REVERB_PARAM_DIFFUSION:
-    case REVERB_PARAM_DENSITY:
+    if (pReverb->m_Preset) {
+        if (param != REVERB_PARAM_PRESET || *pSize < sizeof(int16_t)) {
+            return -EINVAL;
+        }
         size = sizeof(int16_t);
-        break;
-
-    case REVERB_PARAM_BYPASS:
-    case REVERB_PARAM_PRESET:
-    case REVERB_PARAM_DECAY_TIME:
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-    case REVERB_PARAM_REVERB_DELAY:
-        size = sizeof(int32_t);
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        size = sizeof(t_reverb_properties);
-        break;
-
-    default:
-        return -EINVAL;
-    }
-
-    if (*pSize < size) {
-        return -EINVAL;
-    }
-    *pSize = size;
-    pValue32 = (int32_t *) pValue;
-    pValue16 = (int16_t *) pValue;
-    pProperties = (t_reverb_properties *) pValue;
-
-    switch (param) {
-    case REVERB_PARAM_BYPASS:
-        *(int32_t *) pValue = (int32_t) pReverb->m_bBypass;
-        break;
-    case REVERB_PARAM_PRESET:
-        *(int32_t *) pValue = (int8_t) pReverb->m_nCurrentRoom;
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        pValue16 = &pProperties->roomLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_LEVEL:
-        // Convert m_nRoomLpfFwd to millibels
-        temp = (pReverb->m_nRoomLpfFwd << 15)
-                / (32767 - pReverb->m_nRoomLpfFbk);
-        *pValue16 = Effects_Linear16ToMillibels(temp);
-
-        LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
-        if (param == REVERB_PARAM_ROOM_LEVEL) {
-            break;
-        }
-        pValue16 = &pProperties->roomHFLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-        // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
-        // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
-        // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
-        // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-
-        temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
-        temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
-                << 1;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
-        temp = 32767 + temp - temp2;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
-        temp = Effects_Sqrt(temp) * 181;
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
-        temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
-
-        LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-
-        *pValue16 = Effects_Linear16ToMillibels(temp);
-
-        if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->decayTime;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_TIME:
-        // Calculate reverb feedback path gain
-        temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
-        temp = Effects_Linear16ToMillibels(temp);
-
-        // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
-        temp = (-6000 * pReverb->m_nLateDelay) / temp;
-
-        // Convert samples to ms
-        *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
-
-        if (param == REVERB_PARAM_DECAY_TIME) {
-            break;
-        }
-        pValue16 = &pProperties->decayHFRatio;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_HF_RATIO:
-        // If r is the decay HF ratio  (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
-        //       DT_5000Hz = DT_0Hz * r
-        //  and  G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
-        // r = G_0Hz/G_5000Hz in millibels
-        // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
-        // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
-        // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
-        // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
-        if (pReverb->m_nRvbLpfFbk == 0) {
-            *pValue16 = 1000;
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+        pValue16 = (int16_t *)pValue;
+        // REVERB_PRESET_NONE is mapped to bypass
+        if (pReverb->m_bBypass != 0) {
+            *pValue16 = (int16_t)REVERB_PRESET_NONE;
         } else {
-            temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
-            temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+            *pValue16 = (int16_t)(pReverb->m_nNextRoom + 1);
+        }
+        LOGV("get REVERB_PARAM_PRESET, preset %d", *pValue16);
+    } else {
+        switch (param) {
+        case REVERB_PARAM_ROOM_LEVEL:
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+        case REVERB_PARAM_DECAY_HF_RATIO:
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+        case REVERB_PARAM_REVERB_LEVEL:
+        case REVERB_PARAM_DIFFUSION:
+        case REVERB_PARAM_DENSITY:
+            size = sizeof(int16_t);
+            break;
+
+        case REVERB_PARAM_BYPASS:
+        case REVERB_PARAM_DECAY_TIME:
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+        case REVERB_PARAM_REVERB_DELAY:
+            size = sizeof(int32_t);
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            size = sizeof(t_reverb_properties);
+            break;
+
+        default:
+            return -EINVAL;
+        }
+
+        if (*pSize < size) {
+            return -EINVAL;
+        }
+
+        pValue32 = (int32_t *) pValue;
+        pValue16 = (int16_t *) pValue;
+        pProperties = (t_reverb_properties *) pValue;
+
+        switch (param) {
+        case REVERB_PARAM_BYPASS:
+            *pValue32 = (int32_t) pReverb->m_bBypass;
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            pValue16 = &pProperties->roomLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_LEVEL:
+            // Convert m_nRoomLpfFwd to millibels
+            temp = (pReverb->m_nRoomLpfFwd << 15)
+                    / (32767 - pReverb->m_nRoomLpfFbk);
+            *pValue16 = Effects_Linear16ToMillibels(temp);
+
+            LOGV("get REVERB_PARAM_ROOM_LEVEL %d, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", *pValue16, temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+            if (param == REVERB_PARAM_ROOM_LEVEL) {
+                break;
+            }
+            pValue16 = &pProperties->roomHFLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+            // The ratio between linear gain at 0Hz and at 5000Hz for the room low pass is:
+            // (1 + a1) / sqrt(a1^2 + 2*C*a1 + 1) where:
+            // - a1 is minus the LP feedback gain: -pReverb->m_nRoomLpfFbk
+            // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+
+            temp = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFbk);
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 %d", temp);
+            temp2 = MULT_EG1_EG1(pReverb->m_nRoomLpfFbk, pReverb->m_nCosWT_5KHz)
                     << 1;
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, 2 Cos a1 %d", temp2);
             temp = 32767 + temp - temp2;
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, a1^2 + 2 Cos a1 + 1 %d", temp);
             temp = Effects_Sqrt(temp) * 181;
-            temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
-            // The linear gain at 0Hz is b0 / (a1 + 1)
-            temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
-                    - pReverb->m_nRvbLpfFbk);
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, SQRT(a1^2 + 2 Cos a1 + 1) %d", temp);
+            temp = ((32767 - pReverb->m_nRoomLpfFbk) << 15) / temp;
 
+            LOGV("get REVERB_PARAM_ROOM_HF_LEVEL, gain %d, m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+
+            *pValue16 = Effects_Linear16ToMillibels(temp);
+
+            if (param == REVERB_PARAM_ROOM_HF_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->decayTime;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_TIME:
+            // Calculate reverb feedback path gain
+            temp = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
             temp = Effects_Linear16ToMillibels(temp);
-            temp2 = Effects_Linear16ToMillibels(temp2);
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
 
-            if (temp == 0)
-                temp = 1;
-            temp = (int16_t) ((1000 * temp2) / temp);
+            // Calculate decay time: g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+            temp = (-6000 * pReverb->m_nLateDelay) / temp;
+
+            // Convert samples to ms
+            *pValue32 = (temp * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_DECAY_TIME, samples %d, ms %d", temp, *pValue32);
+
+            if (param == REVERB_PARAM_DECAY_TIME) {
+                break;
+            }
+            pValue16 = &pProperties->decayHFRatio;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_HF_RATIO:
+            // If r is the decay HF ratio  (r = REVERB_PARAM_DECAY_HF_RATIO/1000) we have:
+            //       DT_5000Hz = DT_0Hz * r
+            //  and  G_5000Hz = -6000 * d / DT_5000Hz and G_0Hz = -6000 * d / DT_0Hz in millibels so :
+            // r = G_0Hz/G_5000Hz in millibels
+            // The linear gain at 5000Hz is b0 / sqrt(a1^2 + 2*C*a1 + 1) where:
+            // - a1 is minus the LP feedback gain: -pReverb->m_nRvbLpfFbk
+            // - b0 is the LP forward gain: pReverb->m_nRvbLpfFwd
+            // - C is cos(2piWT) @ 5000Hz: pReverb->m_nCosWT_5KHz
+            if (pReverb->m_nRvbLpfFbk == 0) {
+                *pValue16 = 1000;
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, pReverb->m_nRvbLpfFbk == 0, ratio %d", *pValue16);
+            } else {
+                temp = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFbk);
+                temp2 = MULT_EG1_EG1(pReverb->m_nRvbLpfFbk, pReverb->m_nCosWT_5KHz)
+                        << 1;
+                temp = 32767 + temp - temp2;
+                temp = Effects_Sqrt(temp) * 181;
+                temp = (pReverb->m_nRvbLpfFwd << 15) / temp;
+                // The linear gain at 0Hz is b0 / (a1 + 1)
+                temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767
+                        - pReverb->m_nRvbLpfFbk);
+
+                temp = Effects_Linear16ToMillibels(temp);
+                temp2 = Effects_Linear16ToMillibels(temp2);
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, gain 5KHz %d mB, gain DC %d mB", temp, temp2);
+
+                if (temp == 0)
+                    temp = 1;
+                temp = (int16_t) ((1000 * temp2) / temp);
+                if (temp > 1000)
+                    temp = 1000;
+
+                *pValue16 = temp;
+                LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
+            }
+
+            if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+                break;
+            }
+            pValue16 = &pProperties->reflectionsLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+            *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
+
+            LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
+            if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->reflectionsDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+            // convert samples to ms
+            *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
+
+            if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
+                break;
+            }
+            pValue16 = &pProperties->reverbLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_LEVEL:
+            // Convert linear gain to millibels
+            *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
+
+            LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
+
+            if (param == REVERB_PARAM_REVERB_LEVEL) {
+                break;
+            }
+            pValue32 = &pProperties->reverbDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_DELAY:
+            // convert samples to ms
+            *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
+
+            LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
+
+            if (param == REVERB_PARAM_REVERB_DELAY) {
+                break;
+            }
+            pValue16 = &pProperties->diffusion;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DIFFUSION:
+            temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
+                    / AP0_GAIN_RANGE);
+
+            if (temp < 0)
+                temp = 0;
             if (temp > 1000)
                 temp = 1000;
 
             *pValue16 = temp;
-            LOGV("get REVERB_PARAM_DECAY_HF_RATIO, ratio %d", *pValue16);
-        }
+            LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
 
-        if (param == REVERB_PARAM_DECAY_HF_RATIO) {
+            if (param == REVERB_PARAM_DIFFUSION) {
+                break;
+            }
+            pValue16 = &pProperties->density;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DENSITY:
+            // Calculate AP delay in time units
+            temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
+                    / pReverb->m_nSamplingRate;
+
+            temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
+
+            if (temp < 0)
+                temp = 0;
+            if (temp > 1000)
+                temp = 1000;
+
+            *pValue16 = temp;
+
+            LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
+            break;
+
+        default:
             break;
         }
-        pValue16 = &pProperties->reflectionsLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-        *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nEarlyGain);
-
-        LOGV("get REVERB_PARAM_REFLECTIONS_LEVEL, %d", *pValue16);
-        if (param == REVERB_PARAM_REFLECTIONS_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->reflectionsDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-        // convert samples to ms
-        *pValue32 = (pReverb->m_nEarlyDelay * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_REFLECTIONS_DELAY, samples %d, ms %d", pReverb->m_nEarlyDelay, *pValue32);
-
-        if (param == REVERB_PARAM_REFLECTIONS_DELAY) {
-            break;
-        }
-        pValue16 = &pProperties->reverbLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_LEVEL:
-        // Convert linear gain to millibels
-        *pValue16 = Effects_Linear16ToMillibels(pReverb->m_nLateGain << 2);
-
-        LOGV("get REVERB_PARAM_REVERB_LEVEL %d", *pValue16);
-
-        if (param == REVERB_PARAM_REVERB_LEVEL) {
-            break;
-        }
-        pValue32 = &pProperties->reverbDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_DELAY:
-        // convert samples to ms
-        *pValue32 = (pReverb->m_nLateDelay * 1000) / pReverb->m_nSamplingRate;
-
-        LOGV("get REVERB_PARAM_REVERB_DELAY, samples %d, ms %d", pReverb->m_nLateDelay, *pValue32);
-
-        if (param == REVERB_PARAM_REVERB_DELAY) {
-            break;
-        }
-        pValue16 = &pProperties->diffusion;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DIFFUSION:
-        temp = (int16_t) ((1000 * (pReverb->m_sAp0.m_nApGain - AP0_GAIN_BASE))
-                / AP0_GAIN_RANGE);
-
-        if (temp < 0)
-            temp = 0;
-        if (temp > 1000)
-            temp = 1000;
-
-        *pValue16 = temp;
-        LOGV("get REVERB_PARAM_DIFFUSION, %d, AP0 gain %d", *pValue16, pReverb->m_sAp0.m_nApGain);
-
-        if (param == REVERB_PARAM_DIFFUSION) {
-            break;
-        }
-        pValue16 = &pProperties->density;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DENSITY:
-        // Calculate AP delay in time units
-        temp = ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn) << 16)
-                / pReverb->m_nSamplingRate;
-
-        temp = (int16_t) ((1000 * (temp - AP0_TIME_BASE)) / AP0_TIME_RANGE);
-
-        if (temp < 0)
-            temp = 0;
-        if (temp > 1000)
-            temp = 1000;
-
-        *pValue16 = temp;
-
-        LOGV("get REVERB_PARAM_DENSITY, %d, AP0 delay smps %d", *pValue16, pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn);
-        break;
-
-    default:
-        break;
     }
 
+    *pSize = size;
+
     LOGV("Reverb_getParameter, context %p, param %d, value %d",
             pReverb, param, *(int *)pValue);
 
@@ -945,382 +951,386 @@
     LOGV("Reverb_setParameter, context %p, param %d, value16 %d, value32 %d",
             pReverb, param, *(int16_t *)pValue, *(int32_t *)pValue);
 
-    if (pReverb->m_Preset && param != REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-    if (!pReverb->m_Preset && param == REVERB_PARAM_PRESET) {
-        return -EINVAL;
-    }
-
-    switch (param) {
-    case REVERB_PARAM_ROOM_LEVEL:
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-    case REVERB_PARAM_DECAY_HF_RATIO:
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-    case REVERB_PARAM_REVERB_LEVEL:
-    case REVERB_PARAM_DIFFUSION:
-    case REVERB_PARAM_DENSITY:
-        paramSize = sizeof(int16_t);
-        break;
-
-    case REVERB_PARAM_BYPASS:
-    case REVERB_PARAM_PRESET:
-    case REVERB_PARAM_DECAY_TIME:
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-    case REVERB_PARAM_REVERB_DELAY:
-        paramSize = sizeof(int32_t);
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        paramSize = sizeof(t_reverb_properties);
-        break;
-
-    default:
-        return -EINVAL;
-    }
-
-    if (size != paramSize) {
-        return -EINVAL;
-    }
-
-    if (paramSize == sizeof(int16_t)) {
-        value16 = *(int16_t *) pValue;
-    } else if (paramSize == sizeof(int32_t)) {
-        value32 = *(int32_t *) pValue;
-    } else {
-        pProperties = (t_reverb_properties *) pValue;
-    }
-
-    pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nCurrentRoom];
-
-    switch (param) {
-    case REVERB_PARAM_BYPASS:
-        pReverb->m_bBypass = (uint16_t)value32;
-        break;
-    case REVERB_PARAM_PRESET:
-        if (value32 != REVERB_PRESET_LARGE_HALL && value32
-                != REVERB_PRESET_HALL && value32 != REVERB_PRESET_CHAMBER
-                && value32 != REVERB_PRESET_ROOM)
+    if (pReverb->m_Preset) {
+        if (param != REVERB_PARAM_PRESET || size != sizeof(int16_t)) {
             return -EINVAL;
-        pReverb->m_nNextRoom = (int16_t) value32;
-        break;
-
-    case REVERB_PARAM_PROPERTIES:
-        value16 = pProperties->roomLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_LEVEL:
-        // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
-        if (value16 > 0)
-            return -EINVAL;
-
-        temp = Effects_MillibelsToLinear16(value16);
-
-        pReverb->m_nRoomLpfFwd
-                = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
-
-        LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
-        if (param == REVERB_PARAM_ROOM_LEVEL)
-            break;
-        value16 = pProperties->roomHFLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_ROOM_HF_LEVEL:
-
-        // Limit to 0 , -40dB range because of low pass implementation
-        if (value16 > 0 || value16 < -4000)
-            return -EINVAL;
-        // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
-        // m_nRoomLpfFbk is -a1 where a1 is the solution of:
-        // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
-        // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
-        // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
-
-        // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
-        // while changing HF level
-        temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
-                - pReverb->m_nRoomLpfFbk);
-        if (value16 == 0) {
-            pReverb->m_nRoomLpfFbk = 0;
-        } else {
-            int32_t dG2, b, delta;
-
-            // dG^2
-            temp = Effects_MillibelsToLinear16(value16);
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
-            temp = (1 << 30) / temp;
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
-            dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
-            // b = 2*(C-dG^2)/(1-dG^2)
-            b = (int32_t) ((((int64_t) 1 << (15 + 1))
-                    * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
-                    / ((int64_t) 32767 - (int64_t) dG2));
-
-            // delta = b^2 - 4
-            delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
-                    + 2)));
-
-            LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
-
-            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
-            // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
-            pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
         }
-        LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
-                temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
-
-        pReverb->m_nRoomLpfFwd
-                = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
-        LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
-
-        if (param == REVERB_PARAM_ROOM_HF_LEVEL)
-            break;
-        value32 = pProperties->decayTime;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_TIME:
-
-        // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
-        // convert ms to samples
-        value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
-
-        // calculate valid decay time range as a function of current reverb delay and
-        // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
-        // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
-        // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
-        averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
-        averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
-                + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
-
-        temp = (-6000 * averageDelay) / value32;
-        LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
-        if (temp < -4000 || temp > -100)
+        value16 = *(int16_t *)pValue;
+        LOGV("set REVERB_PARAM_PRESET, preset %d", value16);
+        if (value16 < REVERB_PRESET_NONE || value16 > REVERB_PRESET_PLATE) {
             return -EINVAL;
-
-        // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
-        // xfade and sum gain (max +9dB)
-        temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
-        temp = Effects_MillibelsToLinear16(temp);
-
-        // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
-        pReverb->m_nRvbLpfFwd
-                = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
-
-        LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
-
-        if (param == REVERB_PARAM_DECAY_TIME)
-            break;
-        value16 = pProperties->decayHFRatio;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DECAY_HF_RATIO:
-
-        // We limit max value to 1000 because reverb filter is lowpass only
-        if (value16 < 100 || value16 > 1000)
-            return -EINVAL;
-        // Convert per mille to => m_nLpfFwd, m_nLpfFbk
-
-        // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
-        // while changing HF level
-        temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
-
-        if (value16 == 1000) {
-            pReverb->m_nRvbLpfFbk = 0;
+        }
+        // REVERB_PRESET_NONE is mapped to bypass
+        if (value16 == REVERB_PRESET_NONE) {
+            pReverb->m_bBypass = 1;
         } else {
-            int32_t dG2, b, delta;
+            pReverb->m_bBypass = 0;
+            pReverb->m_nNextRoom = value16 - 1;
+        }
+    } else {
+        switch (param) {
+        case REVERB_PARAM_ROOM_LEVEL:
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+        case REVERB_PARAM_DECAY_HF_RATIO:
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+        case REVERB_PARAM_REVERB_LEVEL:
+        case REVERB_PARAM_DIFFUSION:
+        case REVERB_PARAM_DENSITY:
+            paramSize = sizeof(int16_t);
+            break;
 
-            temp = Effects_Linear16ToMillibels(temp2);
-            // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+        case REVERB_PARAM_BYPASS:
+        case REVERB_PARAM_DECAY_TIME:
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+        case REVERB_PARAM_REVERB_DELAY:
+            paramSize = sizeof(int32_t);
+            break;
 
-            value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+        case REVERB_PARAM_PROPERTIES:
+            paramSize = sizeof(t_reverb_properties);
+            break;
 
-            temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+        default:
+            return -EINVAL;
+        }
 
-            if (temp < -4000) {
-                LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
-                temp = -4000;
+        if (size != paramSize) {
+            return -EINVAL;
+        }
+
+        if (paramSize == sizeof(int16_t)) {
+            value16 = *(int16_t *) pValue;
+        } else if (paramSize == sizeof(int32_t)) {
+            value32 = *(int32_t *) pValue;
+        } else {
+            pProperties = (t_reverb_properties *) pValue;
+        }
+
+        pPreset = &pReverb->m_sPreset.m_sPreset[pReverb->m_nNextRoom];
+
+        switch (param) {
+        case REVERB_PARAM_BYPASS:
+            pReverb->m_bBypass = (uint16_t)value32;
+            break;
+
+        case REVERB_PARAM_PROPERTIES:
+            value16 = pProperties->roomLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_LEVEL:
+            // Convert millibels to linear 16 bit signed => m_nRoomLpfFwd
+            if (value16 > 0)
+                return -EINVAL;
+
+            temp = Effects_MillibelsToLinear16(value16);
+
+            pReverb->m_nRoomLpfFwd
+                    = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRoomLpfFbk));
+
+            LOGV("REVERB_PARAM_ROOM_LEVEL, gain %d, new m_nRoomLpfFwd %d, m_nRoomLpfFbk %d", temp, pReverb->m_nRoomLpfFwd, pReverb->m_nRoomLpfFbk);
+            if (param == REVERB_PARAM_ROOM_LEVEL)
+                break;
+            value16 = pProperties->roomHFLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_ROOM_HF_LEVEL:
+
+            // Limit to 0 , -40dB range because of low pass implementation
+            if (value16 > 0 || value16 < -4000)
+                return -EINVAL;
+            // Convert attenuation @ 5000H expressed in millibels to => m_nRoomLpfFbk
+            // m_nRoomLpfFbk is -a1 where a1 is the solution of:
+            // a1^2 + 2*(C-dG^2)/(1-dG^2)*a1 + 1 = 0 where:
+            // - C is cos(2*pi*5000/Fs) (pReverb->m_nCosWT_5KHz)
+            // - dG is G0/Gf (G0 is the linear gain at DC and Gf is the wanted gain at 5000Hz)
+
+            // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+            // while changing HF level
+            temp2 = (pReverb->m_nRoomLpfFwd << 15) / (32767
+                    - pReverb->m_nRoomLpfFbk);
+            if (value16 == 0) {
+                pReverb->m_nRoomLpfFbk = 0;
+            } else {
+                int32_t dG2, b, delta;
+
+                // dG^2
+                temp = Effects_MillibelsToLinear16(value16);
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, HF gain %d", temp);
+                temp = (1 << 30) / temp;
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain %d", temp);
+                dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, 1/ HF gain ^ 2 %d", dG2);
+                // b = 2*(C-dG^2)/(1-dG^2)
+                b = (int32_t) ((((int64_t) 1 << (15 + 1))
+                        * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+                        / ((int64_t) 32767 - (int64_t) dG2));
+
+                // delta = b^2 - 4
+                delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+                        + 2)));
+
+                LOGV_IF(delta > (1<<30), " delta overflow %d", delta);
+
+                LOGV("REVERB_PARAM_ROOM_HF_LEVEL, dG2 %d, b %d, delta %d, m_nCosWT_5KHz %d", dG2, b, delta, pReverb->m_nCosWT_5KHz);
+                // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+                pReverb->m_nRoomLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+            }
+            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, olg DC gain %d new m_nRoomLpfFbk %d, old m_nRoomLpfFwd %d",
+                    temp2, pReverb->m_nRoomLpfFbk, pReverb->m_nRoomLpfFwd);
+
+            pReverb->m_nRoomLpfFwd
+                    = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRoomLpfFbk));
+            LOGV("REVERB_PARAM_ROOM_HF_LEVEL, new m_nRoomLpfFwd %d", pReverb->m_nRoomLpfFwd);
+
+            if (param == REVERB_PARAM_ROOM_HF_LEVEL)
+                break;
+            value32 = pProperties->decayTime;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_TIME:
+
+            // Convert milliseconds to => m_nRvbLpfFwd (function of m_nRvbLpfFbk)
+            // convert ms to samples
+            value32 = (value32 * pReverb->m_nSamplingRate) / 1000;
+
+            // calculate valid decay time range as a function of current reverb delay and
+            // max feed back gain. Min value <=> -40dB in one pass, Max value <=> feedback gain = -1 dB
+            // Calculate attenuation for each round in late reverb given a total attenuation of -6000 millibels.
+            // g = -6000 d/DT , g gain in millibels, d reverb delay, DT decay time
+            averageDelay = pReverb->m_nLateDelay - pReverb->m_nMaxExcursion;
+            averageDelay += ((pReverb->m_sAp0.m_zApOut - pReverb->m_sAp0.m_zApIn)
+                    + (pReverb->m_sAp1.m_zApOut - pReverb->m_sAp1.m_zApIn)) >> 1;
+
+            temp = (-6000 * averageDelay) / value32;
+            LOGV("REVERB_PARAM_DECAY_TIME, delay smps %d, DT smps %d, gain mB %d",averageDelay, value32, temp);
+            if (temp < -4000 || temp > -100)
+                return -EINVAL;
+
+            // calculate low pass gain by adding reverb input attenuation (pReverb->m_nLateGain) and substrating output
+            // xfade and sum gain (max +9dB)
+            temp -= Effects_Linear16ToMillibels(pReverb->m_nLateGain) + 900;
+            temp = Effects_MillibelsToLinear16(temp);
+
+            // DC gain (temp) = b0 / (1 + a1) = pReverb->m_nRvbLpfFwd / (32767 - pReverb->m_nRvbLpfFbk)
+            pReverb->m_nRvbLpfFwd
+                    = MULT_EG1_EG1(temp, (32767 - pReverb->m_nRvbLpfFbk));
+
+            LOGV("REVERB_PARAM_DECAY_TIME, gain %d, new m_nRvbLpfFwd %d, old m_nRvbLpfFbk %d, reverb gain %d", temp, pReverb->m_nRvbLpfFwd, pReverb->m_nRvbLpfFbk, Effects_Linear16ToMillibels(pReverb->m_nLateGain));
+
+            if (param == REVERB_PARAM_DECAY_TIME)
+                break;
+            value16 = pProperties->decayHFRatio;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DECAY_HF_RATIO:
+
+            // We limit max value to 1000 because reverb filter is lowpass only
+            if (value16 < 100 || value16 > 1000)
+                return -EINVAL;
+            // Convert per mille to => m_nLpfFwd, m_nLpfFbk
+
+            // Save current DC gain m_nRoomLpfFwd / (32767 - m_nRoomLpfFbk) to keep it unchanged
+            // while changing HF level
+            temp2 = (pReverb->m_nRvbLpfFwd << 15) / (32767 - pReverb->m_nRvbLpfFbk);
+
+            if (value16 == 1000) {
+                pReverb->m_nRvbLpfFbk = 0;
+            } else {
+                int32_t dG2, b, delta;
+
+                temp = Effects_Linear16ToMillibels(temp2);
+                // G_5000Hz = G_DC * (1000/REVERB_PARAM_DECAY_HF_RATIO) in millibels
+
+                value32 = ((int32_t) 1000 << 15) / (int32_t) value16;
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, DC gain %d, DC gain mB %d, 1000/R %d", temp2, temp, value32);
+
+                temp = (int32_t) (((int64_t) temp * (int64_t) value32) >> 15);
+
+                if (temp < -4000) {
+                    LOGV("REVERB_PARAM_DECAY_HF_RATIO HF gain overflow %d mB", temp);
+                    temp = -4000;
+                }
+
+                temp = Effects_MillibelsToLinear16(temp);
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
+                // dG^2
+                temp = (temp2 << 15) / temp;
+                dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+
+                // b = 2*(C-dG^2)/(1-dG^2)
+                b = (int32_t) ((((int64_t) 1 << (15 + 1))
+                        * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
+                        / ((int64_t) 32767 - (int64_t) dG2));
+
+                // delta = b^2 - 4
+                delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
+                        + 2)));
+
+                // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
+                pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+
+                LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+
             }
 
-            temp = Effects_MillibelsToLinear16(temp);
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, HF gain %d", temp);
-            // dG^2
-            temp = (temp2 << 15) / temp;
-            dG2 = (int32_t) (((int64_t) temp * (int64_t) temp) >> 15);
+            LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
 
-            // b = 2*(C-dG^2)/(1-dG^2)
-            b = (int32_t) ((((int64_t) 1 << (15 + 1))
-                    * ((int64_t) pReverb->m_nCosWT_5KHz - (int64_t) dG2))
-                    / ((int64_t) 32767 - (int64_t) dG2));
+            pReverb->m_nRvbLpfFwd
+                    = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
 
-            // delta = b^2 - 4
-            delta = (int32_t) ((((int64_t) b * (int64_t) b) >> 15) - (1 << (15
-                    + 2)));
+            if (param == REVERB_PARAM_DECAY_HF_RATIO)
+                break;
+            value16 = pProperties->reflectionsLevel;
+            /* FALL THROUGH */
 
-            // m_nRoomLpfFbk = -a1 = - (- b + sqrt(delta)) / 2
-            pReverb->m_nRvbLpfFbk = (b - Effects_Sqrt(delta) * 181) >> 1;
+        case REVERB_PARAM_REFLECTIONS_LEVEL:
+            // We limit max value to 0 because gain is limited to 0dB
+            if (value16 > 0 || value16 < -6000)
+                return -EINVAL;
 
-            LOGV("REVERB_PARAM_DECAY_HF_RATIO, dG2 %d, b %d, delta %d", dG2, b, delta);
+            // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
+            value16 = Effects_MillibelsToLinear16(value16);
+            for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+                pReverb->m_sEarlyL.m_nGain[i]
+                        = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
+                pReverb->m_sEarlyR.m_nGain[i]
+                        = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
+            }
+            pReverb->m_nEarlyGain = value16;
+            LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
 
+            if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
+                break;
+            value32 = pProperties->reflectionsDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REFLECTIONS_DELAY:
+            // We limit max value MAX_EARLY_TIME
+            // convert ms to time units
+            temp = (value32 * 65536) / 1000;
+            if (temp < 0 || temp > MAX_EARLY_TIME)
+                return -EINVAL;
+
+            maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
+                    >> 16;
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
+                temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
+                        * pReverb->m_nSamplingRate) >> 16);
+                if (temp2 > maxSamples)
+                    temp2 = maxSamples;
+                pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
+                temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
+                        * pReverb->m_nSamplingRate) >> 16);
+                if (temp2 > maxSamples)
+                    temp2 = maxSamples;
+                pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
+            }
+            pReverb->m_nEarlyDelay = temp;
+
+            LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
+
+            // Convert milliseconds to sample count => m_nEarlyDelay
+            if (param == REVERB_PARAM_REFLECTIONS_DELAY)
+                break;
+            value16 = pProperties->reverbLevel;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_LEVEL:
+            // We limit max value to 0 because gain is limited to 0dB
+            if (value16 > 0 || value16 < -6000)
+                return -EINVAL;
+            // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
+            pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
+
+            LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
+
+            if (param == REVERB_PARAM_REVERB_LEVEL)
+                break;
+            value32 = pProperties->reverbDelay;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_REVERB_DELAY:
+            // We limit max value to MAX_DELAY_TIME
+            // convert ms to time units
+            temp = (value32 * 65536) / 1000;
+            if (temp < 0 || temp > MAX_DELAY_TIME)
+                return -EINVAL;
+
+            maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
+                    >> 16;
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
+                temp = maxSamples - pReverb->m_nMaxExcursion;
+            }
+            if (temp < pReverb->m_nMaxExcursion) {
+                temp = pReverb->m_nMaxExcursion;
+            }
+
+            temp -= pReverb->m_nLateDelay;
+            pReverb->m_nDelay0Out += temp;
+            pReverb->m_nDelay1Out += temp;
+            pReverb->m_nLateDelay += temp;
+
+            LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
+
+            // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
+            if (param == REVERB_PARAM_REVERB_DELAY)
+                break;
+
+            value16 = pProperties->diffusion;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DIFFUSION:
+            if (value16 < 0 || value16 > 1000)
+                return -EINVAL;
+
+            // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
+            pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
+                    * AP0_GAIN_RANGE) / 1000;
+            pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
+                    * AP1_GAIN_RANGE) / 1000;
+
+            LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
+
+            if (param == REVERB_PARAM_DIFFUSION)
+                break;
+
+            value16 = pProperties->density;
+            /* FALL THROUGH */
+
+        case REVERB_PARAM_DENSITY:
+            if (value16 < 0 || value16 > 1000)
+                return -EINVAL;
+
+            // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
+            maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
+
+            temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
+            /*lint -e{702} shift for performance */
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if (temp > maxSamples)
+                temp = maxSamples;
+            pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
+
+            LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
+
+            temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
+            /*lint -e{702} shift for performance */
+            temp = (temp * pReverb->m_nSamplingRate) >> 16;
+            if (temp > maxSamples)
+                temp = maxSamples;
+            pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
+
+            LOGV("Ap1 delay smps %d", temp);
+
+            break;
+
+        default:
+            break;
         }
-
-        LOGV("REVERB_PARAM_DECAY_HF_RATIO, gain %d, m_nRvbLpfFbk %d, m_nRvbLpfFwd %d", temp2, pReverb->m_nRvbLpfFbk, pReverb->m_nRvbLpfFwd);
-
-        pReverb->m_nRvbLpfFwd
-                = MULT_EG1_EG1(temp2, (32767 - pReverb->m_nRvbLpfFbk));
-
-        if (param == REVERB_PARAM_DECAY_HF_RATIO)
-            break;
-        value16 = pProperties->reflectionsLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_LEVEL:
-        // We limit max value to 0 because gain is limited to 0dB
-        if (value16 > 0 || value16 < -6000)
-            return -EINVAL;
-
-        // Convert millibels to linear 16 bit signed and recompute m_sEarlyL.m_nGain[i] and m_sEarlyR.m_nGain[i].
-        value16 = Effects_MillibelsToLinear16(value16);
-        for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
-            pReverb->m_sEarlyL.m_nGain[i]
-                    = MULT_EG1_EG1(pPreset->m_sEarlyL.m_nGain[i],value16);
-            pReverb->m_sEarlyR.m_nGain[i]
-                    = MULT_EG1_EG1(pPreset->m_sEarlyR.m_nGain[i],value16);
-        }
-        pReverb->m_nEarlyGain = value16;
-        LOGV("REVERB_PARAM_REFLECTIONS_LEVEL, m_nEarlyGain %d", pReverb->m_nEarlyGain);
-
-        if (param == REVERB_PARAM_REFLECTIONS_LEVEL)
-            break;
-        value32 = pProperties->reflectionsDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REFLECTIONS_DELAY:
-        // We limit max value MAX_EARLY_TIME
-        // convert ms to time units
-        temp = (value32 * 65536) / 1000;
-        if (temp < 0 || temp > MAX_EARLY_TIME)
-            return -EINVAL;
-
-        maxSamples = (int32_t) (MAX_EARLY_TIME * pReverb->m_nSamplingRate)
-                >> 16;
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        for (i = 0; i < REVERB_MAX_NUM_REFLECTIONS; i++) {
-            temp2 = temp + (((int32_t) pPreset->m_sEarlyL.m_zDelay[i]
-                    * pReverb->m_nSamplingRate) >> 16);
-            if (temp2 > maxSamples)
-                temp2 = maxSamples;
-            pReverb->m_sEarlyL.m_zDelay[i] = pReverb->m_nEarly0in + temp2;
-            temp2 = temp + (((int32_t) pPreset->m_sEarlyR.m_zDelay[i]
-                    * pReverb->m_nSamplingRate) >> 16);
-            if (temp2 > maxSamples)
-                temp2 = maxSamples;
-            pReverb->m_sEarlyR.m_zDelay[i] = pReverb->m_nEarly1in + temp2;
-        }
-        pReverb->m_nEarlyDelay = temp;
-
-        LOGV("REVERB_PARAM_REFLECTIONS_DELAY, m_nEarlyDelay smps %d max smp delay %d", pReverb->m_nEarlyDelay, maxSamples);
-
-        // Convert milliseconds to sample count => m_nEarlyDelay
-        if (param == REVERB_PARAM_REFLECTIONS_DELAY)
-            break;
-        value16 = pProperties->reverbLevel;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_LEVEL:
-        // We limit max value to 0 because gain is limited to 0dB
-        if (value16 > 0 || value16 < -6000)
-            return -EINVAL;
-        // Convert millibels to linear 16 bits (gange 0 - 8191) => m_nLateGain.
-        pReverb->m_nLateGain = Effects_MillibelsToLinear16(value16) >> 2;
-
-        LOGV("REVERB_PARAM_REVERB_LEVEL, m_nLateGain %d", pReverb->m_nLateGain);
-
-        if (param == REVERB_PARAM_REVERB_LEVEL)
-            break;
-        value32 = pProperties->reverbDelay;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_REVERB_DELAY:
-        // We limit max value to MAX_DELAY_TIME
-        // convert ms to time units
-        temp = (value32 * 65536) / 1000;
-        if (temp < 0 || temp > MAX_DELAY_TIME)
-            return -EINVAL;
-
-        maxSamples = (int32_t) (MAX_DELAY_TIME * pReverb->m_nSamplingRate)
-                >> 16;
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if ((temp + pReverb->m_nMaxExcursion) > maxSamples) {
-            temp = maxSamples - pReverb->m_nMaxExcursion;
-        }
-        if (temp < pReverb->m_nMaxExcursion) {
-            temp = pReverb->m_nMaxExcursion;
-        }
-
-        temp -= pReverb->m_nLateDelay;
-        pReverb->m_nDelay0Out += temp;
-        pReverb->m_nDelay1Out += temp;
-        pReverb->m_nLateDelay += temp;
-
-        LOGV("REVERB_PARAM_REVERB_DELAY, m_nLateDelay smps %d max smp delay %d", pReverb->m_nLateDelay, maxSamples);
-
-        // Convert milliseconds to sample count => m_nDelay1Out + m_nMaxExcursion
-        if (param == REVERB_PARAM_REVERB_DELAY)
-            break;
-
-        value16 = pProperties->diffusion;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DIFFUSION:
-        if (value16 < 0 || value16 > 1000)
-            return -EINVAL;
-
-        // Convert per mille to m_sAp0.m_nApGain, m_sAp1.m_nApGain
-        pReverb->m_sAp0.m_nApGain = AP0_GAIN_BASE + ((int32_t) value16
-                * AP0_GAIN_RANGE) / 1000;
-        pReverb->m_sAp1.m_nApGain = AP1_GAIN_BASE + ((int32_t) value16
-                * AP1_GAIN_RANGE) / 1000;
-
-        LOGV("REVERB_PARAM_DIFFUSION, m_sAp0.m_nApGain %d m_sAp1.m_nApGain %d", pReverb->m_sAp0.m_nApGain, pReverb->m_sAp1.m_nApGain);
-
-        if (param == REVERB_PARAM_DIFFUSION)
-            break;
-
-        value16 = pProperties->density;
-        /* FALL THROUGH */
-
-    case REVERB_PARAM_DENSITY:
-        if (value16 < 0 || value16 > 1000)
-            return -EINVAL;
-
-        // Convert per mille to m_sAp0.m_zApOut, m_sAp1.m_zApOut
-        maxSamples = (int32_t) (MAX_AP_TIME * pReverb->m_nSamplingRate) >> 16;
-
-        temp = AP0_TIME_BASE + ((int32_t) value16 * AP0_TIME_RANGE) / 1000;
-        /*lint -e{702} shift for performance */
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if (temp > maxSamples)
-            temp = maxSamples;
-        pReverb->m_sAp0.m_zApOut = (uint16_t) (pReverb->m_sAp0.m_zApIn + temp);
-
-        LOGV("REVERB_PARAM_DENSITY, Ap0 delay smps %d", temp);
-
-        temp = AP1_TIME_BASE + ((int32_t) value16 * AP1_TIME_RANGE) / 1000;
-        /*lint -e{702} shift for performance */
-        temp = (temp * pReverb->m_nSamplingRate) >> 16;
-        if (temp > maxSamples)
-            temp = maxSamples;
-        pReverb->m_sAp1.m_zApOut = (uint16_t) (pReverb->m_sAp1.m_zApIn + temp);
-
-        LOGV("Ap1 delay smps %d", temp);
-
-        break;
-
-    default:
-        break;
     }
+
     return 0;
 } /* end Reverb_setParameter */
 
@@ -1905,139 +1915,15 @@
  */
 static int ReverbReadInPresets(reverb_object_t *pReverb) {
 
-    int preset = 0;
-    int defaultPreset = 0;
+    int preset;
 
-    //now init any remaining presets to defaults
-    for (defaultPreset = preset; defaultPreset < REVERB_MAX_ROOM_TYPE; defaultPreset++) {
-        reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[defaultPreset];
-        if (defaultPreset == 0 || defaultPreset > REVERB_MAX_ROOM_TYPE - 1) {
-            pPreset->m_nRvbLpfFbk = 8307;
-            pPreset->m_nRvbLpfFwd = 14768;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 24569;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 2163;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6388;
-            pPreset->m_nAp0_ApGain = 15691;
-            pPreset->m_nAp0_ApOut = 711;
-            pPreset->m_nAp1_ApGain = 16317;
-            pPreset->m_nAp1_ApOut = 1029;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 1) {
-            pPreset->m_nRvbLpfFbk = 6461;
-            pPreset->m_nRvbLpfFwd = 14307;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 24569;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6391;
-            pPreset->m_nAp0_ApGain = 15230;
-            pPreset->m_nAp0_ApOut = 708;
-            pPreset->m_nAp1_ApGain = 15547;
-            pPreset->m_nAp1_ApOut = 1023;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 2) {
-            pPreset->m_nRvbLpfFbk = 5077;
-            pPreset->m_nRvbLpfFwd = 12922;
-            pPreset->m_nEarlyGain = 27690;
-            pPreset->m_nEarlyDelay = 1311;
-            pPreset->m_nLateGain = 8191;
-            pPreset->m_nLateDelay = 3932;
-            pPreset->m_nRoomLpfFbk = 3692;
-            pPreset->m_nRoomLpfFwd = 21703;
-            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
-            pPreset->m_sEarlyL.m_nGain[0] = 22152;
-            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
-            pPreset->m_sEarlyL.m_nGain[1] = 17537;
-            pPreset->m_sEarlyL.m_zDelay[2] = 0;
-            pPreset->m_sEarlyL.m_nGain[2] = 14768;
-            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
-            pPreset->m_sEarlyL.m_nGain[3] = 14307;
-            pPreset->m_sEarlyL.m_zDelay[4] = 0;
-            pPreset->m_sEarlyL.m_nGain[4] = 13384;
-            pPreset->m_sEarlyR.m_zDelay[0] = 721;
-            pPreset->m_sEarlyR.m_nGain[0] = 20306;
-            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
-            pPreset->m_sEarlyR.m_nGain[1] = 17537;
-            pPreset->m_sEarlyR.m_zDelay[2] = 0;
-            pPreset->m_sEarlyR.m_nGain[2] = 14768;
-            pPreset->m_sEarlyR.m_zDelay[3] = 0;
-            pPreset->m_sEarlyR.m_nGain[3] = 16153;
-            pPreset->m_sEarlyR.m_zDelay[4] = 0;
-            pPreset->m_sEarlyR.m_nGain[4] = 13384;
-            pPreset->m_nMaxExcursion = 127;
-            pPreset->m_nXfadeInterval = 6449;
-            pPreset->m_nAp0_ApGain = 15691;
-            pPreset->m_nAp0_ApOut = 774;
-            pPreset->m_nAp1_ApGain = 16317;
-            pPreset->m_nAp1_ApOut = 1155;
-            pPreset->m_rfu4 = 0;
-            pPreset->m_rfu5 = 0;
-            pPreset->m_rfu6 = 0;
-            pPreset->m_rfu7 = 0;
-            pPreset->m_rfu8 = 0;
-            pPreset->m_rfu9 = 0;
-            pPreset->m_rfu10 = 0;
-        } else if (defaultPreset == 3) {
+    // this is for test only. OpenSL ES presets are mapped to 4 presets.
+    // REVERB_PRESET_NONE is mapped to bypass
+    for (preset = 0; preset < REVERB_NUM_PRESETS; preset++) {
+        reverb_preset_t *pPreset = &pReverb->m_sPreset.m_sPreset[preset];
+        switch (preset + 1) {
+        case REVERB_PRESET_PLATE:
+        case REVERB_PRESET_SMALLROOM:
             pPreset->m_nRvbLpfFbk = 5077;
             pPreset->m_nRvbLpfFwd = 11076;
             pPreset->m_nEarlyGain = 27690;
@@ -2079,6 +1965,137 @@
             pPreset->m_rfu8 = 0;
             pPreset->m_rfu9 = 0;
             pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_MEDIUMROOM:
+        case REVERB_PRESET_LARGEROOM:
+            pPreset->m_nRvbLpfFbk = 5077;
+            pPreset->m_nRvbLpfFwd = 12922;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 21703;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6449;
+            pPreset->m_nAp0_ApGain = 15691;
+            pPreset->m_nAp0_ApOut = 774;
+            pPreset->m_nAp1_ApGain = 16317;
+            pPreset->m_nAp1_ApOut = 1155;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_MEDIUMHALL:
+            pPreset->m_nRvbLpfFbk = 6461;
+            pPreset->m_nRvbLpfFwd = 14307;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 24569;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 1462;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6391;
+            pPreset->m_nAp0_ApGain = 15230;
+            pPreset->m_nAp0_ApOut = 708;
+            pPreset->m_nAp1_ApGain = 15547;
+            pPreset->m_nAp1_ApOut = 1023;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
+        case REVERB_PRESET_LARGEHALL:
+            pPreset->m_nRvbLpfFbk = 8307;
+            pPreset->m_nRvbLpfFwd = 14768;
+            pPreset->m_nEarlyGain = 27690;
+            pPreset->m_nEarlyDelay = 1311;
+            pPreset->m_nLateGain = 8191;
+            pPreset->m_nLateDelay = 3932;
+            pPreset->m_nRoomLpfFbk = 3692;
+            pPreset->m_nRoomLpfFwd = 24569;
+            pPreset->m_sEarlyL.m_zDelay[0] = 1376;
+            pPreset->m_sEarlyL.m_nGain[0] = 22152;
+            pPreset->m_sEarlyL.m_zDelay[1] = 2163;
+            pPreset->m_sEarlyL.m_nGain[1] = 17537;
+            pPreset->m_sEarlyL.m_zDelay[2] = 0;
+            pPreset->m_sEarlyL.m_nGain[2] = 14768;
+            pPreset->m_sEarlyL.m_zDelay[3] = 1835;
+            pPreset->m_sEarlyL.m_nGain[3] = 14307;
+            pPreset->m_sEarlyL.m_zDelay[4] = 0;
+            pPreset->m_sEarlyL.m_nGain[4] = 13384;
+            pPreset->m_sEarlyR.m_zDelay[0] = 721;
+            pPreset->m_sEarlyR.m_nGain[0] = 20306;
+            pPreset->m_sEarlyR.m_zDelay[1] = 2621;
+            pPreset->m_sEarlyR.m_nGain[1] = 17537;
+            pPreset->m_sEarlyR.m_zDelay[2] = 0;
+            pPreset->m_sEarlyR.m_nGain[2] = 14768;
+            pPreset->m_sEarlyR.m_zDelay[3] = 0;
+            pPreset->m_sEarlyR.m_nGain[3] = 16153;
+            pPreset->m_sEarlyR.m_zDelay[4] = 0;
+            pPreset->m_sEarlyR.m_nGain[4] = 13384;
+            pPreset->m_nMaxExcursion = 127;
+            pPreset->m_nXfadeInterval = 6388;
+            pPreset->m_nAp0_ApGain = 15691;
+            pPreset->m_nAp0_ApOut = 711;
+            pPreset->m_nAp1_ApGain = 16317;
+            pPreset->m_nAp1_ApOut = 1029;
+            pPreset->m_rfu4 = 0;
+            pPreset->m_rfu5 = 0;
+            pPreset->m_rfu6 = 0;
+            pPreset->m_rfu7 = 0;
+            pPreset->m_rfu8 = 0;
+            pPreset->m_rfu9 = 0;
+            pPreset->m_rfu10 = 0;
+            break;
         }
     }
 
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index f5aadfa..5af316d 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -17,7 +17,8 @@
 #ifndef ANDROID_EFFECTREVERB_H_
 #define ANDROID_EFFECTREVERB_H_
 
-#include <media/EffectReverbApi.h>
+#include <media/EffectEnvironmentalReverbApi.h>
+#include <media/EffectPresetReverbApi.h>
 
 
 /*------------------------------------
@@ -43,7 +44,7 @@
 
 #define REVERB_BUFFER_SIZE_IN_SAMPLES_MAX   16384
 
-#define REVERB_MAX_ROOM_TYPE            4   // any room numbers larger than this are invalid
+#define REVERB_NUM_PRESETS  REVERB_PRESET_PLATE   // REVERB_PRESET_NONE is not included
 #define REVERB_MAX_NUM_REFLECTIONS      5   // max num reflections per channel
 
 
@@ -171,7 +172,7 @@
 
 typedef struct
 {
-    reverb_preset_t     m_sPreset[REVERB_MAX_ROOM_TYPE];    //array of presets
+    reverb_preset_t     m_sPreset[REVERB_NUM_PRESETS]; // array of presets(does not include REVERB_PRESET_NONE)
 
 } reverb_preset_bank_t;
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 4872047..5401ec0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -511,11 +511,17 @@
             sp<Client> c = mClients[i].promote();
             if (c != 0) c->dump(fd, args);
         }
-        for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
-            result.append(" MediaRecorderClient\n");
-            sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
-            snprintf(buffer, 255, "  pid(%d)\n\n", c->mPid);
-            result.append(buffer);
+        if (mMediaRecorderClients.size() == 0) {
+                result.append(" No media recorder client\n\n");
+        } else {
+            for (int i = 0, n = mMediaRecorderClients.size(); i < n; ++i) {
+                sp<MediaRecorderClient> c = mMediaRecorderClients[i].promote();
+                snprintf(buffer, 255, " MediaRecorderClient pid(%d)\n", c->mPid);
+                result.append(buffer);
+                write(fd, result.string(), result.size());
+                result = "\n";
+                c->dump(fd, args);
+            }
         }
 
         result.append(" Files opened and/or mapped:\n");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 80b1cfd..fef3e6e 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -329,5 +329,12 @@
     return mRecorder->setListener(listener);
 }
 
+status_t MediaRecorderClient::dump(int fd, const Vector<String16>& args) const {
+    if (mRecorder != NULL) {
+        return mRecorder->dump(fd, args);
+    }
+    return OK;
+}
+
 }; // namespace android
 
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index b53d950..d12e558 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -28,7 +28,7 @@
 class MediaRecorderClient : public BnMediaRecorder
 {
 public:
-    virtual	    status_t		setCamera(const sp<ICamera>& camera);
+    virtual     status_t        setCamera(const sp<ICamera>& camera);
     virtual     status_t        setPreviewSurface(const sp<ISurface>& surface);
     virtual     status_t        setVideoSource(int vs);
     virtual     status_t        setAudioSource(int as);
@@ -45,21 +45,22 @@
     virtual     status_t        getMaxAmplitude(int* max);
     virtual     status_t        start();
     virtual     status_t        stop();
-    virtual	    status_t        reset();
+    virtual     status_t        reset();
     virtual     status_t        init();
     virtual     status_t        close();
     virtual     status_t        release();
 
+    virtual     status_t        dump(int fd, const Vector<String16>& args) const;
 private:
-    friend class                 MediaPlayerService;  // for accessing private constructor
+    friend class                MediaPlayerService;  // for accessing private constructor
 
-                                 MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
-    virtual 		         ~MediaRecorderClient();
+                                MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid);
+    virtual                     ~MediaRecorderClient();
 
-    pid_t			 mPid;
-    Mutex			 mLock;
-    MediaRecorderBase            *mRecorder;
-    sp<MediaPlayerService>       mMediaPlayerService;
+    pid_t                       mPid;
+    Mutex                       mLock;
+    MediaRecorderBase           *mRecorder;
+    sp<MediaPlayerService>      mMediaPlayerService;
 };
 
 }; // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 50f74f2..72061ad 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1057,4 +1057,64 @@
     return OK;
 }
 
+status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "   Recorder: %p", this);
+    snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file size (bytes): %lld\n", mMaxFileSizeBytes);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max file duration (us): %lld\n", mMaxFileDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     File offset length (bits): %d\n", mUse64BitFileOffset? 64: 32);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Interleave duration (us): %d\n", mInterleaveDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %d frames\n", mTrackEveryNumberOfFrames);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Progress notification: %lld us\n", mTrackEveryTimeDurationUs);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Audio\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mAudioSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mAudioEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mAudioBitRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Sampling rate (hz): %d\n", mSampleRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Number of channels: %d\n", mAudioChannels);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Max amplitude: %d\n", mAudioSourceNode == 0? 0: mAudioSourceNode->getMaxAmplitude());
+    result.append(buffer);
+    snprintf(buffer, SIZE, "   Video\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Source: %d\n", mVideoSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera Id: %d\n", mCameraId);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Camera flags: %d\n", mFlags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder: %d\n", mVideoEncoder);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder profile: %d\n", mVideoEncoderProfile);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Encoder level: %d\n", mVideoEncoderLevel);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     I frames interval (s): %d\n", mIFramesInterval);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame size (pixels): %dx%d\n", mVideoWidth, mVideoHeight);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Frame rate (fps): %d\n", mFrameRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     Bit rate (bps): %d\n", mVideoBitRate);
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return OK;
+}
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 85d2557..704523f 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -54,6 +54,7 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     enum CameraFlags {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 83f7040..efaab5b 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -948,7 +948,7 @@
 
         int32_t supportedProfile = static_cast<int32_t>(param.eProfile);
         int32_t supportedLevel = static_cast<int32_t>(param.eLevel);
-        CODEC_LOGV("Supported profile: %ld, level %ld",
+        CODEC_LOGV("Supported profile: %d, level %d",
             supportedProfile, supportedLevel);
 
         if (profile == supportedProfile &&
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
index 2bc4448..f3b281f 100644
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "AACDecoder.h"
+#define LOG_TAG "AACDecoder"
 
 #include "../../include/ESDS.h"
 
@@ -36,26 +37,33 @@
       mAnchorTimeUs(0),
       mNumSamplesOutput(0),
       mInputBuffer(NULL) {
-}
 
-AACDecoder::~AACDecoder() {
-    if (mStarted) {
-        stop();
+    sp<MetaData> srcFormat = mSource->getFormat();
+
+    int32_t sampleRate;
+    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+    mMeta = new MetaData;
+    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+
+    // We'll always output stereo, regardless of how many channels are
+    // present in the input due to decoder limitations.
+    mMeta->setInt32(kKeyChannelCount, 2);
+    mMeta->setInt32(kKeySampleRate, sampleRate);
+
+    int64_t durationUs;
+    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+        mMeta->setInt64(kKeyDuration, durationUs);
     }
+    mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
 
-    delete mConfig;
-    mConfig = NULL;
+    mInitCheck = initCheck();
 }
 
-status_t AACDecoder::start(MetaData *params) {
-    CHECK(!mStarted);
-
-    mBufferGroup = new MediaBufferGroup;
-    mBufferGroup->add_buffer(new MediaBuffer(2048 * 2));
-
+status_t AACDecoder::initCheck() {
+    memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
     mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
-    mConfig->aacPlusUpsamplingFactor = 0;
-    mConfig->aacPlusEnabled = false;
+    mConfig->aacPlusEnabled = 1;
 
     // The software decoder doesn't properly support mono output on
     // AACplus files. Always output stereo.
@@ -64,8 +72,11 @@
     UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
     mDecoderBuf = malloc(memRequirements);
 
-    CHECK_EQ(PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf),
-             MP4AUDEC_SUCCESS);
+    status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
+    if (err != MP4AUDEC_SUCCESS) {
+        LOGE("Failed to initialize MP4 audio decoder");
+        return UNKNOWN_ERROR;
+    }
 
     uint32_t type;
     const void *data;
@@ -83,18 +94,38 @@
         mConfig->pInputBuffer = (UChar *)codec_specific_data;
         mConfig->inputBufferCurrentLength = codec_specific_data_size;
         mConfig->inputBufferMaxLength = 0;
-        mConfig->inputBufferUsedLength = 0;
-        mConfig->remainderBits = 0;
-
-        mConfig->pOutputBuffer = NULL;
-        mConfig->pOutputBuffer_plus = NULL;
-        mConfig->repositionFlag = false;
 
         if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
                 != MP4AUDEC_SUCCESS) {
             return ERROR_UNSUPPORTED;
         }
+
+        // Check on the sampling rate to see whether it is changed.
+        int32_t sampleRate;
+        CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
+        if (mConfig->samplingRate != sampleRate) {
+            mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
+            LOGW("Sample rate was %d, but now is %d",
+                    sampleRate, mConfig->samplingRate);
+        }
     }
+    return OK;
+}
+
+AACDecoder::~AACDecoder() {
+    if (mStarted) {
+        stop();
+    }
+
+    delete mConfig;
+    mConfig = NULL;
+}
+
+status_t AACDecoder::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mBufferGroup = new MediaBufferGroup;
+    mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
 
     mSource->start();
 
@@ -127,28 +158,7 @@
 }
 
 sp<MetaData> AACDecoder::getFormat() {
-    sp<MetaData> srcFormat = mSource->getFormat();
-
-    int32_t sampleRate;
-    CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
-    sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
-    // We'll always output stereo, regardless of how many channels are
-    // present in the input due to decoder limitations.
-    meta->setInt32(kKeyChannelCount, 2);
-
-    meta->setInt32(kKeySampleRate, sampleRate);
-
-    int64_t durationUs;
-    if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
-        meta->setInt64(kKeyDuration, durationUs);
-    }
-
-    meta->setCString(kKeyDecoderComponent, "AACDecoder");
-
-    return meta;
+    return mMeta;
 }
 
 status_t AACDecoder::read(
@@ -200,13 +210,19 @@
     mConfig->remainderBits = 0;
 
     mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
-    mConfig->pOutputBuffer_plus = NULL;
+    mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
     mConfig->repositionFlag = false;
 
     Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
 
     size_t numOutBytes =
         mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
+    if (mConfig->aacPlusUpsamplingFactor == 2) {
+        if (mConfig->desiredChannels == 1) {
+            memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
+        }
+        numOutBytes *= 2;
+    }
 
     if (decoderErr != MP4AUDEC_SUCCESS) {
         LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h
index f09addd..200f93c 100644
--- a/media/libstagefright/include/AACDecoder.h
+++ b/media/libstagefright/include/AACDecoder.h
@@ -25,6 +25,7 @@
 namespace android {
 
 struct MediaBufferGroup;
+struct MetaData;
 
 struct AACDecoder : public MediaSource {
     AACDecoder(const sp<MediaSource> &source);
@@ -41,6 +42,7 @@
     virtual ~AACDecoder();
 
 private:
+    sp<MetaData>    mMeta;
     sp<MediaSource> mSource;
     bool mStarted;
 
@@ -50,9 +52,11 @@
     void *mDecoderBuf;
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
+    status_t mInitCheck;
 
     MediaBuffer *mInputBuffer;
 
+    status_t initCheck();
     AACDecoder(const AACDecoder &);
     AACDecoder &operator=(const AACDecoder &);
 };
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 015a1ce..89d53e2 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -186,9 +186,9 @@
 }
 
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        ALooper_callbackFunc callback, void* data) {
+        ALooper_callbackFunc* callback, void* data) {
     queue->setPollLoop(static_cast<android::PollLoop*>(looper));
-    ALooper_setCallback(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
+    ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
             POLLIN, callback, data);
 }
 
diff --git a/native/android/looper.cpp b/native/android/looper.cpp
index 6e78bbd..1564c47 100644
--- a/native/android/looper.cpp
+++ b/native/android/looper.cpp
@@ -27,22 +27,41 @@
     return PollLoop::getForThread().get();
 }
 
-ALooper* ALooper_prepare() {
+ALooper* ALooper_prepare(int32_t opts) {
+    bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0;
     sp<PollLoop> loop = PollLoop::getForThread();
     if (loop == NULL) {
-        loop = new PollLoop();
+        loop = new PollLoop(allowFds);
         PollLoop::setForThread(loop);
     }
+    if (loop->getAllowNonCallbacks() != allowFds) {
+        LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS");
+    }
     return loop.get();
 }
 
-int32_t ALooper_pollOnce(int timeoutMillis) {
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) {
     sp<PollLoop> loop = PollLoop::getForThread();
     if (loop == NULL) {
         LOGW("ALooper_pollOnce: No looper for this thread!");
         return -1;
     }
-    return loop->pollOnce(timeoutMillis) ? 1 : 0;
+    return loop->pollOnce(timeoutMillis, outEvents, outData);
+}
+
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) {
+    sp<PollLoop> loop = PollLoop::getForThread();
+    if (loop == NULL) {
+        LOGW("ALooper_pollOnce: No looper for this thread!");
+        return -1;
+    }
+    
+    int32_t result;
+    while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) {
+        ;
+    }
+    
+    return result;
 }
 
 void ALooper_acquire(ALooper* looper) {
@@ -53,11 +72,11 @@
     static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire);
 }
 
-void ALooper_setCallback(ALooper* looper, int fd, int events,
+void ALooper_addFd(ALooper* looper, int fd, int events,
         ALooper_callbackFunc* callback, void* data) {
     static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data);
 }
 
-int32_t ALooper_removeCallback(ALooper* looper, int fd) {
+int32_t ALooper_removeFd(ALooper* looper, int fd) {
     return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0;
 }
diff --git a/native/glue/threaded_app/Android.mk b/native/glue/threaded_app/Android.mk
new file mode 100644
index 0000000..cfc9b2a
--- /dev/null
+++ b/native/glue/threaded_app/Android.mk
@@ -0,0 +1,18 @@
+BASE_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# our source files
+#
+LOCAL_SRC_FILES:= \
+    threaded_app.c
+
+LOCAL_C_INCLUDES += \
+    frameworks/base/native/include \
+    frameworks/base/core/jni/android \
+    dalvik/libnativehelper/include/nativehelper
+
+LOCAL_MODULE:= libthreaded_app
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c
new file mode 100644
index 0000000..c9cae8b
--- /dev/null
+++ b/native/glue/threaded_app/threaded_app.c
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ *
+ */
+
+#include <jni.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include <android_glue/threaded_app.h>
+
+#include <android/log.h>
+
+#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
+#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__))
+
+void android_app_destroy(struct android_app* android_app) {
+    LOGI("android_app_destroy!");
+    pthread_mutex_lock(&android_app->mutex);
+    if (android_app->inputQueue != NULL) {
+        AInputQueue_detachLooper(android_app->inputQueue);
+    }
+    android_app->destroyed = 1;
+    pthread_cond_broadcast(&android_app->cond);
+    pthread_mutex_unlock(&android_app->mutex);
+    // Can't touch android_app object after this.
+}
+
+int8_t android_app_read_cmd(struct android_app* android_app) {
+    int8_t cmd;
+    if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
+        return cmd;
+    } else {
+        LOGW("No data on command pipe!");
+    }
+    return -1;
+}
+
+void android_app_exec_cmd(struct android_app* android_app, int8_t cmd) {
+    switch (cmd) {
+        case APP_CMD_INPUT_CHANGED:
+            LOGI("APP_CMD_INPUT_CHANGED\n");
+            pthread_mutex_lock(&android_app->mutex);
+            if (android_app->inputQueue != NULL) {
+                AInputQueue_detachLooper(android_app->inputQueue);
+            }
+            android_app->inputQueue = android_app->pendingInputQueue;
+            if (android_app->inputQueue != NULL) {
+                LOGI("Attaching input queue to looper");
+                AInputQueue_attachLooper(android_app->inputQueue,
+                        android_app->looper, NULL, (void*)LOOPER_ID_EVENT);
+            }
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_WINDOW_CHANGED:
+            LOGI("APP_CMD_WINDOW_CHANGED\n");
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->window = android_app->pendingWindow;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_START:
+        case APP_CMD_RESUME:
+        case APP_CMD_PAUSE:
+        case APP_CMD_STOP:
+            LOGI("activityState=%d\n", cmd);
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->activityState = cmd;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+            
+        case APP_CMD_DESTROY:
+            LOGI("APP_CMD_DESTROY\n");
+            android_app->destroyRequested = 1;
+            break;
+    }
+}
+
+static void* android_app_entry(void* param) {
+    struct android_app* android_app = (struct android_app*)param;
+    
+    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+    ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, (void*)LOOPER_ID_MAIN);
+    android_app->looper = looper;
+    
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->running = 1;
+    pthread_cond_broadcast(&android_app->cond);
+    pthread_mutex_unlock(&android_app->mutex);
+    
+    android_main(android_app);
+    return NULL;
+}
+
+// --------------------------------------------------------------------
+// Native activity interaction (called from main thread)
+// --------------------------------------------------------------------
+
+static struct android_app* android_app_create(ANativeActivity* activity) {
+    struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
+    memset(android_app, 0, sizeof(struct android_app));
+    android_app->activity = activity;
+    
+    pthread_mutex_init(&android_app->mutex, NULL);
+    pthread_cond_init(&android_app->cond, NULL);
+    
+    int msgpipe[2];
+    if (pipe(msgpipe)) {
+        LOGI("could not create pipe: %s", strerror(errno));
+    }
+    android_app->msgread = msgpipe[0];
+    android_app->msgwrite = msgpipe[1];
+    
+    pthread_attr_t attr; 
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+    pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
+    
+    // Wait for thread to start.
+    pthread_mutex_lock(&android_app->mutex);
+    while (!android_app->running) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+    
+    return android_app;
+}
+
+static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
+    if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
+        LOGI("Failure writing android_app cmd: %s\n", strerror(errno));
+    }
+}
+
+static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->pendingInputQueue = inputQueue;
+    android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
+    while (android_app->inputQueue != android_app->pendingInputQueue) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->pendingWindow = window;
+    android_app_write_cmd(android_app, APP_CMD_WINDOW_CHANGED);
+    while (android_app->window != android_app->pendingWindow) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app_write_cmd(android_app, cmd);
+    while (android_app->activityState != cmd) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_free(struct android_app* android_app) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app_write_cmd(android_app, APP_CMD_DESTROY);
+    while (!android_app->destroyed) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+    
+    close(android_app->msgread);
+    close(android_app->msgwrite);
+    pthread_cond_destroy(&android_app->cond);
+    pthread_mutex_destroy(&android_app->mutex);
+    free(android_app);
+}
+
+static void onDestroy(ANativeActivity* activity) {
+    LOGI("Destroy: %p\n", activity);
+    android_app_free((struct android_app*)activity->instance);
+}
+
+static void onStart(ANativeActivity* activity) {
+    LOGI("Start: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
+}
+
+static void onResume(ANativeActivity* activity) {
+    LOGI("Resume: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
+}
+
+static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
+    LOGI("SaveInstanceState: %p\n", activity);
+    return NULL;
+}
+
+static void onPause(ANativeActivity* activity) {
+    LOGI("Pause: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
+}
+
+static void onStop(ANativeActivity* activity) {
+    LOGI("Stop: %p\n", activity);
+    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
+}
+
+static void onLowMemory(ANativeActivity* activity) {
+    LOGI("LowMemory: %p\n", activity);
+}
+
+static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
+    LOGI("WindowFocusChanged: %p -- %d\n", activity, focused);
+    android_app_write_cmd((struct android_app*)activity->instance,
+            focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
+}
+
+static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
+    LOGI("NativeWindowCreated: %p -- %p\n", activity, window);
+    android_app_set_window((struct android_app*)activity->instance, window);
+}
+
+static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
+    LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
+    android_app_set_window((struct android_app*)activity->instance, NULL);
+}
+
+static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
+    LOGI("InputQueueCreated: %p -- %p\n", activity, queue);
+    android_app_set_input((struct android_app*)activity->instance, queue);
+}
+
+static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
+    LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue);
+    android_app_set_input((struct android_app*)activity->instance, NULL);
+}
+
+void ANativeActivity_onCreate(ANativeActivity* activity,
+        void* savedState, size_t savedStateSize) {
+    LOGI("Creating: %p\n", activity);
+    activity->callbacks->onDestroy = onDestroy;
+    activity->callbacks->onStart = onStart;
+    activity->callbacks->onResume = onResume;
+    activity->callbacks->onSaveInstanceState = onSaveInstanceState;
+    activity->callbacks->onPause = onPause;
+    activity->callbacks->onStop = onStop;
+    activity->callbacks->onLowMemory = onLowMemory;
+    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
+    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
+    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
+    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+    
+    activity->instance = android_app_create(activity);
+}
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 75be85a..014b6a3 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -534,10 +534,11 @@
 typedef struct AInputQueue AInputQueue;
 
 /*
- * Add this input queue to a looper for processing.
+ * Add this input queue to a looper for processing.  See
+ * ALooper_addFd() for information on the callback and data params.
  */
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
-        ALooper_callbackFunc callback, void* data);
+        ALooper_callbackFunc* callback, void* data);
 
 /*
  * Remove the input queue from the looper it is currently attached to.
diff --git a/native/include/android/looper.h b/native/include/android/looper.h
index 90a8983..2917216 100644
--- a/native/include/android/looper.h
+++ b/native/include/android/looper.h
@@ -24,25 +24,151 @@
 extern "C" {
 #endif
 
+/**
+ * ALooper
+ *
+ * A looper is the state tracking an event loop for a thread.
+ * Loopers do not define event structures or other such things; rather
+ * they are a lower-level facility to attach one or more discrete objects
+ * listening for an event.  An "event" here is simply data available on
+ * a file descriptor: each attached object has an associated file descriptor,
+ * and waiting for "events" means (internally) polling on all of these file
+ * descriptors until one or more of them have data available.
+ *
+ * A thread can have only one ALooper associated with it.
+ */
 struct ALooper;
 typedef struct ALooper ALooper;
 
+/**
+ * For callback-based event loops, this is the prototype of the function
+ * that is called.  It is given the file descriptor it is associated with,
+ * a bitmask of the poll events that were triggered (typically POLLIN), and
+ * the data pointer that was originally supplied.
+ *
+ * Implementations should return 1 to continue receiving callbacks, or 0
+ * to have this file descriptor and callback unregistered from the looper.
+ */
 typedef int ALooper_callbackFunc(int fd, int events, void* data);
 
+/**
+ * Return the ALooper associated with the calling thread, or NULL if
+ * there is not one.
+ */
 ALooper* ALooper_forThread();
 
-ALooper* ALooper_prepare();
+enum {
+    /**
+     * Option for ALooper_prepare: this ALooper will accept calls to
+     * ALooper_addFd() that do not have a callback (that is provide NULL
+     * for the callback).  In this case the caller of ALooper_pollOnce()
+     * or ALooper_pollAll() MUST check the return from these functions to
+     * discover when data is available on such fds and process it.
+     */
+    ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0
+};
 
-int32_t ALooper_pollOnce(int timeoutMillis);
+/**
+ * Prepare an ALooper associated with the calling thread, and return it.
+ * If the thread already has an ALooper, it is returned.  Otherwise, a new
+ * one is created, associated with the thread, and returned.
+ *
+ * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0.
+ */
+ALooper* ALooper_prepare(int32_t opts);
 
+enum {
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): one or
+     * more callbacks were executed.
+     */
+    ALOOPER_POLL_CALLBACK = -1,
+    
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): the
+     * timeout expired.
+     */
+    ALOOPER_POLL_TIMEOUT = -2,
+    
+    /**
+     * Result from ALooper_pollOnce() and ALooper_pollAll(): an error
+     * occurred.
+     */
+    ALOOPER_POLL_ERROR = -3,
+};
+
+/**
+ * Wait for events to be available, with optional timeout in milliseconds.
+ * Invokes callbacks for all file descriptors on which an event occurred.
+ *
+ * If the timeout is zero, returns immediately without blocking.
+ * If the timeout is negative, waits indefinitely until an event appears.
+ *
+ * Returns ALOOPER_POLL_CALLBACK if a callback was invoked.
+ *
+ * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given
+ * timeout expired.
+ *
+ * Returns ALOPER_POLL_ERROR if an error occurred.
+ *
+ * Returns a value >= 0 containing a file descriptor if it has data
+ * and it has no callback function (requiring the caller here to handle it).
+ * In this (and only this) case outEvents and outData will contain the poll
+ * events and data associated with the fd.
+ *
+ * This method does not return until it has finished invoking the appropriate callbacks
+ * for all file descriptors that were signalled.
+ */
+int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Like ALooper_pollOnce(), but performs all pending callbacks until all
+ * data has been consumed or a file descriptor is available with no callback.
+ * This function will never return ALOOPER_POLL_CALLBACK.
+ */
+int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData);
+
+/**
+ * Acquire a reference on the given ALooper object.  This prevents the object
+ * from being deleted until the reference is removed.  This is only needed
+ * to safely hand an ALooper from one thread to another.
+ */
 void ALooper_acquire(ALooper* looper);
 
+/**
+ * Remove a reference that was previously acquired with ALooper_acquire().
+ */
 void ALooper_release(ALooper* looper);
 
-void ALooper_setCallback(ALooper* looper, int fd, int events,
+/**
+ * Add a new file descriptor to be polled by the looper.  If the same file
+ * descriptor was previously added, it is replaced.
+ *
+ * "fd" is the file descriptor to be added.
+ * "events" are the poll events to wake up on.  Typically this is POLLIN.
+ * "callback" is the function to call when there is an event on the file
+ * descriptor.
+ * "id" is an identifier to associated with this file descriptor, or 0.
+ * "data" is a private data pointer to supply to the callback.
+ *
+ * There are two main uses of this function:
+ *
+ * (1) If "callback" is non-NULL, then
+ * this function will be called when there is data on the file descriptor.  It
+ * should execute any events it has pending, appropriately reading from the
+ * file descriptor.
+ *
+ * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce
+ * when it has data available, requiring the caller to take care of processing
+ * it.
+ */
+void ALooper_addFd(ALooper* looper, int fd, int events,
         ALooper_callbackFunc* callback, void* data);
 
-int32_t ALooper_removeCallback(ALooper* looper, int fd);
+/**
+ * Remove a previously added file descriptor from the looper.
+ */
+int32_t ALooper_removeFd(ALooper* looper, int fd);
 
 #ifdef __cplusplus
 };
diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h
new file mode 100644
index 0000000..80de3bf
--- /dev/null
+++ b/native/include/android_glue/threaded_app.h
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ *
+ */
+
+#include <poll.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include <android/native_activity.h>
+#include <android/looper.h>
+
+/**
+ * This is the interface for the standard glue code of a threaded
+ * application.  In this model, the application's code is running
+ * in its own thread separate from the main thread of the process.
+ * It is not required that this thread be associated with the Java
+ * VM, although it will need to be in order to make JNI calls any
+ * Java objects.
+ */
+struct android_app {
+    // The application can place a pointer to its own state object
+    // here if it likes.
+    void* userData;
+
+    // The ANativeActivity object instance that this app is running in.
+    ANativeActivity* activity;
+
+    // The ALooper associated with the app's thread.
+    ALooper* looper;
+
+    // When non-NULL, this is the input queue from which the app will
+    // receive user input events.
+    AInputQueue* inputQueue;
+
+    // When non-NULL, this is the window surface that the app can draw in.
+    ANativeWindow* window;
+
+    // Current state of the app's activity.  May be either APP_CMD_START,
+    // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
+    int activityState;
+
+    // This is non-zero when the application's NativeActivity is being
+    // destroyed and waiting for the app thread to complete.
+    int destroyRequested;
+
+    // -------------------------------------------------
+    // Below are "private" implementation of the glue code.
+
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+
+    int msgread;
+    int msgwrite;
+
+    pthread_t thread;
+
+    int running;
+    int destroyed;
+    AInputQueue* pendingInputQueue;
+    ANativeWindow* pendingWindow;
+};
+
+enum {
+    /**
+     * Looper data ID of commands coming from the app's main thread.
+     * These can be retrieved and processed with android_app_read_cmd()
+     * and android_app_exec_cmd().
+     */
+    LOOPER_ID_MAIN = 1,
+
+    /**
+     * Looper data ID of events coming from the AInputQueue of the
+     * application's window.  These can be read via the inputQueue
+     * object of android_app.
+     */
+    LOOPER_ID_EVENT = 2
+};
+
+enum {
+    /**
+     * Command from main thread: the AInputQueue has changed.  Upon processing
+     * this command, android_app->inputQueue will be updated to the new queue
+     * (or NULL).
+     */
+    APP_CMD_INPUT_CHANGED,
+
+    /**
+     * Command from main thread: the ANativeWindow has changed.  Upon processing
+     * this command, android_app->window will be updated to the new window surface
+     * (or NULL).
+     */
+    APP_CMD_WINDOW_CHANGED,
+
+    /**
+     * Command from main thread: the app's activity window has gained
+     * input focus.
+     */
+    APP_CMD_GAINED_FOCUS,
+
+    /**
+     * Command from main thread: the app's activity window has lost
+     * input focus.
+     */
+    APP_CMD_LOST_FOCUS,
+
+    /**
+     * Command from main thread: the app's activity has been started.
+     */
+    APP_CMD_START,
+
+    /**
+     * Command from main thread: the app's activity has been resumed.
+     */
+    APP_CMD_RESUME,
+
+    /**
+     * Command from main thread: the app's activity has been paused.
+     */
+    APP_CMD_PAUSE,
+
+    /**
+     * Command from main thread: the app's activity has been stopped.
+     */
+    APP_CMD_STOP,
+
+    /**
+     * Command from main thread: the app's activity is being destroyed,
+     * and waiting for the app thread to clean up and exit before proceeding.
+     */
+    APP_CMD_DESTROY,
+};
+
+/**
+ * Call if android_app->destroyRequested is non-zero.  Upon return, the
+ * android_app structure is no longer valid and must not be touched.
+ */
+void android_app_destroy(struct android_app* android_app);
+
+/**
+ * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
+ * app command message.
+ */
+int8_t android_app_read_cmd(struct android_app* android_app);
+
+/**
+ * Call with the command returned by android_app_read_cmd() to do the
+ * default processing of the given command.
+ */
+void android_app_exec_cmd(struct android_app* android_app, int8_t cmd);
+
+/**
+ * This is the function that application code must implement, representing
+ * the main entry to the app.
+ */
+extern void android_main(struct android_app* app);
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index f8abc5a..b9e915a4 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -244,27 +244,12 @@
             intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-            final boolean adbOn = 1 == Settings.Secure.getInt(
-                mContext.getContentResolver(),
-                Settings.Secure.ADB_ENABLED,
-                0);
-
             PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
             setUsbStorageNotification(
                     com.android.internal.R.string.usb_storage_notification_title,
                     com.android.internal.R.string.usb_storage_notification_message,
                     com.android.internal.R.drawable.stat_sys_data_usb,
                     false, true, pi);
-
-            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
-                // We assume that developers don't want to enable UMS every
-                // time they attach a device to a USB host. The average user,
-                // however, is looking to charge the phone (in which case this
-                // is harmless) or transfer files (in which case this coaches
-                // the user about how to complete that task and saves several
-                // steps).
-                mContext.startActivity(intent);
-            }
         } else {
             setUsbStorageNotification(0, 0, 0, false, false, null);
         }
@@ -313,6 +298,23 @@
             }
 
             mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+            final boolean adbOn = 1 == Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                Settings.Secure.ADB_ENABLED,
+                0);
+
+            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
+                // Pop up a full-screen alert to coach the user through enabling UMS. The average
+                // user has attached the device to USB either to charge the phone (in which case
+                // this is harmless) or transfer files, and in the latter case this alert saves
+                // several steps (as well as subtly indicates that you shouldn't mix UMS with other
+                // activities on the device).
+                //
+                // If ADB is enabled, however, we suppress this dialog (under the assumption that a
+                // developer (a) knows how to enable UMS, and (b) is probably using USB to install
+                // builds or use adb commands.
+                mUsbStorageNotification.fullScreenIntent = pi;
+            }
         }
     
         final int notificationId = mUsbStorageNotification.icon;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index a01e25b..83d9c47 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -60,7 +60,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.WindowOrientationListener;
-import android.view.RawInputEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -153,8 +152,6 @@
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
     static final int APPLICATION_PANEL_SUBLAYER = 1;
     static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
-
-    static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
     
     // Debugging: set this to have the system act like there is no hard keyboard.
     static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
@@ -164,6 +161,10 @@
     static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
 
+    // Useful scan codes.
+    private static final int SW_LID = 0x00;
+    private static final int BTN_MOUSE = 0x110;
+    
     final Object mLock = new Object();
     
     Context mContext;
@@ -690,7 +691,7 @@
     
     void readLidState() {
         try {
-            int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID);
+            int sw = mWindowManager.getSwitchState(SW_LID);
             if (sw >= 0) {
                 mLidOpen = sw == 0;
             }
@@ -727,19 +728,6 @@
                 : Configuration.KEYBOARDHIDDEN_YES;
     }
     
-    public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
-        if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
-            return true;
-        }
-        int size = ev.getHistorySize();
-        for(int i = 0; i < size; i++) {
-            if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
     public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY) {
         if (mPointerLocationView == null) {
             return;
@@ -1034,19 +1022,22 @@
         };
 
     /** {@inheritDoc} */
-    public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 
-            int repeatCount, int flags) {
-        boolean keyguardOn = keyguardOn();
+    @Override
+    public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
+            int keyCode, int metaState, int repeatCount, int policyFlags) {
+        final boolean keyguardOn = keyguardOn();
+        final boolean down = (action == KeyEvent.ACTION_DOWN);
+        final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
 
         if (false) {
-            Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
+            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
                     + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
         }
 
         // Clear a pending HOME longpress if the user releases Home
         // TODO: This could probably be inside the next bit of logic, but that code
         // turned out to be a bit fragile so I'm doing it here explicitly, for now.
-        if ((code == KeyEvent.KEYCODE_HOME) && !down) {
+        if ((keyCode == KeyEvent.KEYCODE_HOME) && !down) {
             mHandler.removeCallbacks(mHomeLongPress);
         }
 
@@ -1056,11 +1047,11 @@
             
             // If we have released the home key, and didn't do anything else
             // while it was pressed, then it is time to go home!
-            if (code == KeyEvent.KEYCODE_HOME) {
+            if (keyCode == KeyEvent.KEYCODE_HOME) {
                 if (!down) {
                     mHomePressed = false;
                     
-                    if ((flags&KeyEvent.FLAG_CANCELED) == 0) {
+                    if (! canceled) {
                         // If an incoming call is ringing, HOME is totally disabled.
                         // (The user is already on the InCallScreen at this point,
                         // and his ONLY options are to answer or reject the call.)
@@ -1094,7 +1085,7 @@
         // can never break it, although if keyguard is on, we do let
         // it handle it, because that gives us the correct 5 second
         // timeout.
-        if (code == KeyEvent.KEYCODE_HOME) {
+        if (keyCode == KeyEvent.KEYCODE_HOME) {
 
             // If a system window has focus, then it doesn't make sense
             // right now to interact with applications.
@@ -1122,17 +1113,17 @@
                 mHomePressed = true;
             }
             return true;
-        } else if (code == KeyEvent.KEYCODE_MENU) {
+        } else if (keyCode == KeyEvent.KEYCODE_MENU) {
             // Hijack modified menu keys for debugging features
             final int chordBug = KeyEvent.META_SHIFT_ON;
 
             if (down && repeatCount == 0) {
-                if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) {
+                if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
                     Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
                     mContext.sendOrderedBroadcast(intent, null);
                     return true;
                 } else if (SHOW_PROCESSES_ON_ALT_MENU &&
-                        (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
+                        (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
                     Intent service = new Intent();
                     service.setClassName(mContext, "com.android.server.LoadAverageService");
                     ContentResolver res = mContext.getContentResolver();
@@ -1148,7 +1139,7 @@
                     return true;
                 }
             }
-        } else if (code == KeyEvent.KEYCODE_SEARCH) {
+        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
             if (down) {
                 if (repeatCount == 0) {
                     mSearchKeyPressed = true;
@@ -1167,7 +1158,7 @@
         // Shortcuts are invoked through Search+key, so intercept those here
         if (mSearchKeyPressed) {
             if (down && repeatCount == 0 && !keyguardOn) {
-                Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
+                Intent shortcutIntent = mShortcutManager.getIntent(keyCode, metaState);
                 if (shortcutIntent != null) {
                     shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     mContext.startActivity(shortcutIntent);
@@ -1606,42 +1597,6 @@
     }
 
     /** {@inheritDoc} */
-    public boolean preprocessInputEventTq(RawInputEvent event) {
-        switch (event.type) {
-            case RawInputEvent.EV_SW:
-                if (event.keycode == RawInputEvent.SW_LID) {
-                    // lid changed state
-                    mLidOpen = event.value == 0;
-                    boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen);
-                    updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
-                    if (awakeNow) {
-                        // If the lid opening and we don't have to keep the
-                        // keyguard up, then we can turn on the screen
-                        // immediately.
-                        mKeyguardMediator.pokeWakelock();
-                    } else if (keyguardIsShowingTq()) {
-                        if (mLidOpen) {
-                            // If we are opening the lid and not hiding the
-                            // keyguard, then we need to have it turn on the
-                            // screen once it is shown.
-                            mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
-                                    KeyEvent.KEYCODE_POWER);
-                        }
-                    } else {
-                        // Light up the keyboard if we are sliding up.
-                        if (mLidOpen) {
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                                    LocalPowerManager.BUTTON_EVENT);
-                        } else {
-                            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                                    LocalPowerManager.OTHER_EVENT);
-                        }
-                    }
-                }
-        }
-        return false;
-    }
-    
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
         // lid changed state
         mLidOpen = lidOpen;
@@ -1672,26 +1627,6 @@
         }
     }
 
-    
-    /** {@inheritDoc} */
-    public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
-        return keycode == KeyEvent.KEYCODE_HOME
-                || keycode == KeyEvent.KEYCODE_ENDCALL;
-    }
-    
-    /** {@inheritDoc} */
-    public boolean isMovementKeyTi(int keycode) {
-        switch (keycode) {
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                return true;
-        }
-        return false;
-    }
-
-
     /**
      * @return Whether a telephone call is in progress right now.
      */
@@ -1762,60 +1697,63 @@
     }
  
     /** {@inheritDoc} */
-    public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
+    @Override
+    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+            int policyFlags, boolean isScreenOn) {
         int result = ACTION_PASS_TO_USER;
-        final boolean isWakeKey = isWakeKeyTq(event);
+        
+        final boolean isWakeKey = (policyFlags
+                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+        
         // If screen is off then we treat the case where the keyguard is open but hidden
         // the same as if it were open and in front.
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
-        final boolean keyguardActive = (screenIsOn ?
+        final boolean keyguardActive = (isScreenOn ?
                                         mKeyguardMediator.isShowingAndNotHidden() :
                                         mKeyguardMediator.isShowing());
 
         if (false) {
-            Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
-                  + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);
+            Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
         }
 
         if (keyguardActive) {
-            if (screenIsOn) {
+            if (isScreenOn) {
                 // when the screen is on, always give the event to the keyguard
                 result |= ACTION_PASS_TO_USER;
             } else {
                 // otherwise, don't pass it to the user
                 result &= ~ACTION_PASS_TO_USER;
 
-                final boolean isKeyDown =
-                        (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
-                if (isWakeKey && isKeyDown) {
+                if (isWakeKey && down) {
 
                     // tell the mediator about a wake key, it may decide to
                     // turn on the screen depending on whether the key is
                     // appropriate.
-                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
-                            && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
+                            && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
                         // when keyguard is showing and screen off, we need
                         // to handle the volume key for calls and  music here
                         if (isInCall()) {
-                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
                         } else if (isMusicActive()) {
-                            handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
+                            handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
                         }
                     }
                 }
             }
-        } else if (!screenIsOn) {
+        } else if (!isScreenOn) {
             // If we are in-call with screen off and keyguard is not showing,
             // then handle the volume key ourselves.
             // This is necessary because the phone app will disable the keyguard
             // when the proximity sensor is in use.
-            if (isInCall() && event.type == RawInputEvent.EV_KEY &&
-                     (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+            if (isInCall() &&
+                     (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
                 result &= ~ACTION_PASS_TO_USER;
-                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
             }
             if (isWakeKey) {
                 // a wake key has a sole purpose of waking the device; don't pass
@@ -1825,156 +1763,151 @@
             }
         }
 
-        int type = event.type;
-        int code = event.keycode;
-        boolean down = event.value != 0;
-
-        if (type == RawInputEvent.EV_KEY) {
-            if (code == KeyEvent.KEYCODE_ENDCALL
-                    || code == KeyEvent.KEYCODE_POWER) {
-                if (down) {
-                    boolean handled = false;
-                    boolean hungUp = false;
-                    // key repeats are generated by the window manager, and we don't see them
-                    // here, so unless the driver is doing something it shouldn't be, we know
-                    // this is the real press event.
-                    ITelephony phoneServ = getPhoneInterface();
-                    if (phoneServ != null) {
-                        try {
-                            if (code == KeyEvent.KEYCODE_ENDCALL) {
+        if (keyCode == KeyEvent.KEYCODE_ENDCALL
+                || keyCode == KeyEvent.KEYCODE_POWER) {
+            if (down) {
+                boolean handled = false;
+                boolean hungUp = false;
+                // key repeats are generated by the window manager, and we don't see them
+                // here, so unless the driver is doing something it shouldn't be, we know
+                // this is the real press event.
+                ITelephony phoneServ = getPhoneInterface();
+                if (phoneServ != null) {
+                    try {
+                        if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
+                            handled = hungUp = phoneServ.endCall();
+                        } else if (keyCode == KeyEvent.KEYCODE_POWER) {
+                            if (phoneServ.isRinging()) {
+                                // Pressing Power while there's a ringing incoming
+                                // call should silence the ringer.
+                                phoneServ.silenceRinger();
+                                handled = true;
+                            } else if (phoneServ.isOffhook() &&
+                                       ((mIncallPowerBehavior
+                                         & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
+                                        != 0)) {
+                                // Otherwise, if "Power button ends call" is enabled,
+                                // the Power button will hang up any current active call.
                                 handled = hungUp = phoneServ.endCall();
-                            } else if (code == KeyEvent.KEYCODE_POWER) {
-                                if (phoneServ.isRinging()) {
-                                    // Pressing Power while there's a ringing incoming
-                                    // call should silence the ringer.
-                                    phoneServ.silenceRinger();
-                                    handled = true;
-                                } else if (phoneServ.isOffhook() &&
-                                           ((mIncallPowerBehavior
-                                             & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
-                                            != 0)) {
-                                    // Otherwise, if "Power button ends call" is enabled,
-                                    // the Power button will hang up any current active call.
-                                    handled = hungUp = phoneServ.endCall();
-                                }
                             }
-                        } catch (RemoteException ex) {
-                            Log.w(TAG, "ITelephony threw RemoteException" + ex);
                         }
-                    } else {
-                        Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
-                    }
-
-                    if (!screenIsOn
-                            || (handled && code != KeyEvent.KEYCODE_POWER)
-                            || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {
-                        mShouldTurnOffOnKeyUp = false;
-                    } else {
-                        // only try to turn off the screen if we didn't already hang up
-                        mShouldTurnOffOnKeyUp = true;
-                        mHandler.postDelayed(mPowerLongPress,
-                                ViewConfiguration.getGlobalActionKeyTimeout());
-                        result &= ~ACTION_PASS_TO_USER;
+                    } catch (RemoteException ex) {
+                        Log.w(TAG, "ITelephony threw RemoteException" + ex);
                     }
                 } else {
-                    mHandler.removeCallbacks(mPowerLongPress);
-                    if (mShouldTurnOffOnKeyUp) {
-                        mShouldTurnOffOnKeyUp = false;
-                        boolean gohome, sleeps;
-                        if (code == KeyEvent.KEYCODE_ENDCALL) {
-                            gohome = (mEndcallBehavior
-                                      & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
-                            sleeps = (mEndcallBehavior
-                                      & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
-                        } else {
-                            gohome = false;
-                            sleeps = true;
-                        }
-                        if (keyguardActive
-                                || (sleeps && !gohome)
-                                || (gohome && !goHome() && sleeps)) {
-                            // they must already be on the keyguad or home screen,
-                            // go to sleep instead
-                            Log.d(TAG, "I'm tired mEndcallBehavior=0x"
-                                    + Integer.toHexString(mEndcallBehavior));
-                            result &= ~ACTION_POKE_USER_ACTIVITY;
-                            result |= ACTION_GO_TO_SLEEP;
-                        }
-                        result &= ~ACTION_PASS_TO_USER;
-                    }
+                    Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
                 }
-            } else if (isMediaKey(code)) {
-                // This key needs to be handled even if the screen is off.
-                // If others need to be handled while it's off, this is a reasonable
-                // pattern to follow.
-                if ((result & ACTION_PASS_TO_USER) == 0) {
-                    // Only do this if we would otherwise not pass it to the user. In that
-                    // case, the PhoneWindow class will do the same thing, except it will
-                    // only do it if the showing app doesn't process the key on its own.
-                    KeyEvent keyEvent = new KeyEvent(event.when, event.when,
-                            down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                            code, 0);
-                    mBroadcastWakeLock.acquire();
-                    mHandler.post(new PassHeadsetKey(keyEvent));
+
+                if (!isScreenOn
+                        || (handled && keyCode != KeyEvent.KEYCODE_POWER)
+                        || (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
+                    mShouldTurnOffOnKeyUp = false;
+                } else {
+                    // only try to turn off the screen if we didn't already hang up
+                    mShouldTurnOffOnKeyUp = true;
+                    mHandler.postDelayed(mPowerLongPress,
+                            ViewConfiguration.getGlobalActionKeyTimeout());
+                    result &= ~ACTION_PASS_TO_USER;
                 }
-            } else if (code == KeyEvent.KEYCODE_CALL) {
-                // If an incoming call is ringing, answer it!
-                // (We handle this key here, rather than in the InCallScreen, to make
-                // sure we'll respond to the key even if the InCallScreen hasn't come to
-                // the foreground yet.)
-
-                // We answer the call on the DOWN event, to agree with
-                // the "fallback" behavior in the InCallScreen.
-                if (down) {
-                    try {
-                        ITelephony phoneServ = getPhoneInterface();
-                        if (phoneServ != null) {
-                            if (phoneServ.isRinging()) {
-                                Log.i(TAG, "interceptKeyTq:"
-                                      + " CALL key-down while ringing: Answer the call!");
-                                phoneServ.answerRingingCall();
-
-                                // And *don't* pass this key thru to the current activity
-                                // (which is presumably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                            }
-                        } else {
-                            Log.w(TAG, "CALL button: Unable to find ITelephony interface");
-                        }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
+            } else {
+                mHandler.removeCallbacks(mPowerLongPress);
+                if (mShouldTurnOffOnKeyUp) {
+                    mShouldTurnOffOnKeyUp = false;
+                    boolean gohome, sleeps;
+                    if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
+                        gohome = (mEndcallBehavior
+                                  & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
+                        sleeps = (mEndcallBehavior
+                                  & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
+                    } else {
+                        gohome = false;
+                        sleeps = true;
                     }
+                    if (keyguardActive
+                            || (sleeps && !gohome)
+                            || (gohome && !goHome() && sleeps)) {
+                        // they must already be on the keyguad or home screen,
+                        // go to sleep instead
+                        Log.d(TAG, "I'm tired mEndcallBehavior=0x"
+                                + Integer.toHexString(mEndcallBehavior));
+                        result &= ~ACTION_POKE_USER_ACTIVITY;
+                        result |= ACTION_GO_TO_SLEEP;
+                    }
+                    result &= ~ACTION_PASS_TO_USER;
                 }
-            } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
-                       || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-                // If an incoming call is ringing, either VOLUME key means
-                // "silence ringer".  We handle these keys here, rather than
-                // in the InCallScreen, to make sure we'll respond to them
-                // even if the InCallScreen hasn't come to the foreground yet.
+            }
+        } else if (isMediaKey(keyCode)) {
+            // This key needs to be handled even if the screen is off.
+            // If others need to be handled while it's off, this is a reasonable
+            // pattern to follow.
+            if ((result & ACTION_PASS_TO_USER) == 0) {
+                // Only do this if we would otherwise not pass it to the user. In that
+                // case, the PhoneWindow class will do the same thing, except it will
+                // only do it if the showing app doesn't process the key on its own.
+                long when = whenNanos / 1000000;
+                KeyEvent keyEvent = new KeyEvent(when, when,
+                        down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
+                        keyCode, 0);
+                mBroadcastWakeLock.acquire();
+                mHandler.post(new PassHeadsetKey(keyEvent));
+            }
+        } else if (keyCode == KeyEvent.KEYCODE_CALL) {
+            // If an incoming call is ringing, answer it!
+            // (We handle this key here, rather than in the InCallScreen, to make
+            // sure we'll respond to the key even if the InCallScreen hasn't come to
+            // the foreground yet.)
 
-                // Look for the DOWN event here, to agree with the "fallback"
-                // behavior in the InCallScreen.
-                if (down) {
-                    try {
-                        ITelephony phoneServ = getPhoneInterface();
-                        if (phoneServ != null) {
-                            if (phoneServ.isRinging()) {
-                                Log.i(TAG, "interceptKeyTq:"
-                                      + " VOLUME key-down while ringing: Silence ringer!");
-                                // Silence the ringer.  (It's safe to call this
-                                // even if the ringer has already been silenced.)
-                                phoneServ.silenceRinger();
+            // We answer the call on the DOWN event, to agree with
+            // the "fallback" behavior in the InCallScreen.
+            if (down) {
+                try {
+                    ITelephony phoneServ = getPhoneInterface();
+                    if (phoneServ != null) {
+                        if (phoneServ.isRinging()) {
+                            Log.i(TAG, "interceptKeyTq:"
+                                  + " CALL key-down while ringing: Answer the call!");
+                            phoneServ.answerRingingCall();
 
-                                // And *don't* pass this key thru to the current activity
-                                // (which is probably the InCallScreen.)
-                                result &= ~ACTION_PASS_TO_USER;
-                            }
-                        } else {
-                            Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
+                            // And *don't* pass this key thru to the current activity
+                            // (which is presumably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
+                    } else {
+                        Log.w(TAG, "CALL button: Unable to find ITelephony interface");
                     }
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
+                }
+            }
+        } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
+                   || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
+            // If an incoming call is ringing, either VOLUME key means
+            // "silence ringer".  We handle these keys here, rather than
+            // in the InCallScreen, to make sure we'll respond to them
+            // even if the InCallScreen hasn't come to the foreground yet.
+
+            // Look for the DOWN event here, to agree with the "fallback"
+            // behavior in the InCallScreen.
+            if (down) {
+                try {
+                    ITelephony phoneServ = getPhoneInterface();
+                    if (phoneServ != null) {
+                        if (phoneServ.isRinging()) {
+                            Log.i(TAG, "interceptKeyTq:"
+                                  + " VOLUME key-down while ringing: Silence ringer!");
+                            // Silence the ringer.  (It's safe to call this
+                            // even if the ringer has already been silenced.)
+                            phoneServ.silenceRinger();
+
+                            // And *don't* pass this key thru to the current activity
+                            // (which is probably the InCallScreen.)
+                            result &= ~ACTION_PASS_TO_USER;
+                        }
+                    } else {
+                        Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
+                    }
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
                 }
             }
         }
@@ -2024,35 +1957,6 @@
     };
 
     /** {@inheritDoc} */
-    public boolean isWakeRelMovementTq(int device, int classes,
-            RawInputEvent event) {
-        // if it's tagged with one of the wake bits, it wakes up the device
-        return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
-    }
-
-    /** {@inheritDoc} */
-    public boolean isWakeAbsMovementTq(int device, int classes,
-            RawInputEvent event) {
-        // if it's tagged with one of the wake bits, it wakes up the device
-        return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
-    }
-
-    /**
-     * Given the current state of the world, should this key wake up the device?
-     */
-    protected boolean isWakeKeyTq(RawInputEvent event) {
-        // There are not key maps for trackball devices, but we'd still
-        // like to have pressing it wake the device up, so force it here.
-        int keycode = event.keycode;
-        int flags = event.flags;
-        if (keycode == RawInputEvent.BTN_MOUSE) {
-            flags |= WindowManagerPolicy.FLAG_WAKE;
-        }
-        return (flags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-    }
-
-    /** {@inheritDoc} */
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
         mKeyguardMediator.onScreenTurnedOff(why);
@@ -2165,7 +2069,7 @@
             int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
             int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
             int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
-            int trackballState = mWindowManager.getTrackballScancodeState(RawInputEvent.BTN_MOUSE);
+            int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE);
             mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
             performHapticFeedbackLw(null, mSafeMode
                     ? HapticFeedbackConstants.SAFE_MODE_ENABLED
@@ -2413,13 +2317,6 @@
         return true;
     }
     
-    public void keyFeedbackFromInput(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN
-                && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-    }
-    
     public void screenOnStoppedLw() {
         if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) {
             long curTime = SystemClock.uptimeMillis();
diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java
deleted file mode 100644
index 414b69f..0000000
--- a/services/java/com/android/server/InputDevice.java
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.server;
-
-import android.util.Slog;
-import android.view.Display;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.WindowManagerPolicy;
-
-import java.io.PrintWriter;
-
-public class InputDevice {
-    static final boolean DEBUG_POINTERS = false;
-    static final boolean DEBUG_HACKS = false;
-    
-    /** Amount that trackball needs to move in order to generate a key event. */
-    static final int TRACKBALL_MOVEMENT_THRESHOLD = 6;
-
-    /** Maximum number of pointers we will track and report. */
-    static final int MAX_POINTERS = 10;
-    
-    /**
-     * Slop distance for jumpy pointer detection.
-     * The vertical range of the screen divided by this is our epsilon value.
-     */
-    private static final int JUMPY_EPSILON_DIVISOR = 212;
-    
-    /** Number of jumpy points to drop for touchscreens that need it. */
-    private static final int JUMPY_TRANSITION_DROPS = 3;
-    private static final int JUMPY_DROP_LIMIT = 3;
-    
-    final int id;
-    final int classes;
-    final String name;
-    final AbsoluteInfo absX;
-    final AbsoluteInfo absY;
-    final AbsoluteInfo absPressure;
-    final AbsoluteInfo absSize;
-    
-    long mKeyDownTime = 0;
-    int mMetaKeysState = 0;
-    
-    // For use by KeyInputQueue for keeping track of the current touch
-    // data in the old non-multi-touch protocol.
-    final int[] curTouchVals = new int[MotionEvent.NUM_SAMPLE_DATA * 2];
-    
-    final MotionState mAbs = new MotionState(0, 0);
-    final MotionState mRel = new MotionState(TRACKBALL_MOVEMENT_THRESHOLD,
-            TRACKBALL_MOVEMENT_THRESHOLD);
-    
-    static class MotionState {
-        int xPrecision;
-        int yPrecision;
-        float xMoveScale;
-        float yMoveScale;
-        MotionEvent currentMove = null;
-        boolean changed = false;
-        boolean everChanged = false;
-        long mDownTime = 0;
-        
-        // The currently assigned pointer IDs, corresponding to the last data.
-        int[] mPointerIds = new int[MAX_POINTERS];
-        
-        // This is the last generated pointer data, ordered to match
-        // mPointerIds.
-        boolean mSkipLastPointers;
-        int mLastNumPointers = 0;
-        final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // This is the next set of pointer data being generated.  It is not
-        // in any known order, and will be propagated in to mLastData
-        // as part of mapping it to the appropriate pointer IDs.
-        // Note that we have one extra sample of data here, to help clients
-        // avoid doing bounds checking.
-        int mNextNumPointers = 0;
-        final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
-                                        + MotionEvent.NUM_SAMPLE_DATA];
-        
-        // Used to determine whether we dropped bad data, to avoid doing
-        // it repeatedly.
-        final boolean[] mDroppedBadPoint = new boolean[MAX_POINTERS];
-
-        // Used to count the number of jumpy points dropped.
-        private int mJumpyPointsDropped = 0;
-        
-        // Used to perform averaging of reported coordinates, to smooth
-        // the data and filter out transients during a release.
-        static final int HISTORY_SIZE = 5;
-        int[] mHistoryDataStart = new int[MAX_POINTERS];
-        int[] mHistoryDataEnd = new int[MAX_POINTERS];
-        final int[] mHistoryData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS)
-                                        * HISTORY_SIZE];
-        final int[] mAveragedData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // Temporary data structures for doing the pointer ID mapping.
-        final int[] mLast2Next = new int[MAX_POINTERS];
-        final int[] mNext2Last = new int[MAX_POINTERS];
-        final long[] mNext2LastDistance = new long[MAX_POINTERS];
-        
-        // Temporary data structure for generating the final motion data.
-        final float[] mReportData = new float[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];
-        
-        // This is not used here, but can be used by callers for state tracking.
-        int mAddingPointerOffset = 0;
-        final boolean[] mDown = new boolean[MAX_POINTERS];
-        
-        void dumpIntArray(PrintWriter pw, int[] array) {
-            pw.print("[");
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(array[i]);
-            }
-            pw.print("]");
-        }
-        
-        void dumpBooleanArray(PrintWriter pw, boolean[] array) {
-            pw.print("[");
-            for (int i=0; i<array.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(array[i] ? "true" : "false");
-            }
-            pw.print("]");
-        }
-        
-        void dump(PrintWriter pw, String prefix) {
-            pw.print(prefix); pw.print("xPrecision="); pw.print(xPrecision);
-                    pw.print(" yPrecision="); pw.println(yPrecision);
-            pw.print(prefix); pw.print("xMoveScale="); pw.print(xMoveScale);
-                    pw.print(" yMoveScale="); pw.println(yMoveScale);
-            if (currentMove != null) {
-                pw.print(prefix); pw.print("currentMove="); pw.println(currentMove);
-            }
-            if (changed || mDownTime != 0) {
-                pw.print(prefix); pw.print("changed="); pw.print(changed);
-                        pw.print(" mDownTime="); pw.println(mDownTime);
-            }
-            pw.print(prefix); pw.print("mPointerIds="); dumpIntArray(pw, mPointerIds);
-                    pw.println("");
-            if (mSkipLastPointers || mLastNumPointers != 0) {
-                pw.print(prefix); pw.print("mSkipLastPointers="); pw.print(mSkipLastPointers);
-                        pw.print(" mLastNumPointers="); pw.println(mLastNumPointers);
-                pw.print(prefix); pw.print("mLastData="); dumpIntArray(pw, mLastData);
-                        pw.println("");
-            }
-            if (mNextNumPointers != 0) {
-                pw.print(prefix); pw.print("mNextNumPointers="); pw.println(mNextNumPointers);
-                pw.print(prefix); pw.print("mNextData="); dumpIntArray(pw, mNextData);
-                        pw.println("");
-            }
-            pw.print(prefix); pw.print("mDroppedBadPoint=");
-                    dumpBooleanArray(pw, mDroppedBadPoint); pw.println("");
-            pw.print(prefix); pw.print("mAddingPointerOffset="); pw.println(mAddingPointerOffset);
-            pw.print(prefix); pw.print("mDown=");
-                    dumpBooleanArray(pw, mDown); pw.println("");
-        }
-        
-        MotionState(int mx, int my) {
-            xPrecision = mx;
-            yPrecision = my;
-            xMoveScale = mx != 0 ? (1.0f/mx) : 1.0f;
-            yMoveScale = my != 0 ? (1.0f/my) : 1.0f;
-            for (int i=0; i<MAX_POINTERS; i++) {
-                mPointerIds[i] = i;
-            }
-        }
-        
-        /**
-         * Special hack for devices that have bad screen data: if one of the
-         * points has moved more than a screen height from the last position,
-         * then drop it.
-         */
-        void dropBadPoint(InputDevice dev) {
-            // We should always have absY, but let's be paranoid.
-            if (dev.absY == null) {
-                return;
-            }
-            // Don't do anything if a finger is going down or up.  We run
-            // here before assigning pointer IDs, so there isn't a good
-            // way to do per-finger matching.
-            if (mNextNumPointers != mLastNumPointers) {
-                return;
-            }
-            
-            // We consider a single movement across more than a 7/16 of
-            // the long size of the screen to be bad.  This was a magic value
-            // determined by looking at the maximum distance it is feasible
-            // to actually move in one sample.
-            final int maxDy = ((dev.absY.maxValue-dev.absY.minValue)*7)/16;
-            
-            // Look through all new points and see if any are farther than
-            // acceptable from all previous points.
-            for (int i=mNextNumPointers-1; i>=0; i--) {
-                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                //final int x = mNextData[ioff + MotionEvent.SAMPLE_X];
-                final int y = mNextData[ioff + MotionEvent.SAMPLE_Y];
-                if (DEBUG_HACKS) Slog.v("InputDevice", "Looking at next point #" + i + ": y=" + y);
-                boolean dropped = false;
-                if (!mDroppedBadPoint[i] && mLastNumPointers > 0) {
-                    dropped = true;
-                    int closestDy = -1;
-                    int closestY = -1;
-                    // We will drop this new point if it is sufficiently
-                    // far away from -all- last points.
-                    for (int j=mLastNumPointers-1; j>=0; j--) {
-                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                        //int dx = x - mLastData[joff + MotionEvent.SAMPLE_X];
-                        int dy = y - mLastData[joff + MotionEvent.SAMPLE_Y];
-                        //if (dx < 0) dx = -dx;
-                        if (dy < 0) dy = -dy;
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Comparing with last point #" + j
-                                + ": y=" + mLastData[joff] + " dy=" + dy);
-                        if (dy < maxDy) {
-                            dropped = false;
-                            break;
-                        } else if (closestDy < 0 || dy < closestDy) {
-                            closestDy = dy;
-                            closestY = mLastData[joff + MotionEvent.SAMPLE_Y];
-                        }
-                    }
-                    if (dropped) {
-                        dropped = true;
-                        Slog.i("InputDevice", "Dropping bad point #" + i
-                                + ": newY=" + y + " closestDy=" + closestDy
-                                + " maxDy=" + maxDy);
-                        mNextData[ioff + MotionEvent.SAMPLE_Y] = closestY;
-                        break;
-                    }
-                }
-                mDroppedBadPoint[i] = dropped;
-            }
-        }
-        
-        void dropJumpyPoint(InputDevice dev) {
-            // We should always have absY, but let's be paranoid.
-            if (dev.absY == null) {
-                return;
-            }
-            final int jumpyEpsilon = dev.absY.range / JUMPY_EPSILON_DIVISOR;
-            
-            final int nextNumPointers = mNextNumPointers;
-            final int lastNumPointers = mLastNumPointers;
-            final int[] nextData = mNextData;
-            final int[] lastData = mLastData;
-            
-            if (nextNumPointers != mLastNumPointers) {
-                if (DEBUG_HACKS) {
-                    Slog.d("InputDevice", "Different pointer count " + lastNumPointers + 
-                            " -> " + nextNumPointers);
-                    for (int i = 0; i < nextNumPointers; i++) {
-                        int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                        Slog.d("InputDevice", "Pointer " + i + " (" + 
-                                mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
-                                mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
-                    }
-                }
-                
-                // Just drop the first few events going from 1 to 2 pointers.
-                // They're bad often enough that they're not worth considering.
-                if (lastNumPointers == 1 && nextNumPointers == 2
-                        && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-                    mNextNumPointers = 1;
-                    mJumpyPointsDropped++;
-                } else if (lastNumPointers == 2 && nextNumPointers == 1
-                        && mJumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-                    // The event when we go from 2 -> 1 tends to be messed up too
-                    System.arraycopy(lastData, 0, nextData, 0, 
-                            lastNumPointers * MotionEvent.NUM_SAMPLE_DATA);
-                    mNextNumPointers = lastNumPointers;
-                    mJumpyPointsDropped++;
-                    
-                    if (DEBUG_HACKS) {
-                        for (int i = 0; i < mNextNumPointers; i++) {
-                            int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                            Slog.d("InputDevice", "Pointer " + i + " replaced (" + 
-                                    mNextData[ioff + MotionEvent.SAMPLE_X] + ", " +
-                                    mNextData[ioff + MotionEvent.SAMPLE_Y] + ")");
-                        }
-                    }
-                } else {
-                    mJumpyPointsDropped = 0;
-                    
-                    if (DEBUG_HACKS) {
-                        Slog.d("InputDevice", "Transition - drop limit reset");
-                    }
-                }
-                return;
-            }
-            
-            // A 'jumpy' point is one where the coordinate value for one axis
-            // has jumped to the other pointer's location. No need to do anything
-            // else if we only have one pointer.
-            if (nextNumPointers < 2) {
-                return;
-            }
-            
-            int badPointerIndex = -1;
-            int badPointerReplaceXWith = 0;
-            int badPointerReplaceYWith = 0;
-            int badPointerDistance = Integer.MIN_VALUE;
-            for (int i = nextNumPointers - 1; i >= 0; i--) {
-                boolean dropx = false;
-                boolean dropy = false;
-                
-                // Limit how many times a jumpy point can get dropped.
-                if (mJumpyPointsDropped < JUMPY_DROP_LIMIT) {
-                    final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                    final int x = nextData[ioff + MotionEvent.SAMPLE_X];
-                    final int y = nextData[ioff + MotionEvent.SAMPLE_Y];
-                    
-                    if (DEBUG_HACKS) {
-                        Slog.d("InputDevice", "Point " + i + " (" + x + ", " + y + ")");
-                    }
-
-                    // Check if a touch point is too close to another's coordinates
-                    for (int j = 0; j < nextNumPointers && !dropx && !dropy; j++) {
-                        if (j == i) {
-                            continue;
-                        }
-
-                        final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                        final int xOther = nextData[joff + MotionEvent.SAMPLE_X];
-                        final int yOther = nextData[joff + MotionEvent.SAMPLE_Y];
-
-                        dropx = Math.abs(x - xOther) <= jumpyEpsilon;
-                        dropy = Math.abs(y - yOther) <= jumpyEpsilon;
-                    }
-                    
-                    if (dropx) {
-                        int xreplace = lastData[MotionEvent.SAMPLE_X];
-                        int yreplace = lastData[MotionEvent.SAMPLE_Y];
-                        int distance = Math.abs(yreplace - y);
-                        for (int j = 1; j < lastNumPointers; j++) {
-                            final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                            int lasty = lastData[joff + MotionEvent.SAMPLE_Y];   
-                            int currDist = Math.abs(lasty - y);
-                            if (currDist < distance) {
-                                xreplace = lastData[joff + MotionEvent.SAMPLE_X];
-                                yreplace = lasty;
-                                distance = currDist;
-                            }
-                        }
-                        
-                        int badXDelta = Math.abs(xreplace - x);
-                        if (badXDelta > badPointerDistance) {
-                            badPointerDistance = badXDelta;
-                            badPointerIndex = i;
-                            badPointerReplaceXWith = xreplace;
-                            badPointerReplaceYWith = yreplace;
-                        }
-                    } else if (dropy) {
-                        int xreplace = lastData[MotionEvent.SAMPLE_X];
-                        int yreplace = lastData[MotionEvent.SAMPLE_Y];
-                        int distance = Math.abs(xreplace - x);
-                        for (int j = 1; j < lastNumPointers; j++) {
-                            final int joff = j * MotionEvent.NUM_SAMPLE_DATA;
-                            int lastx = lastData[joff + MotionEvent.SAMPLE_X];   
-                            int currDist = Math.abs(lastx - x);
-                            if (currDist < distance) {
-                                xreplace = lastx;
-                                yreplace = lastData[joff + MotionEvent.SAMPLE_Y];
-                                distance = currDist;
-                            }
-                        }
-                        
-                        int badYDelta = Math.abs(yreplace - y);
-                        if (badYDelta > badPointerDistance) {
-                            badPointerDistance = badYDelta;
-                            badPointerIndex = i;
-                            badPointerReplaceXWith = xreplace;
-                            badPointerReplaceYWith = yreplace;
-                        }
-                    }
-                }
-            }
-            if (badPointerIndex >= 0) {
-                if (DEBUG_HACKS) {
-                    Slog.d("InputDevice", "Replacing bad pointer " + badPointerIndex +
-                            " with (" + badPointerReplaceXWith + ", " + badPointerReplaceYWith +
-                            ")");
-                }
-
-                final int offset = badPointerIndex * MotionEvent.NUM_SAMPLE_DATA;
-                nextData[offset + MotionEvent.SAMPLE_X] = badPointerReplaceXWith;
-                nextData[offset + MotionEvent.SAMPLE_Y] = badPointerReplaceYWith;
-                mJumpyPointsDropped++;
-            } else {
-                mJumpyPointsDropped = 0;
-            }
-        }
-        
-        /**
-         * Special hack for devices that have bad screen data: aggregate and
-         * compute averages of the coordinate data, to reduce the amount of
-         * jitter seen by applications.
-         */
-        int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,
-                int nextNumPointers) {
-            final int numPointers = mLastNumPointers;
-            final int[] rawData = mLastData;
-            if (DEBUG_HACKS) Slog.v("InputDevice", "lastNumPointers=" + lastNumPointers
-                    + " nextNumPointers=" + nextNumPointers
-                    + " numPointers=" + numPointers);
-            for (int i=0; i<numPointers; i++) {
-                final int ioff = i * MotionEvent.NUM_SAMPLE_DATA;
-                // We keep the average data in offsets based on the pointer
-                // ID, so we don't need to move it around as fingers are
-                // pressed and released.
-                final int p = mPointerIds[i];
-                final int poff = p * MotionEvent.NUM_SAMPLE_DATA * HISTORY_SIZE;
-                if (i == upOrDownPointer && lastNumPointers != nextNumPointers) {
-                    if (lastNumPointers < nextNumPointers) {
-                        // This pointer is going down.  Clear its history
-                        // and start fresh.
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer down @ index "
-                                + upOrDownPointer + " id " + mPointerIds[i]);
-                        mHistoryDataStart[i] = 0;
-                        mHistoryDataEnd[i] = 0;
-                        System.arraycopy(rawData, ioff, mHistoryData, poff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        continue;
-                    } else {
-                        // The pointer is going up.  Just fall through to
-                        // recompute the last averaged point (and don't add
-                        // it as a new point to include in the average).
-                        if (DEBUG_HACKS) Slog.v("InputDevice", "Pointer up @ index "
-                                + upOrDownPointer + " id " + mPointerIds[i]);
-                    }
-                } else {
-                    int end = mHistoryDataEnd[i];
-                    int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                    int oldX = mHistoryData[eoff + MotionEvent.SAMPLE_X];
-                    int oldY = mHistoryData[eoff + MotionEvent.SAMPLE_Y];
-                    int newX = rawData[ioff + MotionEvent.SAMPLE_X];
-                    int newY = rawData[ioff + MotionEvent.SAMPLE_Y];
-                    int dx = newX-oldX;
-                    int dy = newY-oldY;
-                    int delta = dx*dx + dy*dy;
-                    if (DEBUG_HACKS) Slog.v("InputDevice", "Delta from last: " + delta);
-                    if (delta >= (75*75)) {
-                        // Magic number, if moving farther than this, turn
-                        // off filtering to avoid lag in response.
-                        mHistoryDataStart[i] = 0;
-                        mHistoryDataEnd[i] = 0;
-                        System.arraycopy(rawData, ioff, mHistoryData, poff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(rawData, ioff, mAveragedData, ioff,
-                                MotionEvent.NUM_SAMPLE_DATA);
-                        continue;
-                    } else {
-                        end++;
-                        if (end >= HISTORY_SIZE) {
-                            end -= HISTORY_SIZE;
-                        }
-                        mHistoryDataEnd[i] = end;
-                        int noff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                        mHistoryData[noff + MotionEvent.SAMPLE_X] = newX;
-                        mHistoryData[noff + MotionEvent.SAMPLE_Y] = newY;
-                        mHistoryData[noff + MotionEvent.SAMPLE_PRESSURE]
-                                = rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
-                        int start = mHistoryDataStart[i];
-                        if (end == start) {
-                            start++;
-                            if (start >= HISTORY_SIZE) {
-                                start -= HISTORY_SIZE;
-                            }
-                            mHistoryDataStart[i] = start;
-                        }
-                    }
-                }
-                
-                // Now compute the average.
-                int start = mHistoryDataStart[i];
-                int end = mHistoryDataEnd[i];
-                int x=0, y=0;
-                int totalPressure = 0;
-                while (start != end) {
-                    int soff = poff + (start*MotionEvent.NUM_SAMPLE_DATA);
-                    int pressure = mHistoryData[soff + MotionEvent.SAMPLE_PRESSURE];
-                    if (pressure <= 0) pressure = 1;
-                    x += mHistoryData[soff + MotionEvent.SAMPLE_X] * pressure;
-                    y += mHistoryData[soff + MotionEvent.SAMPLE_Y] * pressure;
-                    totalPressure += pressure;
-                    start++;
-                    if (start >= HISTORY_SIZE) start = 0;
-                }
-                int eoff = poff + (end*MotionEvent.NUM_SAMPLE_DATA);
-                int pressure = mHistoryData[eoff + MotionEvent.SAMPLE_PRESSURE];
-                if (pressure <= 0) pressure = 1;
-                x += mHistoryData[eoff + MotionEvent.SAMPLE_X] * pressure;
-                y += mHistoryData[eoff + MotionEvent.SAMPLE_Y] * pressure;
-                totalPressure += pressure;
-                x /= totalPressure;
-                y /= totalPressure;
-                if (DEBUG_HACKS) Slog.v("InputDevice", "Averaging " + totalPressure
-                        + " weight: (" + x + "," + y + ")");
-                mAveragedData[ioff + MotionEvent.SAMPLE_X] = x;
-                mAveragedData[ioff + MotionEvent.SAMPLE_Y] = y;
-                mAveragedData[ioff + MotionEvent.SAMPLE_PRESSURE] =
-                        rawData[ioff + MotionEvent.SAMPLE_PRESSURE];
-                mAveragedData[ioff + MotionEvent.SAMPLE_SIZE] =
-                        rawData[ioff + MotionEvent.SAMPLE_SIZE];
-            }
-            return mAveragedData;
-        }
-        
-        private boolean assignPointer(int nextIndex, boolean allowOverlap) {
-            final int lastNumPointers = mLastNumPointers;
-            final int[] next2Last = mNext2Last;
-            final long[] next2LastDistance = mNext2LastDistance;
-            final int[] last2Next = mLast2Next;
-            final int[] lastData = mLastData;
-            final int[] nextData = mNextData;
-            final int id = nextIndex * MotionEvent.NUM_SAMPLE_DATA;
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "assignPointer: nextIndex="
-                    + nextIndex + " dataOff=" + id);
-            final int x1 = nextData[id + MotionEvent.SAMPLE_X];
-            final int y1 = nextData[id + MotionEvent.SAMPLE_Y];
-            
-            long bestDistance = -1;
-            int bestIndex = -1;
-            for (int j=0; j<lastNumPointers; j++) {
-                // If we are not allowing multiple new points to be assigned
-                // to the same old pointer, then skip this one if it is already
-                // detected as a conflict (-2).
-                if (!allowOverlap && last2Next[j] < -1) {
-                    continue;
-                }
-                final int jd = j * MotionEvent.NUM_SAMPLE_DATA;
-                final int xd = lastData[jd + MotionEvent.SAMPLE_X] - x1;
-                final int yd = lastData[jd + MotionEvent.SAMPLE_Y] - y1;
-                final long distance = xd*(long)xd + yd*(long)yd;
-                if (bestDistance == -1 || distance < bestDistance) {
-                    bestDistance = distance;
-                    bestIndex = j;
-                }
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "New index " + nextIndex
-                    + " best old index=" + bestIndex + " (distance="
-                    + bestDistance + ")");
-            next2Last[nextIndex] = bestIndex;
-            next2LastDistance[nextIndex] = bestDistance;
-            
-            if (bestIndex < 0) {
-                return true;
-            }
-            
-            if (last2Next[bestIndex] == -1) {
-                last2Next[bestIndex] = nextIndex;
-                return false;
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "Old index " + bestIndex
-                    + " has multiple best new pointers!");
-            
-            last2Next[bestIndex] = -2;
-            return true;
-        }
-        
-        private int updatePointerIdentifiers() {
-            final int[] lastData = mLastData;
-            final int[] nextData = mNextData;
-            final int nextNumPointers = mNextNumPointers;
-            final int lastNumPointers = mLastNumPointers;
-            
-            if (nextNumPointers == 1 && lastNumPointers == 1) {
-                System.arraycopy(nextData, 0, lastData, 0,
-                        MotionEvent.NUM_SAMPLE_DATA);
-                return -1;
-            }
-            
-            // Clear our old state.
-            final int[] last2Next = mLast2Next;
-            for (int i=0; i<lastNumPointers; i++) {
-                last2Next[i] = -1;
-            }
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice",
-                    "Update pointers: lastNumPointers=" + lastNumPointers
-                    + " nextNumPointers=" + nextNumPointers);
-            
-            // Figure out the closes new points to the previous points.
-            final int[] next2Last = mNext2Last;
-            final long[] next2LastDistance = mNext2LastDistance;
-            boolean conflicts = false;
-            for (int i=0; i<nextNumPointers; i++) {
-                conflicts |= assignPointer(i, true);
-            }
-            
-            // Resolve ambiguities in pointer mappings, when two or more
-            // new pointer locations find their best previous location is
-            // the same.
-            if (conflicts) {
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Resolving conflicts");
-                
-                for (int i=0; i<lastNumPointers; i++) {
-                    if (last2Next[i] != -2) {
-                        continue;
-                    }
-                    
-                    // Note that this algorithm is far from perfect.  Ideally
-                    // we should do something like the one described at
-                    // http://portal.acm.org/citation.cfm?id=997856
-                    
-                    if (DEBUG_POINTERS) Slog.v("InputDevice",
-                            "Resolving last index #" + i);
-                    
-                    int numFound;
-                    do {
-                        numFound = 0;
-                        long worstDistance = 0;
-                        int worstJ = -1;
-                        for (int j=0; j<nextNumPointers; j++) {
-                            if (next2Last[j] != i) {
-                                continue;
-                            }
-                            numFound++;
-                            if (worstDistance < next2LastDistance[j]) {
-                                worstDistance = next2LastDistance[j];
-                                worstJ = j;
-                            }
-                        }
-                        
-                        if (worstJ >= 0) {
-                            if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                    "Worst new pointer: " + worstJ
-                                    + " (distance=" + worstDistance + ")");
-                            if (assignPointer(worstJ, false)) {
-                                // In this case there is no last pointer
-                                // remaining for this new one!
-                                next2Last[worstJ] = -1;
-                            }
-                        }
-                    } while (numFound > 2);
-                }
-            }
-            
-            int retIndex = -1;
-            
-            if (lastNumPointers < nextNumPointers) {
-                // We have one or more new pointers that are down.  Create a
-                // new pointer identifier for one of them.
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Adding new pointer");
-                int nextId = 0;
-                int i=0;
-                while (i < lastNumPointers) {
-                    if (mPointerIds[i] > nextId) {
-                        // Found a hole, insert the pointer here.
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Inserting new pointer at hole " + i);
-                        System.arraycopy(mPointerIds, i, mPointerIds,
-                                i+1, lastNumPointers-i);
-                        System.arraycopy(lastData, i*MotionEvent.NUM_SAMPLE_DATA,
-                                lastData, (i+1)*MotionEvent.NUM_SAMPLE_DATA,
-                                (lastNumPointers-i)*MotionEvent.NUM_SAMPLE_DATA);
-                        System.arraycopy(next2Last, i, next2Last,
-                                i+1, lastNumPointers-i);
-                        break;
-                    }
-                    i++;
-                    nextId++;
-                }
-                
-                if (DEBUG_POINTERS) Slog.v("InputDevice",
-                        "New pointer id " + nextId + " at index " + i);
-                
-                mLastNumPointers++;
-                retIndex = i;
-                mPointerIds[i] = nextId;
-                
-                // And assign this identifier to the first new pointer.
-                for (int j=0; j<nextNumPointers; j++) {
-                    if (next2Last[j] < 0) {
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Assigning new id to new pointer index " + j);
-                        next2Last[j] = i;
-                        break;
-                    }
-                }
-            }
-            
-            // Propagate all of the current data into the appropriate
-            // location in the old data to match the pointer ID that was
-            // assigned to it.
-            for (int i=0; i<nextNumPointers; i++) {
-                int lastIndex = next2Last[i];
-                if (lastIndex >= 0) {
-                    if (DEBUG_POINTERS) Slog.v("InputDevice",
-                            "Copying next pointer index " + i
-                            + " to last index " + lastIndex);
-                    System.arraycopy(nextData, i*MotionEvent.NUM_SAMPLE_DATA,
-                            lastData, lastIndex*MotionEvent.NUM_SAMPLE_DATA,
-                            MotionEvent.NUM_SAMPLE_DATA);
-                }
-            }
-            
-            if (lastNumPointers > nextNumPointers) {
-                // One or more pointers has gone up.  Find the first one,
-                // and adjust accordingly.
-                if (DEBUG_POINTERS) Slog.v("InputDevice", "Removing old pointer");
-                for (int i=0; i<lastNumPointers; i++) {
-                    if (last2Next[i] == -1) {
-                        if (DEBUG_POINTERS) Slog.v("InputDevice",
-                                "Removing old pointer at index " + i);
-                        retIndex = i;
-                        break;
-                    }
-                }
-            }
-            
-            return retIndex;
-        }
-        
-        void removeOldPointer(int index) {
-            final int lastNumPointers = mLastNumPointers;
-            if (index >= 0 && index < lastNumPointers) {
-                System.arraycopy(mPointerIds, index+1, mPointerIds,
-                        index, lastNumPointers-index-1);
-                System.arraycopy(mLastData, (index+1)*MotionEvent.NUM_SAMPLE_DATA,
-                        mLastData, (index)*MotionEvent.NUM_SAMPLE_DATA,
-                        (lastNumPointers-index-1)*MotionEvent.NUM_SAMPLE_DATA);
-                mLastNumPointers--;
-            }
-        }
-        
-        MotionEvent generateAbsMotion(InputDevice device, long curTime,
-                long curTimeNano, Display display, int orientation,
-                int metaState) {
-            
-            if (mSkipLastPointers) {
-                mSkipLastPointers = false;
-                mLastNumPointers = 0;
-            }
-            
-            if (mNextNumPointers <= 0 && mLastNumPointers <= 0) {
-                return null;
-            }
-            
-            final int lastNumPointers = mLastNumPointers;
-            final int nextNumPointers = mNextNumPointers;
-            if (mNextNumPointers > MAX_POINTERS) {
-                Slog.w("InputDevice", "Number of pointers " + mNextNumPointers
-                        + " exceeded maximum of " + MAX_POINTERS);
-                mNextNumPointers = MAX_POINTERS;
-            }
-            
-            int upOrDownPointer = updatePointerIdentifiers();
-            
-            final float[] reportData = mReportData;
-            final int[] rawData;
-            if (KeyInputQueue.BAD_TOUCH_HACK) {
-                rawData = generateAveragedData(upOrDownPointer, lastNumPointers,
-                        nextNumPointers);
-            } else {
-                rawData = mLastData;
-            }
-            
-            final int numPointers = mLastNumPointers;
-            
-            if (DEBUG_POINTERS) Slog.v("InputDevice", "Processing "
-                    + numPointers + " pointers (going from " + lastNumPointers
-                    + " to " + nextNumPointers + ")");
-            
-            for (int i=0; i<numPointers; i++) {
-                final int pos = i * MotionEvent.NUM_SAMPLE_DATA;
-                reportData[pos + MotionEvent.SAMPLE_X] = rawData[pos + MotionEvent.SAMPLE_X];
-                reportData[pos + MotionEvent.SAMPLE_Y] = rawData[pos + MotionEvent.SAMPLE_Y];
-                reportData[pos + MotionEvent.SAMPLE_PRESSURE] = rawData[pos + MotionEvent.SAMPLE_PRESSURE];
-                reportData[pos + MotionEvent.SAMPLE_SIZE] = rawData[pos + MotionEvent.SAMPLE_SIZE];
-            }
-            
-            int action;
-            int edgeFlags = 0;
-            if (nextNumPointers != lastNumPointers) {
-                if (nextNumPointers > lastNumPointers) {
-                    if (lastNumPointers == 0) {
-                        action = MotionEvent.ACTION_DOWN;
-                        mDownTime = curTime;
-                    } else {
-                        action = MotionEvent.ACTION_POINTER_DOWN
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-                    }
-                } else {
-                    if (numPointers == 1) {
-                        action = MotionEvent.ACTION_UP;
-                    } else {
-                        action = MotionEvent.ACTION_POINTER_UP
-                                | (upOrDownPointer << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
-                    }
-                }
-                currentMove = null;
-            } else {
-                action = MotionEvent.ACTION_MOVE;
-            }
-            
-            final int dispW = display.getWidth()-1;
-            final int dispH = display.getHeight()-1;
-            int w = dispW;
-            int h = dispH;
-            if (orientation == Surface.ROTATION_90
-                    || orientation == Surface.ROTATION_270) {
-                int tmp = w;
-                w = h;
-                h = tmp;
-            }
-            
-            final AbsoluteInfo absX = device.absX;
-            final AbsoluteInfo absY = device.absY;
-            final AbsoluteInfo absPressure = device.absPressure;
-            final AbsoluteInfo absSize = device.absSize;
-            for (int i=0; i<numPointers; i++) {
-                final int j = i * MotionEvent.NUM_SAMPLE_DATA;
-            
-                if (absX != null) {
-                    reportData[j + MotionEvent.SAMPLE_X] =
-                            ((reportData[j + MotionEvent.SAMPLE_X]-absX.minValue)
-                                / absX.range) * w;
-                }
-                if (absY != null) {
-                    reportData[j + MotionEvent.SAMPLE_Y] =
-                            ((reportData[j + MotionEvent.SAMPLE_Y]-absY.minValue)
-                                / absY.range) * h;
-                }
-                if (absPressure != null) {
-                    reportData[j + MotionEvent.SAMPLE_PRESSURE] = 
-                            ((reportData[j + MotionEvent.SAMPLE_PRESSURE]-absPressure.minValue)
-                                / (float)absPressure.range);
-                }
-                if (absSize != null) {
-                    reportData[j + MotionEvent.SAMPLE_SIZE] = 
-                            ((reportData[j + MotionEvent.SAMPLE_SIZE]-absSize.minValue)
-                                / (float)absSize.range);
-                }
-                
-                switch (orientation) {
-                    case Surface.ROTATION_90: {
-                        final float temp = reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_X] = reportData[j + MotionEvent.SAMPLE_Y];
-                        reportData[j + MotionEvent.SAMPLE_Y] = w-temp;
-                        break;
-                    }
-                    case Surface.ROTATION_180: {
-                        reportData[j + MotionEvent.SAMPLE_X] = w-reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_Y] = h-reportData[j + MotionEvent.SAMPLE_Y];
-                        break;
-                    }
-                    case Surface.ROTATION_270: {
-                        final float temp = reportData[j + MotionEvent.SAMPLE_X];
-                        reportData[j + MotionEvent.SAMPLE_X] = h-reportData[j + MotionEvent.SAMPLE_Y];
-                        reportData[j + MotionEvent.SAMPLE_Y] = temp;
-                        break;
-                    }
-                }
-            }
-            
-            // We only consider the first pointer when computing the edge
-            // flags, since they are global to the event.
-            if (action == MotionEvent.ACTION_DOWN) {
-                if (reportData[MotionEvent.SAMPLE_X] <= 0) {
-                    edgeFlags |= MotionEvent.EDGE_LEFT;
-                } else if (reportData[MotionEvent.SAMPLE_X] >= dispW) {
-                    edgeFlags |= MotionEvent.EDGE_RIGHT;
-                }
-                if (reportData[MotionEvent.SAMPLE_Y] <= 0) {
-                    edgeFlags |= MotionEvent.EDGE_TOP;
-                } else if (reportData[MotionEvent.SAMPLE_Y] >= dispH) {
-                    edgeFlags |= MotionEvent.EDGE_BOTTOM;
-                }
-            }
-            
-            if (currentMove != null) {
-                if (false) Slog.i("InputDevice", "Adding batch x="
-                        + reportData[MotionEvent.SAMPLE_X]
-                        + " y=" + reportData[MotionEvent.SAMPLE_Y]
-                        + " to " + currentMove);
-                currentMove.addBatch(curTime, reportData, metaState);
-                if (WindowManagerPolicy.WATCH_POINTER) {
-                    Slog.i("KeyInputQueue", "Updating: " + currentMove);
-                }
-                return null;
-            }
-            
-            MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
-                    curTimeNano, action, numPointers, mPointerIds, reportData,
-                    metaState, xPrecision, yPrecision, device.id, edgeFlags);
-            if (action == MotionEvent.ACTION_MOVE) {
-                currentMove = me;
-            }
-            
-            if (nextNumPointers < lastNumPointers) {
-                removeOldPointer(upOrDownPointer);
-            }
-            
-            return me;
-        }
-        
-        boolean hasMore() {
-            return mLastNumPointers != mNextNumPointers;
-        }
-        
-        void finish() {
-            mNextNumPointers = mAddingPointerOffset = 0;
-            mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;
-        }
-        
-        MotionEvent generateRelMotion(InputDevice device, long curTime,
-                long curTimeNano, int orientation, int metaState) {
-            
-            final float[] scaled = mReportData;
-            
-            // For now we only support 1 pointer with relative motions.
-            scaled[MotionEvent.SAMPLE_X] = mNextData[MotionEvent.SAMPLE_X];
-            scaled[MotionEvent.SAMPLE_Y] = mNextData[MotionEvent.SAMPLE_Y];
-            scaled[MotionEvent.SAMPLE_PRESSURE] = 1.0f;
-            scaled[MotionEvent.SAMPLE_SIZE] = 0;
-            int edgeFlags = 0;
-            
-            int action;
-            if (mNextNumPointers != mLastNumPointers) {
-                mNextData[MotionEvent.SAMPLE_X] =
-                        mNextData[MotionEvent.SAMPLE_Y] = 0;
-                if (mNextNumPointers > 0 && mLastNumPointers == 0) {
-                    action = MotionEvent.ACTION_DOWN;
-                    mDownTime = curTime;
-                } else if (mNextNumPointers == 0) {
-                    action = MotionEvent.ACTION_UP;
-                } else {
-                    action = MotionEvent.ACTION_MOVE;
-                }
-                mLastNumPointers = mNextNumPointers;
-                currentMove = null;
-            } else {
-                action = MotionEvent.ACTION_MOVE;
-            }
-            
-            scaled[MotionEvent.SAMPLE_X] *= xMoveScale;
-            scaled[MotionEvent.SAMPLE_Y] *= yMoveScale;
-            switch (orientation) {
-                case Surface.ROTATION_90: {
-                    final float temp = scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_X] = scaled[MotionEvent.SAMPLE_Y];
-                    scaled[MotionEvent.SAMPLE_Y] = -temp;
-                    break;
-                }
-                case Surface.ROTATION_180: {
-                    scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_Y] = -scaled[MotionEvent.SAMPLE_Y];
-                    break;
-                }
-                case Surface.ROTATION_270: {
-                    final float temp = scaled[MotionEvent.SAMPLE_X];
-                    scaled[MotionEvent.SAMPLE_X] = -scaled[MotionEvent.SAMPLE_Y];
-                    scaled[MotionEvent.SAMPLE_Y] = temp;
-                    break;
-                }
-            }
-            
-            if (currentMove != null) {
-                if (false) Slog.i("InputDevice", "Adding batch x="
-                        + scaled[MotionEvent.SAMPLE_X]
-                        + " y=" + scaled[MotionEvent.SAMPLE_Y]
-                        + " to " + currentMove);
-                currentMove.addBatch(curTime, scaled, metaState);
-                if (WindowManagerPolicy.WATCH_POINTER) {
-                    Slog.i("KeyInputQueue", "Updating: " + currentMove);
-                }
-                return null;
-            }
-            
-            MotionEvent me = MotionEvent.obtainNano(mDownTime, curTime,
-                    curTimeNano, action, 1, mPointerIds, scaled, metaState,
-                    xPrecision, yPrecision, device.id, edgeFlags);
-            if (action == MotionEvent.ACTION_MOVE) {
-                currentMove = me;
-            }
-            return me;
-        }
-    }
-    
-    static class AbsoluteInfo {
-        int minValue;
-        int maxValue;
-        int range;
-        int flat;
-        int fuzz;
-        
-        final void dump(PrintWriter pw) {
-            pw.print("minValue="); pw.print(minValue);
-            pw.print(" maxValue="); pw.print(maxValue);
-            pw.print(" range="); pw.print(range);
-            pw.print(" flat="); pw.print(flat);
-            pw.print(" fuzz="); pw.print(fuzz);
-        }
-    };
-    
-    InputDevice(int _id, int _classes, String _name,
-            AbsoluteInfo _absX, AbsoluteInfo _absY,
-            AbsoluteInfo _absPressure, AbsoluteInfo _absSize) {
-        id = _id;
-        classes = _classes;
-        name = _name;
-        absX = _absX;
-        absY = _absY;
-        absPressure = _absPressure;
-        absSize = _absSize;
-    }
-};
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 2ba2914..cdae27c 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -56,7 +56,6 @@
     private final Callbacks mCallbacks;
     private final Context mContext;
     private final WindowManagerService mWindowManagerService;
-    private final WindowManagerPolicy mWindowManagerPolicy;
     private final PowerManager mPowerManager;
     private final PowerManagerService mPowerManagerService;
     
@@ -103,12 +102,10 @@
     
     public InputManager(Context context,
             WindowManagerService windowManagerService,
-            WindowManagerPolicy windowManagerPolicy,
             PowerManager powerManager,
             PowerManagerService powerManagerService) {
         this.mContext = context;
         this.mWindowManagerService = windowManagerService;
-        this.mWindowManagerPolicy = windowManagerPolicy;
         this.mPowerManager = powerManager;
         this.mPowerManagerService = powerManagerService;
         
@@ -325,23 +322,8 @@
         private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
         
         @SuppressWarnings("unused")
-        public boolean isScreenOn() {
-            return mPowerManagerService.isScreenOn();
-        }
-        
-        @SuppressWarnings("unused")
-        public boolean isScreenBright() {
-            return mPowerManagerService.isScreenBright();
-        }
-        
-        @SuppressWarnings("unused")
-        public void virtualKeyFeedback(long whenNanos, int deviceId, int action, int flags,
-                int keyCode, int scanCode, int metaState, long downTimeNanos) {
-            KeyEvent keyEvent = new KeyEvent(downTimeNanos / 1000000,
-                    whenNanos / 1000000, action, keyCode, 0, metaState, scanCode, deviceId,
-                    flags);
-            
-            mWindowManagerService.virtualKeyFeedback(keyEvent);
+        public void virtualKeyDownFeedback() {
+            mWindowManagerService.mInputMonitor.virtualKeyDownFeedback();
         }
         
         @SuppressWarnings("unused")
@@ -356,7 +338,7 @@
         
         @SuppressWarnings("unused")
         public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-            mWindowManagerPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
+            mWindowManagerService.mInputMonitor.notifyLidSwitchChanged(whenNanos, lidOpen);
         }
         
         @SuppressWarnings("unused")
@@ -380,17 +362,17 @@
         }
         
         @SuppressWarnings("unused")
-        public int interceptKeyBeforeQueueing(int deviceId, int type, int scanCode,
-                int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
-            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(deviceId, type,
-                    scanCode, keyCode, policyFlags, value, whenNanos, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+                int policyFlags, boolean isScreenOn) {
+            return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
+                    whenNanos, keyCode, down, policyFlags, isScreenOn);
         }
         
         @SuppressWarnings("unused")
-        public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
-                int metaState, boolean down, int repeatCount, int policyFlags) {
+        public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
+                int flags, int keyCode, int metaState, int repeatCount, int policyFlags) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
-                    keyCode, metaState, down, repeatCount, policyFlags);
+                    action, flags, keyCode, metaState, repeatCount, policyFlags);
         }
         
         @SuppressWarnings("unused")
@@ -401,18 +383,6 @@
         }
         
         @SuppressWarnings("unused")
-        public void goToSleep(long whenNanos) {
-            long when = whenNanos / 1000000;
-            mPowerManager.goToSleep(when);
-        }
-        
-        @SuppressWarnings("unused")
-        public void pokeUserActivity(long eventTimeNanos, int eventType) {
-            long eventTime = eventTimeNanos / 1000000;
-            mPowerManagerService.userActivity(eventTime, false, eventType, false);
-        }
-        
-        @SuppressWarnings("unused")
         public void notifyAppSwitchComing() {
             mWindowManagerService.mInputMonitor.notifyAppSwitchComing();
         }
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
deleted file mode 100644
index f62c7ee..0000000
--- a/services/java/com/android/server/KeyInputQueue.java
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*
- * Copyright (C) 2007 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 com.android.server;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.os.Environment;
-import android.os.LatencyTimer;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.Xml;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.RawInputEvent;
-import android.view.Surface;
-import android.view.WindowManagerPolicy;
-
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-public abstract class KeyInputQueue {
-    static final String TAG = "KeyInputQueue";
-
-    static final boolean DEBUG = false;
-    static final boolean DEBUG_VIRTUAL_KEYS = false;
-    static final boolean DEBUG_POINTERS = false;
-    
-    /**
-     * Turn on some hacks we have to improve the touch interaction with a
-     * certain device whose screen currently is not all that good.
-     */
-    static boolean BAD_TOUCH_HACK = false;
-    
-    /**
-     * Turn on some hacks to improve touch interaction with another device
-     * where touch coordinate data can get corrupted.
-     */
-    static boolean JUMPY_TOUCH_HACK = false;
-    
-    private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
-
-    final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>();
-    final SparseArray<InputDevice> mIgnoredDevices = new SparseArray<InputDevice>();
-    final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>();
-    final HapticFeedbackCallback mHapticFeedbackCallback;
-    
-    int mGlobalMetaState = 0;
-    boolean mHaveGlobalMetaState = false;
-    
-    final QueuedEvent mFirst;
-    final QueuedEvent mLast;
-    QueuedEvent mCache;
-    int mCacheCount;
-
-    Display mDisplay = null;
-    int mDisplayWidth;
-    int mDisplayHeight;
-    
-    int mOrientation = Surface.ROTATION_0;
-    int[] mKeyRotationMap = null;
-    
-    VirtualKey mPressedVirtualKey = null;
-    
-    PowerManager.WakeLock mWakeLock;
-
-    static final int[] KEY_90_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_DOWN,
-    };
-    
-    static final int[] KEY_180_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT,
-    };
-    
-    static final int[] KEY_270_MAP = new int[] {
-        KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_LEFT,
-        KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_UP,
-        KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_RIGHT,
-        KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_DPAD_DOWN,
-    };
-    
-    public static final int FILTER_REMOVE = 0;
-    public static final int FILTER_KEEP = 1;
-    public static final int FILTER_ABORT = -1;
-
-    private static final boolean MEASURE_LATENCY = false;
-    private LatencyTimer lt;
-
-    public interface FilterCallback {
-        int filterEvent(QueuedEvent ev);
-    }
-    
-    public interface HapticFeedbackCallback {
-        void virtualKeyFeedback(KeyEvent event);
-    }
-    
-    static class QueuedEvent {
-        InputDevice inputDevice;
-        long whenNano;
-        int flags; // From the raw event
-        int classType; // One of the class constants in InputEvent
-        Object event;
-        boolean inQueue;
-
-        void copyFrom(QueuedEvent that) {
-            this.inputDevice = that.inputDevice;
-            this.whenNano = that.whenNano;
-            this.flags = that.flags;
-            this.classType = that.classType;
-            this.event = that.event;
-        }
-
-        @Override
-        public String toString() {
-            return "QueuedEvent{"
-                + Integer.toHexString(System.identityHashCode(this))
-                + " " + event + "}";
-        }
-        
-        // not copied
-        QueuedEvent prev;
-        QueuedEvent next;
-    }
-
-    /**
-     * A key that exists as a part of the touch-screen, outside of the normal
-     * display area of the screen.
-     */
-    static class VirtualKey {
-        int scancode;
-        int centerx;
-        int centery;
-        int width;
-        int height;
-        
-        int hitLeft;
-        int hitTop;
-        int hitRight;
-        int hitBottom;
-        
-        InputDevice lastDevice;
-        int lastKeycode;
-        
-        boolean checkHit(int x, int y) {
-            return (x >= hitLeft && x <= hitRight
-                    && y >= hitTop && y <= hitBottom);
-        }
-        
-        void computeHitRect(InputDevice dev, int dw, int dh) {
-            if (dev == lastDevice) {
-                return;
-            }
-            
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "computeHitRect for " + scancode
-                    + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY);
-            
-            lastDevice = dev;
-            
-            int minx = dev.absX.minValue;
-            int maxx = dev.absX.maxValue;
-            
-            int halfw = width/2;
-            int left = centerx - halfw;
-            int right = centerx + halfw;
-            hitLeft = minx + ((left*maxx-minx)/dw);
-            hitRight = minx + ((right*maxx-minx)/dw);
-            
-            int miny = dev.absY.minValue;
-            int maxy = dev.absY.maxValue;
-            
-            int halfh = height/2;
-            int top = centery - halfh;
-            int bottom = centery + halfh;
-            hitTop = miny + ((top*maxy-miny)/dh);
-            hitBottom = miny + ((bottom*maxy-miny)/dh);
-        }
-    }
-
-    private void readVirtualKeys(String deviceName) {
-        try {
-            FileInputStream fis = new FileInputStream(
-                    "/sys/board_properties/virtualkeys." + deviceName);
-            InputStreamReader isr = new InputStreamReader(fis);
-            BufferedReader br = new BufferedReader(isr, 2048);
-            String str = br.readLine();
-            if (str != null) {
-                String[] it = str.split(":");
-                if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
-                final int N = it.length-6;
-                for (int i=0; i<=N; i+=6) {
-                    if (!"0x01".equals(it[i])) {
-                        Slog.w(TAG, "Unknown virtual key type at elem #" + i
-                                + ": " + it[i]);
-                        continue;
-                    }
-                    try {
-                        VirtualKey sb = new VirtualKey();
-                        sb.scancode = Integer.parseInt(it[i+1]);
-                        sb.centerx = Integer.parseInt(it[i+2]);
-                        sb.centery = Integer.parseInt(it[i+3]);
-                        sb.width = Integer.parseInt(it[i+4]);
-                        sb.height = Integer.parseInt(it[i+5]);
-                        if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
-                                + sb.scancode + ": center=" + sb.centerx + ","
-                                + sb.centery + " size=" + sb.width + "x"
-                                + sb.height);
-                        mVirtualKeys.add(sb);
-                    } catch (NumberFormatException e) {
-                        Slog.w(TAG, "Bad number at region " + i + " in: "
-                                + str, e);
-                    }
-                }
-            }
-            br.close();
-        } catch (FileNotFoundException e) {
-            Slog.i(TAG, "No virtual keys found");
-        } catch (IOException e) {
-            Slog.w(TAG, "Error reading virtual keys", e);
-        }
-    }
-
-    private void readExcludedDevices() {
-        // Read partner-provided list of excluded input devices
-        XmlPullParser parser = null;
-        // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
-        File confFile = new File(Environment.getRootDirectory(), EXCLUDED_DEVICES_PATH);
-        FileReader confreader = null;
-        try {
-            confreader = new FileReader(confFile);
-            parser = Xml.newPullParser();
-            parser.setInput(confreader);
-            XmlUtils.beginDocument(parser, "devices");
-
-            while (true) {
-                XmlUtils.nextElement(parser);
-                if (!"device".equals(parser.getName())) {
-                    break;
-                }
-                String name = parser.getAttributeValue(null, "name");
-                if (name != null) {
-                    if (DEBUG) Slog.v(TAG, "addExcludedDevice " + name);
-                    addExcludedDevice(name);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // It's ok if the file does not exist.
-        } catch (Exception e) {
-            Slog.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
-        } finally {
-            try { if (confreader != null) confreader.close(); } catch (IOException e) { }
-        }
-    }
-
-    KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
-        if (MEASURE_LATENCY) {
-            lt = new LatencyTimer(100, 1000);
-        }
-
-        Resources r = context.getResources();
-        BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);
-        
-        JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);
-        
-        mHapticFeedbackCallback = hapticFeedbackCallback;
-        
-        if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
-            readExcludedDevices();
-        }
-        
-        PowerManager pm = (PowerManager)context.getSystemService(
-                                                        Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                                                        "KeyInputQueue");
-        mWakeLock.setReferenceCounted(false);
-
-        mFirst = new QueuedEvent();
-        mLast = new QueuedEvent();
-        mFirst.next = mLast;
-        mLast.prev = mFirst;
-
-        if (! WindowManagerService.ENABLE_NATIVE_INPUT_DISPATCH) {
-            mThread.start();
-        }
-    }
-
-    public void setDisplay(Display display) {
-        mDisplay = display;
-        
-        // We assume at this point that the display dimensions reflect the
-        // natural, unrotated display.  We will perform hit tests for soft
-        // buttons based on that display.
-        mDisplayWidth = display.getWidth();
-        mDisplayHeight = display.getHeight();
-    }
-    
-    public void getInputConfiguration(Configuration config) {
-        synchronized (mFirst) {
-            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
-            config.keyboard = Configuration.KEYBOARD_NOKEYS;
-            config.navigation = Configuration.NAVIGATION_NONAV;
-            
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice d = mDevices.valueAt(i);
-                if (d != null) {
-                    if ((d.classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                        config.touchscreen
-                                = Configuration.TOUCHSCREEN_FINGER;
-                        //Slog.i("foo", "***** HAVE TOUCHSCREEN!");
-                    }
-                    if ((d.classes&RawInputEvent.CLASS_ALPHAKEY) != 0) {
-                        config.keyboard
-                                = Configuration.KEYBOARD_QWERTY;
-                        //Slog.i("foo", "***** HAVE QWERTY!");
-                    }
-                    if ((d.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                        config.navigation
-                                = Configuration.NAVIGATION_TRACKBALL;
-                        //Slog.i("foo", "***** HAVE TRACKBALL!");
-                    } else if ((d.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                        config.navigation
-                                = Configuration.NAVIGATION_DPAD;
-                        //Slog.i("foo", "***** HAVE DPAD!");
-                    }
-                }
-            }
-        }
-    }
-    
-    public int getScancodeState(int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.scancode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetScancodeState(code);
-        }
-    }
-    
-    public int getScancodeState(int deviceId, int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.scancode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetScancodeState(deviceId, code);
-        }
-    }
-    
-    public int getTrackballScancodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                    int res = nativeGetScancodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getDPadScancodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                    int res = nativeGetScancodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getKeycodeState(int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.lastKeycode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetKeycodeState(code);
-        }
-    }
-    
-    public int getKeycodeState(int deviceId, int code) {
-        synchronized (mFirst) {
-            VirtualKey vk = mPressedVirtualKey;
-            if (vk != null) {
-                if (vk.lastKeycode == code) {
-                    return 2;
-                }
-            }
-            return nativeGetKeycodeState(deviceId, code);
-        }
-    }
-    
-    public int getTrackballKeycodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                    int res = nativeGetKeycodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public int getDPadKeycodeState(int code) {
-        synchronized (mFirst) {
-            final int N = mDevices.size();
-            for (int i=0; i<N; i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                if ((dev.classes&RawInputEvent.CLASS_DPAD) != 0) {
-                    int res = nativeGetKeycodeState(dev.id, code);
-                    if (res > 0) {
-                        return res;
-                    }
-                }
-            }
-        }
-        
-        return 0;
-    }
-    
-    public static native String getDeviceName(int deviceId);
-    public static native int getDeviceClasses(int deviceId);
-    public static native void addExcludedDevice(String deviceName);
-    public static native boolean getAbsoluteInfo(int deviceId, int axis,
-            InputDevice.AbsoluteInfo outInfo);
-    public static native int getSwitchState(int sw);
-    public static native int getSwitchState(int deviceId, int sw);
-    public static native int nativeGetScancodeState(int code);
-    public static native int nativeGetScancodeState(int deviceId, int code);
-    public static native int nativeGetKeycodeState(int code);
-    public static native int nativeGetKeycodeState(int deviceId, int code);
-    public static native int scancodeToKeycode(int deviceId, int scancode);
-    public static native boolean hasKeys(int[] keycodes, boolean[] keyExists);
-    
-    public static KeyEvent newKeyEvent(InputDevice device, long downTime,
-            long eventTime, boolean down, int keycode, int repeatCount,
-            int scancode, int flags) {
-        return new KeyEvent(
-                downTime, eventTime,
-                down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                keycode, repeatCount,
-                device != null ? device.mMetaKeysState : 0,
-                device != null ? device.id : -1, scancode,
-                flags | KeyEvent.FLAG_FROM_SYSTEM);
-    }
-    
-    Thread mThread = new Thread("InputDeviceReader") {
-        public void run() {
-            if (DEBUG) Slog.v(TAG, "InputDeviceReader.run()");
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-            
-            RawInputEvent ev = new RawInputEvent();
-            while (true) {
-                try {
-                    InputDevice di;
-
-                    // block, doesn't release the monitor
-                    readEvent(ev);
-
-                    boolean send = false;
-                    boolean configChanged = false;
-                    
-                    if (false) {
-                        Slog.i(TAG, "Input event: dev=0x"
-                                + Integer.toHexString(ev.deviceId)
-                                + " type=0x" + Integer.toHexString(ev.type)
-                                + " scancode=" + ev.scancode
-                                + " keycode=" + ev.keycode
-                                + " value=" + ev.value);
-                    }
-                    
-                    if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
-                        synchronized (mFirst) {
-                            di = newInputDevice(ev.deviceId);
-                            if (di.classes != 0) {
-                                // If this device is some kind of input class,
-                                // we care about it.
-                                mDevices.put(ev.deviceId, di);
-                                if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                                    readVirtualKeys(di.name);
-                                }
-                                // The configuration may have changed because
-                                // of this device.
-                                configChanged = true;
-                            } else {
-                                // We won't do anything with this device.
-                                mIgnoredDevices.put(ev.deviceId, di);
-                                Slog.i(TAG, "Ignoring non-input device: id=0x"
-                                        + Integer.toHexString(di.id)
-                                        + ", name=" + di.name);
-                            }
-                        }
-                    } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
-                        synchronized (mFirst) {
-                            if (false) {
-                                Slog.i(TAG, "Device removed: id=0x"
-                                        + Integer.toHexString(ev.deviceId));
-                            }
-                            di = mDevices.get(ev.deviceId);
-                            if (di != null) {
-                                mDevices.delete(ev.deviceId);
-                                // The configuration may have changed because
-                                // of this device.
-                                configChanged = true;
-                            } else if ((di=mIgnoredDevices.get(ev.deviceId)) != null) {
-                                mIgnoredDevices.remove(ev.deviceId);
-                            } else {
-                                Slog.w(TAG, "Removing bad device id: "
-                                        + Integer.toHexString(ev.deviceId));
-                                continue;
-                            }
-                        }
-                    } else {
-                        di = getInputDevice(ev.deviceId);
-                        if (di == null) {
-                            // This may be some junk from an ignored device.
-                            continue;
-                        }
-                        
-                        // first crack at it
-                        send = preprocessEvent(di, ev);
-
-                        if (ev.type == RawInputEvent.EV_KEY) {
-                            di.mMetaKeysState = makeMetaState(ev.keycode,
-                                    ev.value != 0, di.mMetaKeysState);
-                            mHaveGlobalMetaState = false;
-                        }
-                    }
-
-                    if (configChanged) {
-                        synchronized (mFirst) {
-                            addLocked(di, System.nanoTime(), 0,
-                                    RawInputEvent.CLASS_CONFIGURATION_CHANGED,
-                                    null);
-                        }
-                    }
-                    
-                    if (!send) {
-                        continue;
-                    }
-                    
-                    synchronized (mFirst) {
-                        // NOTE: The event timebase absolutely must be the same
-                        // timebase as SystemClock.uptimeMillis().
-                        //curTime = gotOne ? ev.when : SystemClock.uptimeMillis();
-                        final long curTime = SystemClock.uptimeMillis();
-                        final long curTimeNano = System.nanoTime();
-                        //Slog.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis());
-                        
-                        final int classes = di.classes;
-                        final int type = ev.type;
-                        final int scancode = ev.scancode;
-                        send = false;
-                        
-                        // Is it a key event?
-                        if (type == RawInputEvent.EV_KEY &&
-                                (classes&RawInputEvent.CLASS_KEYBOARD) != 0 &&
-                                (scancode < RawInputEvent.BTN_FIRST ||
-                                        scancode > RawInputEvent.BTN_LAST)) {
-                            boolean down;
-                            if (ev.value != 0) {
-                                down = true;
-                                di.mKeyDownTime = curTime;
-                            } else {
-                                down = false;
-                            }
-                            int keycode = rotateKeyCodeLocked(ev.keycode);
-                            addLocked(di, curTimeNano, ev.flags,
-                                    RawInputEvent.CLASS_KEYBOARD,
-                                    newKeyEvent(di, di.mKeyDownTime, curTime, down,
-                                            keycode, 0, scancode,
-                                            ((ev.flags & WindowManagerPolicy.FLAG_WOKE_HERE) != 0)
-                                             ? KeyEvent.FLAG_WOKE_HERE : 0));
-                            
-                        } else if (ev.type == RawInputEvent.EV_KEY) {
-                            // Single touch protocol: touch going down or up.
-                            if (ev.scancode == RawInputEvent.BTN_TOUCH &&
-                                    (classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mDown[0] = ev.value != 0;
-                            
-                            // Trackball (mouse) protocol: press down or up.
-                            } else if (ev.scancode == RawInputEvent.BTN_MOUSE &&
-                                    (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextNumPointers = ev.value != 0 ? 1 : 0;
-                                send = true;
-                            }
-    
-                        // Process position events from multitouch protocol.
-                        } else if (ev.type == RawInputEvent.EV_ABS &&
-                                (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
-                            if (ev.scancode == RawInputEvent.ABS_MT_TOUCH_MAJOR) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                        + MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_X) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_X] = ev.value;
-                                if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
-                                        + di.mAbs.mAddingPointerOffset
-                                        + " X:" + ev.value);
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_POSITION_Y) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_Y] = ev.value;
-                                if (DEBUG_POINTERS) Slog.v(TAG, "MT @"
-                                        + di.mAbs.mAddingPointerOffset
-                                        + " Y:" + ev.value);
-                            } else if (ev.scancode == RawInputEvent.ABS_MT_WIDTH_MAJOR) {
-                                di.mAbs.changed = true;
-                                di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                    + MotionEvent.SAMPLE_SIZE] = ev.value;
-                            }
-                        
-                        // Process position events from single touch protocol.
-                        } else if (ev.type == RawInputEvent.EV_ABS &&
-                                (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                            if (ev.scancode == RawInputEvent.ABS_X) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_X] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_Y) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_Y] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_PRESSURE) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                                 + MotionEvent.SAMPLE_PRESSURE] = ev.value;
-                            } else if (ev.scancode == RawInputEvent.ABS_TOOL_WIDTH) {
-                                di.mAbs.changed = true;
-                                di.curTouchVals[MotionEvent.SAMPLE_SIZE] = ev.value;
-                                di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA
-                                                 + MotionEvent.SAMPLE_SIZE] = ev.value;
-                            }
-    
-                        // Process movement events from trackball (mouse) protocol.
-                        } else if (ev.type == RawInputEvent.EV_REL &&
-                                (classes&RawInputEvent.CLASS_TRACKBALL) != 0) {
-                            // Add this relative movement into our totals.
-                            if (ev.scancode == RawInputEvent.REL_X) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextData[MotionEvent.SAMPLE_X] += ev.value;
-                            } else if (ev.scancode == RawInputEvent.REL_Y) {
-                                di.mRel.changed = true;
-                                di.mRel.mNextData[MotionEvent.SAMPLE_Y] += ev.value;
-                            }
-                        }
-                        
-                        // Handle multitouch protocol sync: tells us that the
-                        // driver has returned all data for -one- of the pointers
-                        // that is currently down.
-                        if (ev.type == RawInputEvent.EV_SYN
-                                && ev.scancode == RawInputEvent.SYN_MT_REPORT
-                                && di.mAbs != null) {
-                            di.mAbs.changed = true;
-                            if (di.mAbs.mNextData[MotionEvent.SAMPLE_PRESSURE] > 0) {
-                                // If the value is <= 0, the pointer is not
-                                // down, so keep it in the count.
-                                
-                                if (di.mAbs.mNextData[di.mAbs.mAddingPointerOffset
-                                                      + MotionEvent.SAMPLE_PRESSURE] != 0) {
-                                    final int num = di.mAbs.mNextNumPointers+1;
-                                    di.mAbs.mNextNumPointers = num;
-                                    if (DEBUG_POINTERS) Slog.v(TAG,
-                                            "MT_REPORT: now have " + num + " pointers");
-                                    final int newOffset = (num <= InputDevice.MAX_POINTERS)
-                                            ? (num * MotionEvent.NUM_SAMPLE_DATA)
-                                            : (InputDevice.MAX_POINTERS *
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                    di.mAbs.mAddingPointerOffset = newOffset;
-                                    di.mAbs.mNextData[newOffset
-                                            + MotionEvent.SAMPLE_PRESSURE] = 0;
-                                } else {
-                                    if (DEBUG_POINTERS) Slog.v(TAG, "MT_REPORT: no pointer");
-                                }
-                            }
-                        
-                        // Handle general event sync: all data for the current
-                        // event update has been delivered.
-                        } else if (send || (ev.type == RawInputEvent.EV_SYN
-                                && ev.scancode == RawInputEvent.SYN_REPORT)) {
-                            if (mDisplay != null) {
-                                if (!mHaveGlobalMetaState) {
-                                    computeGlobalMetaStateLocked();
-                                }
-                                
-                                MotionEvent me;
-                                
-                                InputDevice.MotionState ms = di.mAbs;
-                                if (ms.changed) {
-                                    ms.everChanged = true;
-                                    ms.changed = false;
-                                    
-                                    if ((classes&(RawInputEvent.CLASS_TOUCHSCREEN
-                                            |RawInputEvent.CLASS_TOUCHSCREEN_MT))
-                                            == RawInputEvent.CLASS_TOUCHSCREEN) {
-                                        ms.mNextNumPointers = 0;
-                                        if (ms.mDown[0]) {
-                                            System.arraycopy(di.curTouchVals, 0,
-                                                    ms.mNextData, 0,
-                                                    MotionEvent.NUM_SAMPLE_DATA);
-                                            ms.mNextNumPointers++;
-                                        }
-                                    }
-                                    
-                                    if (BAD_TOUCH_HACK) {
-                                        ms.dropBadPoint(di);
-                                    }
-                                    if (JUMPY_TOUCH_HACK) {
-                                        ms.dropJumpyPoint(di);
-                                    }
-                                    
-                                    boolean doMotion = !monitorVirtualKey(di,
-                                            ev, curTime, curTimeNano);
-                                    
-                                    if (doMotion && ms.mNextNumPointers > 0
-                                            && (ms.mLastNumPointers == 0
-                                                    || ms.mSkipLastPointers)) {
-                                        doMotion = !generateVirtualKeyDown(di,
-                                                ev, curTime, curTimeNano);
-                                    }
-                                    
-                                    if (doMotion) {
-                                        // XXX Need to be able to generate
-                                        // multiple events here, for example
-                                        // if two fingers change up/down state
-                                        // at the same time.
-                                        do {
-                                            me = ms.generateAbsMotion(di, curTime,
-                                                    curTimeNano, mDisplay,
-                                                    mOrientation, mGlobalMetaState);
-                                            if (DEBUG_POINTERS) Slog.v(TAG, "Absolute: x="
-                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_X]
-                                                    + " y="
-                                                    + di.mAbs.mNextData[MotionEvent.SAMPLE_Y]
-                                                    + " ev=" + me);
-                                            if (me != null) {
-                                                if (WindowManagerPolicy.WATCH_POINTER) {
-                                                    Slog.i(TAG, "Enqueueing: " + me);
-                                                }
-                                                addLocked(di, curTimeNano, ev.flags,
-                                                        RawInputEvent.CLASS_TOUCHSCREEN, me);
-                                            }
-                                        } while (ms.hasMore());
-                                    } else {
-                                        // We are consuming movement in the
-                                        // virtual key area...  but still
-                                        // propagate this to the previous
-                                        // data for comparisons.
-                                        int num = ms.mNextNumPointers;
-                                        if (num > InputDevice.MAX_POINTERS) {
-                                            num = InputDevice.MAX_POINTERS;
-                                        }
-                                        System.arraycopy(ms.mNextData, 0,
-                                                ms.mLastData, 0,
-                                                num * MotionEvent.NUM_SAMPLE_DATA);
-                                        ms.mLastNumPointers = num;
-                                        ms.mSkipLastPointers = true;
-                                    }
-                                    
-                                    ms.finish();
-                                }
-                                
-                                ms = di.mRel;
-                                if (ms.changed) {
-                                    ms.everChanged = true;
-                                    ms.changed = false;
-                                    
-                                    me = ms.generateRelMotion(di, curTime,
-                                            curTimeNano,
-                                            mOrientation, mGlobalMetaState);
-                                    if (false) Slog.v(TAG, "Relative: x="
-                                            + di.mRel.mNextData[MotionEvent.SAMPLE_X]
-                                            + " y="
-                                            + di.mRel.mNextData[MotionEvent.SAMPLE_Y]
-                                            + " ev=" + me);
-                                    if (me != null) {
-                                        addLocked(di, curTimeNano, ev.flags,
-                                                RawInputEvent.CLASS_TRACKBALL, me);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                
-                } catch (RuntimeException exc) {
-                    Slog.e(TAG, "InputReaderThread uncaught exception", exc);
-                }
-            }
-        }
-    };
-
-    private boolean isInsideDisplay(InputDevice dev) {
-        final InputDevice.AbsoluteInfo absx = dev.absX;
-        final InputDevice.AbsoluteInfo absy = dev.absY;
-        final InputDevice.MotionState absm = dev.mAbs;
-        if (absx == null || absy == null || absm == null) {
-            return true;
-        }
-        
-        if (absm.mNextData[MotionEvent.SAMPLE_X] >= absx.minValue
-                && absm.mNextData[MotionEvent.SAMPLE_X] <= absx.maxValue
-                && absm.mNextData[MotionEvent.SAMPLE_Y] >= absy.minValue
-                && absm.mNextData[MotionEvent.SAMPLE_Y] <= absy.maxValue) {
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Input ("
-                    + absm.mNextData[MotionEvent.SAMPLE_X]
-                    + "," + absm.mNextData[MotionEvent.SAMPLE_Y]
-                    + ") inside of display");
-            return true;
-        }
-        
-        return false;
-    }
-    
-    private VirtualKey findVirtualKey(InputDevice dev) {
-        final int N = mVirtualKeys.size();
-        if (N <= 0) {
-            return null;
-        }
-        
-        final InputDevice.MotionState absm = dev.mAbs;
-        for (int i=0; i<N; i++) {
-            VirtualKey sb = mVirtualKeys.get(i);
-            sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight);
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit test ("
-                    + absm.mNextData[MotionEvent.SAMPLE_X] + ","
-                    + absm.mNextData[MotionEvent.SAMPLE_Y] + ") in code "
-                    + sb.scancode + " - (" + sb.hitLeft
-                    + "," + sb.hitTop + ")-(" + sb.hitRight + ","
-                    + sb.hitBottom + ")");
-            if (sb.checkHit(absm.mNextData[MotionEvent.SAMPLE_X],
-                    absm.mNextData[MotionEvent.SAMPLE_Y])) {
-                if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Hit!");
-                return sb;
-            }
-        }
-        
-        return null;
-    }
-    
-    private boolean generateVirtualKeyDown(InputDevice di, RawInputEvent ev,
-            long curTime, long curTimeNano) {
-        if (isInsideDisplay(di)) {
-            // Didn't consume event.
-            return false;
-        }
-        
-        
-        VirtualKey vk = findVirtualKey(di);
-        if (vk != null) {
-            final InputDevice.MotionState ms = di.mAbs;
-            mPressedVirtualKey = vk;
-            vk.lastKeycode = scancodeToKeycode(di.id, vk.scancode);
-            ms.mLastNumPointers = ms.mNextNumPointers;
-            di.mKeyDownTime = curTime;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
-                    "Generate key down for: " + vk.scancode
-                    + " (keycode=" + vk.lastKeycode + ")");
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, true,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-        }
-        
-        // We always consume the event, even if we didn't
-        // generate a key event.  There are two reasons for
-        // this: to avoid spurious touches when holding
-        // the edges of the device near the touchscreen,
-        // and to avoid reporting events if there are virtual
-        // keys on the touchscreen outside of the display
-        // area.
-        // Note that for all of this we are only looking at the
-        // first pointer, since what we are handling here is the
-        // first pointer going down, and this is the coordinate
-        // that will be used to dispatch the event.
-        if (false) {
-            final InputDevice.AbsoluteInfo absx = di.absX;
-            final InputDevice.AbsoluteInfo absy = di.absY;
-            final InputDevice.MotionState absm = di.mAbs;
-            Slog.v(TAG, "Rejecting ("
-                + absm.mNextData[MotionEvent.SAMPLE_X] + ","
-                + absm.mNextData[MotionEvent.SAMPLE_Y] + "): outside of ("
-                + absx.minValue + "," + absy.minValue
-                + ")-(" + absx.maxValue + ","
-                + absx.maxValue + ")");
-        }
-        return true;
-    }
-    
-    private boolean monitorVirtualKey(InputDevice di, RawInputEvent ev,
-            long curTime, long curTimeNano) {
-        VirtualKey vk = mPressedVirtualKey;
-        if (vk == null) {
-            return false;
-        }
-        
-        final InputDevice.MotionState ms = di.mAbs;
-        if (ms.mNextNumPointers <= 0) {
-            mPressedVirtualKey = null;
-            ms.mLastNumPointers = 0;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Generate key up for: " + vk.scancode);
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-            return true;
-            
-        } else if (isInsideDisplay(di)) {
-            // Whoops the pointer has moved into
-            // the display area!  Cancel the
-            // virtual key and start a pointer
-            // motion.
-            mPressedVirtualKey = null;
-            if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Cancel key up for: " + vk.scancode);
-            KeyEvent event = newKeyEvent(di, di.mKeyDownTime, curTime, false,
-                    vk.lastKeycode, 0, vk.scancode,
-                    KeyEvent.FLAG_CANCELED | KeyEvent.FLAG_VIRTUAL_HARD_KEY);
-            mHapticFeedbackCallback.virtualKeyFeedback(event);
-            addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD,
-                    event);
-            ms.mLastNumPointers = 0;
-            return false;
-        }
-        
-        return true;
-    }
-    
-    /**
-     * Returns a new meta state for the given keys and old state.
-     */
-    private static final int makeMetaState(int keycode, boolean down, int old) {
-        int mask;
-        switch (keycode) {
-        case KeyEvent.KEYCODE_ALT_LEFT:
-            mask = KeyEvent.META_ALT_LEFT_ON;
-            break;
-        case KeyEvent.KEYCODE_ALT_RIGHT:
-            mask = KeyEvent.META_ALT_RIGHT_ON;
-            break;
-        case KeyEvent.KEYCODE_SHIFT_LEFT:
-            mask = KeyEvent.META_SHIFT_LEFT_ON;
-            break;
-        case KeyEvent.KEYCODE_SHIFT_RIGHT:
-            mask = KeyEvent.META_SHIFT_RIGHT_ON;
-            break;
-        case KeyEvent.KEYCODE_SYM:
-            mask = KeyEvent.META_SYM_ON;
-            break;
-        default:
-            return old;
-        }
-        int result = ~(KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON)
-                    & (down ? (old | mask) : (old & ~mask));
-        if (0 != (result & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON))) {
-            result |= KeyEvent.META_ALT_ON;
-        }
-        if (0 != (result & (KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_RIGHT_ON))) {
-            result |= KeyEvent.META_SHIFT_ON;
-        }
-        return result;
-    }
-
-    private void computeGlobalMetaStateLocked() {
-        int i = mDevices.size();
-        mGlobalMetaState = 0;
-        while ((--i) >= 0) {
-            mGlobalMetaState |= mDevices.valueAt(i).mMetaKeysState;
-        }
-        mHaveGlobalMetaState = true;
-    }
-    
-    /*
-     * Return true if you want the event to get passed on to the 
-     * rest of the system, and false if you've handled it and want
-     * it dropped.
-     */
-    abstract boolean preprocessEvent(InputDevice device, RawInputEvent event);
-
-    InputDevice getInputDevice(int deviceId) {
-        synchronized (mFirst) {
-            return getInputDeviceLocked(deviceId);
-        }
-    }
-    
-    private InputDevice getInputDeviceLocked(int deviceId) {
-        return mDevices.get(deviceId);
-    }
-
-    public void setOrientation(int orientation) {
-        synchronized(mFirst) {
-            mOrientation = orientation;
-            switch (orientation) {
-                case Surface.ROTATION_90:
-                    mKeyRotationMap = KEY_90_MAP;
-                    break;
-                case Surface.ROTATION_180:
-                    mKeyRotationMap = KEY_180_MAP;
-                    break;
-                case Surface.ROTATION_270:
-                    mKeyRotationMap = KEY_270_MAP;
-                    break;
-                default:
-                    mKeyRotationMap = null;
-                    break;
-            }
-        }
-    }
-    
-    public int rotateKeyCode(int keyCode) {
-        synchronized(mFirst) {
-            return rotateKeyCodeLocked(keyCode);
-        }
-    }
-    
-    private int rotateKeyCodeLocked(int keyCode) {
-        int[] map = mKeyRotationMap;
-        if (map != null) {
-            final int N = map.length;
-            for (int i=0; i<N; i+=2) {
-                if (map[i] == keyCode) {
-                    return map[i+1];
-                }
-            }
-        }
-        return keyCode;
-    }
-    
-    boolean hasEvents() {
-        synchronized (mFirst) {
-            return mFirst.next != mLast;
-        }
-    }
-    
-    /*
-     * returns true if we returned an event, and false if we timed out
-     */
-    QueuedEvent getEvent(long timeoutMS) {
-        long begin = SystemClock.uptimeMillis();
-        final long end = begin+timeoutMS;
-        long now = begin;
-        synchronized (mFirst) {
-            while (mFirst.next == mLast && end > now) {
-                try {
-                    mWakeLock.release();
-                    mFirst.wait(end-now);
-                }
-                catch (InterruptedException e) {
-                }
-                now = SystemClock.uptimeMillis();
-                if (begin > now) {
-                    begin = now;
-                }
-            }
-            if (mFirst.next == mLast) {
-                return null;
-            }
-            QueuedEvent p = mFirst.next;
-            mFirst.next = p.next;
-            mFirst.next.prev = mFirst;
-            p.inQueue = false;
-            return p;
-        }
-    }
-
-    /**
-     * Return true if the queue has an up event pending that corresponds
-     * to the same key as the given key event.
-     */
-    boolean hasKeyUpEvent(KeyEvent origEvent) {
-        synchronized (mFirst) {
-            final int keyCode = origEvent.getKeyCode();
-            QueuedEvent cur = mLast.prev;
-            while (cur.prev != null) {
-                if (cur.classType == RawInputEvent.CLASS_KEYBOARD) {
-                    KeyEvent ke = (KeyEvent)cur.event;
-                    if (ke.getAction() == KeyEvent.ACTION_UP
-                            && ke.getKeyCode() == keyCode) {
-                        return true;
-                    }
-                }
-                cur = cur.prev;
-            }
-        }
-        
-        return false;
-    }
-    
-    void recycleEvent(QueuedEvent ev) {
-        synchronized (mFirst) {
-            //Slog.i(TAG, "Recycle event: " + ev);
-            if (ev.event == ev.inputDevice.mAbs.currentMove) {
-                ev.inputDevice.mAbs.currentMove = null;
-            }
-            if (ev.event == ev.inputDevice.mRel.currentMove) {
-                if (false) Slog.i(TAG, "Detach rel " + ev.event);
-                ev.inputDevice.mRel.currentMove = null;
-                ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_X] = 0;
-                ev.inputDevice.mRel.mNextData[MotionEvent.SAMPLE_Y] = 0;
-            }
-            recycleLocked(ev);
-        }
-    }
-    
-    void filterQueue(FilterCallback cb) {
-        synchronized (mFirst) {
-            QueuedEvent cur = mLast.prev;
-            while (cur.prev != null) {
-                switch (cb.filterEvent(cur)) {
-                    case FILTER_REMOVE:
-                        cur.prev.next = cur.next;
-                        cur.next.prev = cur.prev;
-                        break;
-                    case FILTER_ABORT:
-                        return;
-                }
-                cur = cur.prev;
-            }
-        }
-    }
-    
-    private QueuedEvent obtainLocked(InputDevice device, long whenNano,
-            int flags, int classType, Object event) {
-        QueuedEvent ev;
-        if (mCacheCount == 0) {
-            ev = new QueuedEvent();
-        } else {
-            ev = mCache;
-            ev.inQueue = false;
-            mCache = ev.next;
-            mCacheCount--;
-        }
-        ev.inputDevice = device;
-        ev.whenNano = whenNano;
-        ev.flags = flags;
-        ev.classType = classType;
-        ev.event = event;
-        return ev;
-    }
-
-    private void recycleLocked(QueuedEvent ev) {
-        if (ev.inQueue) {
-            throw new RuntimeException("Event already in queue!");
-        }
-        if (mCacheCount < 10) {
-            mCacheCount++;
-            ev.next = mCache;
-            mCache = ev;
-            ev.inQueue = true;
-        }
-    }
-
-    private void addLocked(InputDevice device, long whenNano, int flags,
-            int classType, Object event) {
-        boolean poke = mFirst.next == mLast;
-
-        QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event);
-        QueuedEvent p = mLast.prev;
-        while (p != mFirst && ev.whenNano < p.whenNano) {
-            p = p.prev;
-        }
-
-        ev.next = p.next;
-        ev.prev = p;
-        p.next = ev;
-        ev.next.prev = ev;
-        ev.inQueue = true;
-
-        if (poke) {
-            long time;
-            if (MEASURE_LATENCY) {
-                time = System.nanoTime();
-            }
-            mFirst.notify();
-            mWakeLock.acquire();
-            if (MEASURE_LATENCY) {
-                lt.sample("1 addLocked-queued event ", System.nanoTime() - time);
-            }
-        }
-    }
-
-    private InputDevice newInputDevice(int deviceId) {
-        int classes = getDeviceClasses(deviceId);
-        String name = getDeviceName(deviceId);
-        InputDevice.AbsoluteInfo absX = null;
-        InputDevice.AbsoluteInfo absY = null;
-        InputDevice.AbsoluteInfo absPressure = null;
-        InputDevice.AbsoluteInfo absSize = null;
-        if (classes != 0) {
-            Slog.i(TAG, "Device added: id=0x" + Integer.toHexString(deviceId)
-                    + ", name=" + name
-                    + ", classes=" + Integer.toHexString(classes));
-            if ((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) {
-                absX = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_POSITION_X, "X");
-                absY = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_POSITION_Y, "Y");
-                absPressure = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_TOUCH_MAJOR, "Pressure");
-                absSize = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_MT_WIDTH_MAJOR, "Size");
-            } else if ((classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
-                absX = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_X, "X");
-                absY = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_Y, "Y");
-                absPressure = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_PRESSURE, "Pressure");
-                absSize = loadAbsoluteInfo(deviceId,
-                        RawInputEvent.ABS_TOOL_WIDTH, "Size");
-            }
-        }
-        
-        return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize);
-    }
-    
-    private InputDevice.AbsoluteInfo loadAbsoluteInfo(int id, int channel,
-            String name) {
-        InputDevice.AbsoluteInfo info = new InputDevice.AbsoluteInfo();
-        if (getAbsoluteInfo(id, channel, info)
-                && info.minValue != info.maxValue) {
-            Slog.i(TAG, "  " + name + ": min=" + info.minValue
-                    + " max=" + info.maxValue
-                    + " flat=" + info.flat
-                    + " fuzz=" + info.fuzz);
-            info.range = info.maxValue-info.minValue;
-            return info;
-        }
-        Slog.i(TAG, "  " + name + ": unknown values");
-        return null;
-    }
-    private static native boolean readEvent(RawInputEvent outEvent);
-    
-    void dump(PrintWriter pw, String prefix) {
-        synchronized (mFirst) {
-            for (int i=0; i<mDevices.size(); i++) {
-                InputDevice dev = mDevices.valueAt(i);
-                pw.print(prefix); pw.print("Device #");
-                        pw.print(mDevices.keyAt(i)); pw.print(" ");
-                        pw.print(dev.name); pw.print(" (classes=0x");
-                        pw.print(Integer.toHexString(dev.classes));
-                        pw.println("):");
-                pw.print(prefix); pw.print("  mKeyDownTime=");
-                        pw.print(dev.mKeyDownTime); pw.print(" mMetaKeysState=");
-                        pw.println(dev.mMetaKeysState);
-                if (dev.absX != null) {
-                    pw.print(prefix); pw.print("  absX: "); dev.absX.dump(pw);
-                            pw.println("");
-                }
-                if (dev.absY != null) {
-                    pw.print(prefix); pw.print("  absY: "); dev.absY.dump(pw);
-                            pw.println("");
-                }
-                if (dev.absPressure != null) {
-                    pw.print(prefix); pw.print("  absPressure: ");
-                            dev.absPressure.dump(pw); pw.println("");
-                }
-                if (dev.absSize != null) {
-                    pw.print(prefix); pw.print("  absSize: ");
-                            dev.absSize.dump(pw); pw.println("");
-                }
-                if (dev.mAbs.everChanged) {
-                    pw.print(prefix); pw.println("  mAbs:");
-                    dev.mAbs.dump(pw, prefix + "    ");
-                }
-                if (dev.mRel.everChanged) {
-                    pw.print(prefix); pw.println("  mRel:");
-                    dev.mRel.dump(pw, prefix + "    ");
-                }
-            }
-            pw.println(" ");
-            for (int i=0; i<mIgnoredDevices.size(); i++) {
-                InputDevice dev = mIgnoredDevices.valueAt(i);
-                pw.print(prefix); pw.print("Ignored Device #");
-                        pw.print(mIgnoredDevices.keyAt(i)); pw.print(" ");
-                        pw.print(dev.name); pw.print(" (classes=0x");
-                        pw.print(Integer.toHexString(dev.classes));
-                        pw.println(")");
-            }
-            pw.println(" ");
-            for (int i=0; i<mVirtualKeys.size(); i++) {
-                VirtualKey vk = mVirtualKeys.get(i);
-                pw.print(prefix); pw.print("Virtual Key #");
-                        pw.print(i); pw.println(":");
-                pw.print(prefix); pw.print("  scancode="); pw.println(vk.scancode);
-                pw.print(prefix); pw.print("  centerx="); pw.print(vk.centerx);
-                        pw.print(" centery="); pw.print(vk.centery);
-                        pw.print(" width="); pw.print(vk.width);
-                        pw.print(" height="); pw.println(vk.height);
-                pw.print(prefix); pw.print("  hitLeft="); pw.print(vk.hitLeft);
-                        pw.print(" hitTop="); pw.print(vk.hitTop);
-                        pw.print(" hitRight="); pw.print(vk.hitRight);
-                        pw.print(" hitBottom="); pw.println(vk.hitBottom);
-                if (vk.lastDevice != null) {
-                    pw.print(prefix); pw.print("  lastDevice=#");
-                            pw.println(vk.lastDevice.id);
-                }
-                if (vk.lastKeycode != 0) {
-                    pw.print(prefix); pw.print("  lastKeycode=");
-                            pw.println(vk.lastKeycode);
-                }
-            }
-            pw.println(" ");
-            pw.print(prefix); pw.print("  Default keyboard: ");
-                    pw.println(SystemProperties.get("hw.keyboards.0.devname"));
-            pw.print(prefix); pw.print("  mGlobalMetaState=");
-                    pw.print(mGlobalMetaState); pw.print(" mHaveGlobalMetaState=");
-                    pw.println(mHaveGlobalMetaState);
-            pw.print(prefix); pw.print("  mDisplayWidth=");
-                    pw.print(mDisplayWidth); pw.print(" mDisplayHeight=");
-                    pw.println(mDisplayHeight);
-            pw.print(prefix); pw.print("  mOrientation=");
-                    pw.println(mOrientation);
-            if (mPressedVirtualKey != null) {
-                pw.print(prefix); pw.print("  mPressedVirtualKey.scancode=");
-                        pw.println(mPressedVirtualKey.scancode);
-            }
-        }
-    }
-}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b4fc15a..d97f30c 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4583,6 +4583,8 @@
         }
     };
 
+    private static final boolean DEBUG_OBB = false;
+
     private static final void sendPackageBroadcast(String action, String pkg,
             Bundle extras, IIntentReceiver finishedReceiver) {
         IActivityManager am = ActivityManagerNative.getDefault();
@@ -4757,6 +4759,27 @@
         mHandler.sendMessage(msg);
     }
 
+    public void setPackageObbPath(String packageName, String path) {
+        if (DEBUG_OBB)
+            Log.v(TAG, "Setting .obb path for " + packageName + " to: " + path);
+        PackageSetting pkgSetting;
+        final int uid = Binder.getCallingUid();
+        boolean allowedByPermission = false;
+        synchronized (mPackages) {
+            pkgSetting = mSettings.mPackages.get(packageName);
+            if (pkgSetting == null) {
+                throw new IllegalArgumentException("Unknown package: " + packageName);
+            }
+            if (!allowedByPermission && (uid != pkgSetting.userId)) {
+                throw new SecurityException("Permission denial: attempt to set .obb file from pid="
+                        + Binder.getCallingPid() + ", uid=" + uid + ", package uid="
+                        + pkgSetting.userId);
+            }
+            pkgSetting.obbPathString = path;
+            mSettings.writeLP();
+        }
+    }
+
     private void processPendingInstall(final InstallArgs args, final int currentStatus) {
         // Queue up an async operation since the package installation may take a little while.
         mHandler.post(new Runnable() {
@@ -7118,6 +7141,7 @@
                     pw.print("    pkg="); pw.println(ps.pkg);
                     pw.print("    codePath="); pw.println(ps.codePathString);
                     pw.print("    resourcePath="); pw.println(ps.resourcePathString);
+                    pw.print("    obbPath="); pw.println(ps.obbPathString);
                     if (ps.pkg != null) {
                         pw.print("    dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
                         pw.print("    targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
@@ -7684,6 +7708,7 @@
         String codePathString;
         File resourcePath;
         String resourcePathString;
+        String obbPathString;
         private long timeStamp;
         private String timeStampString = "0";
         int versionCode;
@@ -8684,6 +8709,9 @@
             if (pkg.installerPackageName != null) {
                 serializer.attribute(null, "installer", pkg.installerPackageName);
             }
+            if (pkg.obbPathString != null) {
+                serializer.attribute(null, "obbPath", pkg.obbPathString);
+            }
             pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
             if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                 serializer.startTag(null, "perms");
@@ -9060,6 +9088,7 @@
             String sharedIdStr = null;
             String codePathStr = null;
             String resourcePathStr = null;
+            String obbPathStr = null;
             String systemStr = null;
             String installerPackageName = null;
             String uidError = null;
@@ -9077,6 +9106,7 @@
                 sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
                 codePathStr = parser.getAttributeValue(null, "codePath");
                 resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+                obbPathStr = parser.getAttributeValue(null, "obbPath");
                 version = parser.getAttributeValue(null, "version");
                 if (version != null) {
                     try {
@@ -9174,6 +9204,7 @@
             if (packageSetting != null) {
                 packageSetting.uidError = "true".equals(uidError);
                 packageSetting.installerPackageName = installerPackageName;
+                packageSetting.obbPathString = obbPathStr;
                 final String enabledStr = parser.getAttributeValue(null, "enabled");
                 if (enabledStr != null) {
                     if (enabledStr.equalsIgnoreCase("true")) {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 493a348..e9d5efc 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -247,6 +247,9 @@
     private static final boolean mSpew = false;
     private static final boolean mDebugProximitySensor = (true || mSpew);
     private static final boolean mDebugLightSensor = (false || mSpew);
+    
+    private native void nativeInit();
+    private native void nativeSetPowerState(boolean screenOn, boolean screenBright);
 
     /*
     static PrintStream mLog;
@@ -481,6 +484,11 @@
                 }
             }
         }
+        
+        nativeInit();
+        synchronized (mLocks) {
+            updateNativePowerStateLocked();
+        }
     }
 
     void initInThread() {
@@ -1557,8 +1565,16 @@
                     }
                 }
             }
+            
+            updateNativePowerStateLocked();
         }
     }
+    
+    private void updateNativePowerStateLocked() {
+        nativeSetPowerState(
+                (mPowerState & SCREEN_ON_BIT) != 0,
+                (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+    }
 
     private int screenOffFinishedAnimatingLocked(int reason) {
         // I don't think we need to check the current state here because all of these
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 483f9eb..38f1e1f 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -48,7 +48,6 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
-import com.android.server.KeyInputQueue.QueuedEvent;
 import com.android.server.am.BatteryStatsService;
 
 import android.Manifest;
@@ -95,6 +94,7 @@
 import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
 import android.view.IApplicationToken;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -105,7 +105,6 @@
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
-import android.view.RawInputEvent;
 import android.view.Surface;
 import android.view.SurfaceSession;
 import android.view.View;
@@ -137,7 +136,7 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
+        implements Watchdog.Monitor {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_FOCUS = false;
@@ -159,17 +158,12 @@
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean HIDE_STACK_CRAWLS = true;
     static final boolean MEASURE_LATENCY = false;
-    static final boolean ENABLE_NATIVE_INPUT_DISPATCH =
-        WindowManagerPolicy.ENABLE_NATIVE_INPUT_DISPATCH;
     static private LatencyTimer lt;
 
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean BLUR = true;
     static final boolean localLOGV = DEBUG;
 
-    /** How long to wait for subsequent key repeats, in milliseconds */
-    static final int KEY_REPEAT_DELAY = 50;
-
     /** How much to multiply the policy's type layer, to reserve room
      * for multiple windows of the same type and Z-ordering adjustment
      * with TYPE_LAYER_OFFSET. */
@@ -210,34 +204,11 @@
     // Default input dispatching timeout in nanoseconds.
     private static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
-    static final int INJECT_FAILED = 0;
-    static final int INJECT_SUCCEEDED = 1;
-    static final int INJECT_NO_PERMISSION = -1;
-
     static final int UPDATE_FOCUS_NORMAL = 0;
     static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1;
     static final int UPDATE_FOCUS_PLACING_SURFACES = 2;
     static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3;
 
-    /** The minimum time between dispatching touch events. */
-    int mMinWaitTimeBetweenTouchEvents = 1000 / 35;
-
-    // Last touch event time
-    long mLastTouchEventTime = 0;
-
-    // Last touch event type
-    int mLastTouchEventType = OTHER_EVENT;
-
-    // Time to wait before calling useractivity again. This saves CPU usage
-    // when we get a flood of touch events.
-    static final int MIN_TIME_BETWEEN_USERACTIVITIES = 1000;
-
-    // Last time we call user activity
-    long mLastUserActivityCallTime = 0;
-
-    // Last time we updated battery stats
-    long mLastBatteryStatsCallTime = 0;
-
     private static final String SYSTEM_SECURE = "ro.secure";
     private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
 
@@ -486,7 +457,6 @@
     float mLastWallpaperY = -1;
     float mLastWallpaperXStep = -1;
     float mLastWallpaperYStep = -1;
-    boolean mSendingPointersToWallpaper = false;
     // This is set when we are waiting for a wallpaper to tell us it is done
     // changing its scroll position.
     WindowState mWaitingOnWallpaper;
@@ -504,10 +474,7 @@
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
 
-    final KeyWaiter mKeyWaiter = new KeyWaiter();
-    final KeyQ mQueue;
     final InputManager mInputManager;
-    final InputDispatcherThread mInputThread;
 
     // Who is holding the screen on.
     Session mHoldingScreenOn;
@@ -523,8 +490,6 @@
 
     private ViewServer mViewServer;
 
-    final Rect mTempRect = new Rect();
-
     final Configuration mTempConfiguration = new Configuration();
     int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
 
@@ -652,28 +617,11 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        int max_events_per_sec = 35;
-        try {
-            max_events_per_sec = Integer.parseInt(SystemProperties
-                    .get("windowsmgr.max_events_per_sec"));
-            if (max_events_per_sec < 1) {
-                max_events_per_sec = 35;
-            }
-        } catch (NumberFormatException e) {
-        }
-        mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
-
         mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                 "KEEP_SCREEN_ON_FLAG");
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager = new InputManager(context, this, mPolicy, pmc, mPowerManager);
-        } else {
-            mInputManager = null;
-        }
-        mQueue = new KeyQ();
-        mInputThread = new InputDispatcherThread();
+        mInputManager = new InputManager(context, this, pmc, mPowerManager);
 
         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
         thr.start();
@@ -687,11 +635,7 @@
             }
         }
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager.start();
-        } else {
-            mInputThread.start();
-        }
+        mInputManager.start();
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
@@ -1817,70 +1761,6 @@
             }
         }
     }
-
-    void sendPointerToWallpaperLocked(WindowState srcWin,
-            MotionEvent pointer, long eventTime) {
-        int curTokenIndex = mWallpaperTokens.size();
-        while (curTokenIndex > 0) {
-            curTokenIndex--;
-            WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            int curWallpaperIndex = token.windows.size();
-            while (curWallpaperIndex > 0) {
-                curWallpaperIndex--;
-                WindowState wallpaper = token.windows.get(curWallpaperIndex);
-                if ((wallpaper.mAttrs.flags &
-                        WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
-                    continue;
-                }
-                try {
-                    MotionEvent ev = MotionEvent.obtainNoHistory(pointer);
-                    if (srcWin != null) {
-                        ev.offsetLocation(srcWin.mFrame.left-wallpaper.mFrame.left,
-                                srcWin.mFrame.top-wallpaper.mFrame.top);
-                    } else {
-                        ev.offsetLocation(-wallpaper.mFrame.left, -wallpaper.mFrame.top);
-                    }
-                    switch (pointer.getAction()) {
-                        case MotionEvent.ACTION_DOWN:
-                            mSendingPointersToWallpaper = true;
-                            break;
-                        case MotionEvent.ACTION_UP:
-                            mSendingPointersToWallpaper = false;
-                            break;
-                    }
-                    wallpaper.mClient.dispatchPointer(ev, eventTime, false);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failure sending pointer to wallpaper", e);
-                }
-            }
-        }
-    }
-
-    void dispatchPointerElsewhereLocked(WindowState srcWin, WindowState relWin,
-            MotionEvent pointer, long eventTime, boolean skipped) {
-        if (relWin != null) {
-            mPolicy.dispatchedPointerEventLw(pointer, relWin.mFrame.left, relWin.mFrame.top);
-        } else {
-            mPolicy.dispatchedPointerEventLw(pointer, 0, 0);
-        }
-        
-        // If we sent an initial down to the wallpaper, then continue
-        // sending events until the final up.
-        if (mSendingPointersToWallpaper) {
-            if (skipped) {
-                Slog.i(TAG, "Sending skipped pointer to wallpaper!");
-            }
-            sendPointerToWallpaperLocked(relWin, pointer, eventTime);
-            
-        // If we are on top of the wallpaper, then the wallpaper also
-        // gets to see this movement.
-        } else if (srcWin != null
-                && pointer.getAction() == MotionEvent.ACTION_DOWN
-                && mWallpaperTarget == srcWin
-                && srcWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
-            sendPointerToWallpaperLocked(relWin, pointer, eventTime);
-        }
-    }
     
     public int addWindow(Session session, IWindow client,
             WindowManager.LayoutParams attrs, int viewVisibility,
@@ -1903,12 +1783,7 @@
                 mDisplay = wm.getDefaultDisplay();
                 mInitialDisplayWidth = mDisplay.getWidth();
                 mInitialDisplayHeight = mDisplay.getHeight();
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputManager.setDisplaySize(0,
-                            mInitialDisplayWidth, mInitialDisplayHeight);
-                } else {
-                    mQueue.setDisplay(mDisplay);
-                }
+                mInputManager.setDisplaySize(0, mInitialDisplayWidth, mInitialDisplayHeight);
                 reportNewConfig = true;
             }
 
@@ -2002,15 +1877,13 @@
                 return res;
             }
             
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                if (outInputChannel != null) {
-                    String name = win.makeInputChannelName();
-                    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
-                    win.mInputChannel = inputChannels[0];
-                    inputChannels[1].transferToBinderOutParameter(outInputChannel);
-                    
-                    mInputManager.registerInputChannel(win.mInputChannel);
-                }
+            if (outInputChannel != null) {
+                String name = win.makeInputChannelName();
+                InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
+                win.mInputChannel = inputChannels[0];
+                inputChannels[1].transferToBinderOutParameter(outInputChannel);
+                
+                mInputManager.registerInputChannel(win.mInputChannel);
             }
 
             // From now on, no exceptions or errors allowed!
@@ -2186,14 +2059,7 @@
     }
 
     private void removeWindowInnerLocked(Session session, WindowState win) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.windowIsBeingRemovedLw(win);
-        } else {
-            mKeyWaiter.finishedKey(session, win.mClient, true,
-                    KeyWaiter.RETURN_NOTHING);
-            mKeyWaiter.releasePendingPointerLocked(win.mSession);
-            mKeyWaiter.releasePendingTrackballLocked(win.mSession);
-        }
+        mInputMonitor.windowIsBeingRemovedLw(win);
 
         win.mRemoved = true;
 
@@ -2561,12 +2427,7 @@
                               applyAnimationLocked(win, transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBecomingInvisibleLw(win);
-                            } else {
-                                mKeyWaiter.finishedKey(session, client, true,
-                                        KeyWaiter.RETURN_NOTHING);
-                            }
+                            mInputMonitor.windowIsBecomingInvisibleLw(win);
                         } else if (win.isAnimating()) {
                             // Currently in a hide animation... turn this into
                             // an exit.
@@ -3027,12 +2888,7 @@
                         if (win.isVisibleNow()) {
                             applyAnimationLocked(win,
                                     WindowManagerPolicy.TRANSIT_EXIT, false);
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBeingRemovedLw(win);
-                            } else {
-                                mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
-                                        KeyWaiter.RETURN_NOTHING);
-                            }
+                            mInputMonitor.windowIsBeingRemovedLw(win);
                             changed = true;
                         }
                     }
@@ -3349,12 +3205,8 @@
                 if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
                 changed = mFocusedApp != null;
                 mFocusedApp = null;
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (changed) {
-                        mInputMonitor.setFocusedAppLw(null);
-                    }
-                } else {
-                    mKeyWaiter.tickle();
+                if (changed) {
+                    mInputMonitor.setFocusedAppLw(null);
                 }
             } else {
                 AppWindowToken newFocus = findAppWindowToken(token);
@@ -3365,12 +3217,8 @@
                 changed = mFocusedApp != newFocus;
                 mFocusedApp = newFocus;
                 if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp);
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    if (changed) {
-                        mInputMonitor.setFocusedAppLw(newFocus);
-                    }
-                } else {
-                    mKeyWaiter.tickle();
+                if (changed) {
+                    mInputMonitor.setFocusedAppLw(newFocus);
                 }
             }
 
@@ -3682,12 +3530,7 @@
                         applyAnimationLocked(win,
                                 WindowManagerPolicy.TRANSIT_EXIT, false);
                     }
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.windowIsBecomingInvisibleLw(win);
-                    } else {
-                        mKeyWaiter.finishedKey(win.mSession, win.mClient, true,
-                                KeyWaiter.RETURN_NOTHING);
-                    }
+                    mInputMonitor.windowIsBecomingInvisibleLw(win);
                     changed = true;
                 }
             }
@@ -3972,11 +3815,7 @@
                     if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
                     mFocusedApp = null;
                     updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL);
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.setFocusedAppLw(null);
-                    } else {
-                        mKeyWaiter.tickle();
-                    }
+                    mInputMonitor.setFocusedAppLw(null);
                 }
             } else {
                 Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
@@ -4441,11 +4280,7 @@
                 "getSwitchState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getSwitchState(sw);
-        } else {
-            return KeyInputQueue.getSwitchState(sw);
-        }
+        return mInputManager.getSwitchState(sw);
     }
 
     public int getSwitchStateForDevice(int devid, int sw) {
@@ -4453,11 +4288,7 @@
                 "getSwitchStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getSwitchState(devid, sw);
-        } else {
-            return KeyInputQueue.getSwitchState(devid, sw);
-        }
+        return mInputManager.getSwitchState(devid, sw);
     }
 
     public int getScancodeState(int sw) {
@@ -4465,11 +4296,7 @@
                 "getScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getScancodeState(sw);
-        } else {
-            return mQueue.getScancodeState(sw);
-        }
+        return mInputManager.getScancodeState(sw);
     }
 
     public int getScancodeStateForDevice(int devid, int sw) {
@@ -4477,11 +4304,7 @@
                 "getScancodeStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getScancodeState(devid, sw);
-        } else {
-            return mQueue.getScancodeState(devid, sw);
-        }
+        return mInputManager.getScancodeState(devid, sw);
     }
 
     public int getTrackballScancodeState(int sw) {
@@ -4489,11 +4312,7 @@
                 "getTrackballScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getTrackballScancodeState(sw);
-        } else {
-            return mQueue.getTrackballScancodeState(sw);
-        }
+        return mInputManager.getTrackballScancodeState(sw);
     }
 
     public int getDPadScancodeState(int sw) {
@@ -4501,11 +4320,7 @@
                 "getDPadScancodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getDPadScancodeState(sw);
-        } else {
-            return mQueue.getDPadScancodeState(sw);
-        }
+        return mInputManager.getDPadScancodeState(sw);
     }
 
     public int getKeycodeState(int sw) {
@@ -4513,11 +4328,7 @@
                 "getKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getKeycodeState(sw);
-        } else {
-            return mQueue.getKeycodeState(sw);
-        }
+        return mInputManager.getKeycodeState(sw);
     }
 
     public int getKeycodeStateForDevice(int devid, int sw) {
@@ -4525,11 +4336,7 @@
                 "getKeycodeStateForDevice()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getKeycodeState(devid, sw);
-        } else {
-            return mQueue.getKeycodeState(devid, sw);
-        }
+        return mInputManager.getKeycodeState(devid, sw);
     }
 
     public int getTrackballKeycodeState(int sw) {
@@ -4537,11 +4344,7 @@
                 "getTrackballKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getTrackballKeycodeState(sw);
-        } else {
-            return mQueue.getTrackballKeycodeState(sw);
-        }
+        return mInputManager.getTrackballKeycodeState(sw);
     }
 
     public int getDPadKeycodeState(int sw) {
@@ -4549,19 +4352,11 @@
                 "getDPadKeycodeState()")) {
             throw new SecurityException("Requires READ_INPUT_STATE permission");
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.getDPadKeycodeState(sw);
-        } else {
-            return mQueue.getDPadKeycodeState(sw);
-        }
+        return mInputManager.getDPadKeycodeState(sw);
     }
 
     public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            return mInputManager.hasKeys(keycodes, keyExists);
-        } else {
-            return KeyInputQueue.hasKeys(keycodes, keyExists);
-        }
+        return mInputManager.hasKeys(keycodes, keyExists);
     }
 
     public void enableScreenAfterBoot() {
@@ -4706,11 +4501,7 @@
             mLayoutNeeded = true;
             startFreezingDisplayLocked();
             Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                mInputManager.setDisplayOrientation(0, rotation);
-            } else {
-                mQueue.setOrientation(rotation);
-            }
+            mInputManager.setDisplayOrientation(0, rotation);
             if (mDisplayEnabled) {
                 Surface.setOrientation(0, rotation, animFlags);
             }
@@ -5041,11 +4832,8 @@
         if (mDisplay == null) {
             return false;
         }
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputManager.getInputConfiguration(config);
-        } else {
-            mQueue.getInputConfiguration(config);
-        }
+        
+        mInputManager.getInputConfiguration(config);
 
         // Use the effective "visual" dimensions based on current rotation
         final boolean rotated = (mRotation == Surface.ROTATION_90
@@ -5326,6 +5114,13 @@
             mTempInputWindows.clear();
         }
         
+        /* Provides feedback for a virtual key down. */
+        public void virtualKeyDownFeedback() {
+            synchronized (mWindowMap) {
+                mPolicy.performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+            }
+        }
+        
         /* Notifies that an app switch key (BACK / HOME) has just been pressed.
          * This essentially starts a .5 second timeout for the application to process
          * subsequent input events while waiting for the app switch to occur.  If it takes longer
@@ -5334,30 +5129,28 @@
         public void notifyAppSwitchComing() {
             // TODO Not implemented yet.  Should go in the native side.
         }
-
+        
+        /* Notifies that the lid switch changed state. */
+        public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
+            mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
+        }
+        
         /* Provides an opportunity for the window manager policy to intercept early key
          * processing as soon as the key has been read from the device. */
-        public int interceptKeyBeforeQueueing(int deviceId, int type, int scanCode,
-                int keyCode, int policyFlags, int value, long whenNanos, boolean isScreenOn) {
-            RawInputEvent event = new RawInputEvent();
-            event.deviceId = deviceId;
-            event.type = type;
-            event.scancode = scanCode;
-            event.keycode = keyCode;
-            event.flags = policyFlags;
-            event.value = value;
-            event.when = whenNanos / 1000000;
-            
-            return mPolicy.interceptKeyTq(event, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
+                int policyFlags, boolean isScreenOn) {
+            return mPolicy.interceptKeyBeforeQueueing(whenNanos,
+                    keyCode, down, policyFlags, isScreenOn);
         }
         
         /* Provides an opportunity for the window manager policy to process a key before
          * ordinary dispatch. */
-        public boolean interceptKeyBeforeDispatching(InputChannel focus, int keyCode,
-                int metaState, boolean down, int repeatCount, int policyFlags) {
+        public boolean interceptKeyBeforeDispatching(InputChannel focus,
+                int action, int flags, int keyCode, int metaState, int repeatCount,
+                int policyFlags) {
             WindowState windowState = getWindowStateForInputChannel(focus);
-            return mPolicy.interceptKeyTi(windowState, keyCode, metaState, down, repeatCount,
-                    policyFlags);
+            return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
+                    keyCode, metaState, repeatCount, policyFlags);
         }
         
         /* Called when the current input focus changes.
@@ -5496,450 +5289,6 @@
         }
     }
 
-    private final void wakeupIfNeeded(WindowState targetWin, int eventType) {
-        long curTime = SystemClock.uptimeMillis();
-
-        if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) {
-            if (mLastTouchEventType == eventType &&
-                    (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) {
-                return;
-            }
-            mLastUserActivityCallTime = curTime;
-            mLastTouchEventType = eventType;
-        }
-
-        if (targetWin == null
-                || targetWin.mAttrs.type != WindowManager.LayoutParams.TYPE_KEYGUARD) {
-            mPowerManager.userActivity(curTime, false, eventType, false);
-        }
-    }
-
-    // tells if it's a cheek event or not -- this function is stateful
-    private static final int EVENT_NONE = 0;
-    private static final int EVENT_UNKNOWN = 0;
-    private static final int EVENT_CHEEK = 0;
-    private static final int EVENT_IGNORE_DURATION = 300; // ms
-    private static final float CHEEK_THRESHOLD = 0.6f;
-    private int mEventState = EVENT_NONE;
-    private float mEventSize;
-
-    private int eventType(MotionEvent ev) {
-        float size = ev.getSize();
-        switch (ev.getAction()) {
-        case MotionEvent.ACTION_DOWN:
-            mEventSize = size;
-            return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_EVENT;
-        case MotionEvent.ACTION_UP:
-            if (size > mEventSize) mEventSize = size;
-            return (mEventSize > CHEEK_THRESHOLD) ? CHEEK_EVENT : TOUCH_UP_EVENT;
-        case MotionEvent.ACTION_MOVE:
-            final int N = ev.getHistorySize();
-            if (size > mEventSize) mEventSize = size;
-            if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
-            for (int i=0; i<N; i++) {
-                size = ev.getHistoricalSize(i);
-                if (size > mEventSize) mEventSize = size;
-                if (mEventSize > CHEEK_THRESHOLD) return CHEEK_EVENT;
-            }
-            if (ev.getEventTime() < ev.getDownTime() + EVENT_IGNORE_DURATION) {
-                return TOUCH_EVENT;
-            } else {
-                return LONG_TOUCH_EVENT;
-            }
-        default:
-            // not good
-            return OTHER_EVENT;
-        }
-    }
-    
-    private boolean mFatTouch; // remove me together with dispatchPointer
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchPointer(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
-        if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Slog.v(TAG,
-                "dispatchPointer " + ev);
-
-        if (MEASURE_LATENCY) {
-            lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano);
-        }
-
-        Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, true, false, pid, uid);
-
-        if (MEASURE_LATENCY) {
-            lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano);
-        }
-
-        int action = ev.getAction();
-
-        if (action == MotionEvent.ACTION_UP) {
-            // let go of our target
-            mKeyWaiter.mMotionTarget = null;
-            mPowerManager.logPointerUpEvent();
-        } else if (action == MotionEvent.ACTION_DOWN) {
-            mPowerManager.logPointerDownEvent();
-        }
-
-        if (targetObj == null) {
-            // In this case we are either dropping the event, or have received
-            // a move or up without a down.  It is common to receive move
-            // events in such a way, since this means the user is moving the
-            // pointer without actually pressing down.  All other cases should
-            // be atypical, so let's log them.
-            if (action != MotionEvent.ACTION_MOVE) {
-                Slog.w(TAG, "No window to dispatch pointer action " + ev.getAction());
-            }
-            synchronized (mWindowMap) {
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
-            }
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_FAILED;
-        }
-        if (targetObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            synchronized (mWindowMap) {
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), true);
-            }
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState target = (WindowState)targetObj;
-
-        final long eventTime = ev.getEventTime();
-        final long eventTimeNano = ev.getEventTimeNano();
-
-        //Slog.i(TAG, "Sending " + ev + " to " + target);
-
-        if (uid != 0 && uid != target.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting pointer event from pid "
-                        + pid + " uid " + uid + " to window " + target
-                        + " owned by uid " + target.mSession.mUid);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        if (MEASURE_LATENCY) {
-            lt.sample("4 in dispatchPointer     ", System.nanoTime() - eventTimeNano);
-        }
-
-        if ((target.mAttrs.flags &
-                        WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) {
-            //target wants to ignore fat touch events
-            boolean cheekPress = mPolicy.isCheekPressedAgainstScreen(ev);
-            //explicit flag to return without processing event further
-            boolean returnFlag = false;
-            if((action == MotionEvent.ACTION_DOWN)) {
-                mFatTouch = false;
-                if(cheekPress) {
-                    mFatTouch = true;
-                    returnFlag = true;
-                }
-            } else {
-                if(action == MotionEvent.ACTION_UP) {
-                    if(mFatTouch) {
-                        //earlier even was invalid doesnt matter if current up is cheekpress or not
-                        mFatTouch = false;
-                        returnFlag = true;
-                    } else if(cheekPress) {
-                        //cancel the earlier event
-                        ev.setAction(MotionEvent.ACTION_CANCEL);
-                        action = MotionEvent.ACTION_CANCEL;
-                    }
-                } else if(action == MotionEvent.ACTION_MOVE) {
-                    if(mFatTouch) {
-                        //two cases here
-                        //an invalid down followed by 0 or moves(valid or invalid)
-                        //a valid down,  invalid move, more moves. want to ignore till up
-                        returnFlag = true;
-                    } else if(cheekPress) {
-                        //valid down followed by invalid moves
-                        //an invalid move have to cancel earlier action
-                        ev.setAction(MotionEvent.ACTION_CANCEL);
-                        action = MotionEvent.ACTION_CANCEL;
-                        if (DEBUG_INPUT) Slog.v(TAG, "Sending cancel for invalid ACTION_MOVE");
-                        //note that the subsequent invalid moves will not get here
-                        mFatTouch = true;
-                    }
-                }
-            } //else if action
-            if(returnFlag) {
-                //recycle que, ev
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_FAILED;
-            }
-        } //end if target
-
-        // Enable this for testing the "right" value
-        if (false && action == MotionEvent.ACTION_DOWN) {
-            int max_events_per_sec = 35;
-            try {
-                max_events_per_sec = Integer.parseInt(SystemProperties
-                        .get("windowsmgr.max_events_per_sec"));
-                if (max_events_per_sec < 1) {
-                    max_events_per_sec = 35;
-                }
-            } catch (NumberFormatException e) {
-            }
-            mMinWaitTimeBetweenTouchEvents = 1000 / max_events_per_sec;
-        }
-
-        /*
-         * Throttle events to minimize CPU usage when there's a flood of events
-         * e.g. constant contact with the screen
-         */
-        if (action == MotionEvent.ACTION_MOVE) {
-            long nextEventTime = mLastTouchEventTime + mMinWaitTimeBetweenTouchEvents;
-            long now = SystemClock.uptimeMillis();
-            if (now < nextEventTime) {
-                try {
-                    Thread.sleep(nextEventTime - now);
-                } catch (InterruptedException e) {
-                }
-                mLastTouchEventTime = nextEventTime;
-            } else {
-                mLastTouchEventTime = now;
-            }
-        }
-
-        if (MEASURE_LATENCY) {
-            lt.sample("5 in dispatchPointer     ", System.nanoTime() - eventTimeNano);
-        }
-
-        synchronized(mWindowMap) {
-            if (!target.isVisibleLw()) {
-                // During this motion dispatch, the target window has become
-                // invisible.
-                dispatchPointerElsewhereLocked(null, null, ev, ev.getEventTime(), false);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_SUCCEEDED;
-            }
-
-            if (qev != null && action == MotionEvent.ACTION_MOVE) {
-                mKeyWaiter.bindTargetWindowLocked(target,
-                        KeyWaiter.RETURN_PENDING_POINTER, qev);
-                ev = null;
-            } else {
-                if (action == MotionEvent.ACTION_DOWN) {
-                    WindowState out = mKeyWaiter.mOutsideTouchTargets;
-                    if (out != null) {
-                        MotionEvent oev = MotionEvent.obtain(ev);
-                        oev.setAction(MotionEvent.ACTION_OUTSIDE);
-                        do {
-                            final Rect frame = out.mFrame;
-                            oev.offsetLocation(-(float)frame.left, -(float)frame.top);
-                            try {
-                                out.mClient.dispatchPointer(oev, eventTime, false);
-                            } catch (android.os.RemoteException e) {
-                                Slog.i(TAG, "WINDOW DIED during outside motion dispatch: " + out);
-                            }
-                            oev.offsetLocation((float)frame.left, (float)frame.top);
-                            out = out.mNextOutsideTouch;
-                        } while (out != null);
-                        mKeyWaiter.mOutsideTouchTargets = null;
-                    }
-                }
-
-                dispatchPointerElsewhereLocked(target, null, ev, ev.getEventTime(), false);
-
-                final Rect frame = target.mFrame;
-                ev.offsetLocation(-(float)frame.left, -(float)frame.top);
-                mKeyWaiter.bindTargetWindowLocked(target);
-            }
-        }
-
-        // finally offset the event to the target's coordinate system and
-        // dispatch the event.
-        try {
-            if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) {
-                Slog.v(TAG, "Delivering pointer " + qev + " to " + target);
-            }
-
-            if (MEASURE_LATENCY) {
-                lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano);
-            }
-
-            target.mClient.dispatchPointer(ev, eventTime, true);
-
-            if (MEASURE_LATENCY) {
-                lt.sample("7 after  svr->client ipc ", System.nanoTime() - eventTimeNano);
-            }
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during motion dispatch: " + target);
-            mKeyWaiter.mMotionTarget = null;
-            try {
-                removeWindow(target.mSession, target.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-        return INJECT_FAILED;
-    }
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchTrackball(QueuedEvent qev, MotionEvent ev, int pid, int uid) {
-        if (DEBUG_INPUT) Slog.v(
-                TAG, "dispatchTrackball [" + ev.getAction() +"] <" + ev.getX() + ", " + ev.getY() + ">");
-
-        Object focusObj = mKeyWaiter.waitForNextEventTarget(null, qev,
-                ev, false, false, pid, uid);
-        if (focusObj == null) {
-            Slog.w(TAG, "No focus window, dropping trackball: " + ev);
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_FAILED;
-        }
-        if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            if (qev != null) {
-                mQueue.recycleEvent(qev);
-            }
-            ev.recycle();
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState focus = (WindowState)focusObj;
-
-        if (uid != 0 && uid != focus.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting key event from pid "
-                        + pid + " uid " + uid + " to window " + focus
-                        + " owned by uid " + focus.mSession.mUid);
-                if (qev != null) {
-                    mQueue.recycleEvent(qev);
-                }
-                ev.recycle();
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        final long eventTime = ev.getEventTime();
-
-        synchronized(mWindowMap) {
-            if (qev != null && ev.getAction() == MotionEvent.ACTION_MOVE) {
-                mKeyWaiter.bindTargetWindowLocked(focus,
-                        KeyWaiter.RETURN_PENDING_TRACKBALL, qev);
-                // We don't deliver movement events to the client, we hold
-                // them and wait for them to call back.
-                ev = null;
-            } else {
-                mKeyWaiter.bindTargetWindowLocked(focus);
-            }
-        }
-
-        try {
-            focus.mClient.dispatchTrackball(ev, eventTime, true);
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
-            try {
-                removeWindow(focus.mSession, focus.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-
-        return INJECT_FAILED;
-    }
-
-    /**
-     * @return Returns true if event was dispatched, false if it was dropped for any reason
-     */
-    private int dispatchKey(KeyEvent event, int pid, int uid) {
-        if (DEBUG_INPUT) Slog.v(TAG, "Dispatch key: " + event);
-
-        Object focusObj = mKeyWaiter.waitForNextEventTarget(event, null,
-                null, false, false, pid, uid);
-        if (focusObj == null) {
-            Slog.w(TAG, "No focus window, dropping: " + event);
-            return INJECT_FAILED;
-        }
-        if (focusObj == mKeyWaiter.CONSUMED_EVENT_TOKEN) {
-            return INJECT_SUCCEEDED;
-        }
-
-        // Okay we have finished waiting for the last event to be processed.
-        // First off, if this is a repeat event, check to see if there is
-        // a corresponding up event in the queue.  If there is, we will
-        // just drop the repeat, because it makes no sense to repeat after
-        // the user has released a key.  (This is especially important for
-        // long presses.)
-        if (event.getRepeatCount() > 0 && mQueue.hasKeyUpEvent(event)) {
-            return INJECT_SUCCEEDED;
-        }
-
-        WindowState focus = (WindowState)focusObj;
-
-        if (DEBUG_INPUT) Slog.v(
-            TAG, "Dispatching to " + focus + ": " + event);
-
-        if (uid != 0 && uid != focus.mSession.mUid) {
-            if (mContext.checkPermission(
-                    android.Manifest.permission.INJECT_EVENTS, pid, uid)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission denied: injecting key event from pid "
-                        + pid + " uid " + uid + " to window " + focus
-                        + " owned by uid " + focus.mSession.mUid);
-                return INJECT_NO_PERMISSION;
-            }
-        }
-
-        synchronized(mWindowMap) {
-            mKeyWaiter.bindTargetWindowLocked(focus);
-        }
-
-        // NOSHIP extra state logging
-        mKeyWaiter.recordDispatchState(event, focus);
-        // END NOSHIP
-
-        try {
-            if (DEBUG_INPUT || DEBUG_FOCUS) {
-                Slog.v(TAG, "Delivering key " + event.getKeyCode()
-                        + " to " + focus);
-            }
-            focus.mClient.dispatchKey(event);
-            return INJECT_SUCCEEDED;
-        } catch (android.os.RemoteException e) {
-            Slog.i(TAG, "WINDOW DIED during key dispatch: " + focus);
-            try {
-                removeWindow(focus.mSession, focus.mClient);
-            } catch (java.util.NoSuchElementException ex) {
-                // This will happen if the window has already been
-                // removed.
-            }
-        }
-
-        return INJECT_FAILED;
-    }
-
     public void pauseKeyDispatching(IBinder _token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "pauseKeyDispatching()")) {
@@ -5949,11 +5298,7 @@
         synchronized (mWindowMap) {
             WindowToken token = mTokenMap.get(_token);
             if (token != null) {
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputMonitor.pauseDispatchingLw(token);
-                } else {
-                    mKeyWaiter.pauseDispatchingLocked(token);
-                }
+                mInputMonitor.pauseDispatchingLw(token);
             }
         }
     }
@@ -5967,11 +5312,7 @@
         synchronized (mWindowMap) {
             WindowToken token = mTokenMap.get(_token);
             if (token != null) {
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    mInputMonitor.resumeDispatchingLw(token);
-                } else {
-                    mKeyWaiter.resumeDispatchingLocked(token);
-                }
+                mInputMonitor.resumeDispatchingLw(token);
             }
         }
     }
@@ -5983,11 +5324,7 @@
         }
 
         synchronized (mWindowMap) {
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                mInputMonitor.setEventDispatchingLw(enabled);
-            } else {
-                mKeyWaiter.setEventDispatchingLocked(enabled);
-            }
+            mInputMonitor.setEventDispatchingLw(enabled);
         }
     }
 
@@ -6020,16 +5357,8 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectKeyEvent(newEvent, InputQueue.INPUT_EVENT_NATURE_KEY,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchKey(newEvent, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectKeyEvent(newEvent,
+                InputQueue.INPUT_EVENT_NATURE_KEY, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6049,16 +5378,8 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TOUCH,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchPointer(null, ev, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectMotionEvent(ev,
+                InputQueue.INPUT_EVENT_NATURE_TOUCH, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6078,48 +5399,29 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result;
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            result = mInputManager.injectMotionEvent(ev, InputQueue.INPUT_EVENT_NATURE_TRACKBALL,
-                    pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
-        } else {
-            result = dispatchTrackball(null, ev, pid, uid);
-            if (sync) {
-                mKeyWaiter.waitForNextEventTarget(null, null, null, false, true, pid, uid);
-            }
-        }
+        final int result = mInputManager.injectMotionEvent(ev,
+                InputQueue.INPUT_EVENT_NATURE_TRACKBALL, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
     }
     
     private boolean reportInjectionResult(int result) {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            switch (result) {
-                case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
-                    Slog.w(TAG, "Input event injection permission denied.");
-                    throw new SecurityException(
-                            "Injecting to another application requires INJECT_EVENTS permission");
-                case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
-                    Slog.v(TAG, "Input event injection succeeded.");
-                    return true;
-                case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
-                    Slog.w(TAG, "Input event injection timed out.");
-                    return false;
-                case InputManager.INPUT_EVENT_INJECTION_FAILED:
-                default:
-                    Slog.w(TAG, "Input event injection failed.");
-                    return false;
-            }
-        } else {
-            switch (result) {
-                case INJECT_NO_PERMISSION:
-                    throw new SecurityException(
-                            "Injecting to another application requires INJECT_EVENTS permission");
-                case INJECT_SUCCEEDED:
-                    return true;
-            }
-            return false;
+        switch (result) {
+            case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+                Slog.w(TAG, "Input event injection permission denied.");
+                throw new SecurityException(
+                        "Injecting to another application requires INJECT_EVENTS permission");
+            case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
+                Slog.v(TAG, "Input event injection succeeded.");
+                return true;
+            case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
+                Slog.w(TAG, "Input event injection timed out.");
+                return false;
+            case InputManager.INPUT_EVENT_INJECTION_FAILED:
+            default:
+                Slog.w(TAG, "Input event injection failed.");
+                return false;
         }
     }
 
@@ -6133,867 +5435,6 @@
         return mCurrentFocus;
     }
 
-    /**
-     * This class holds the state for dispatching key events.  This state
-     * is protected by the KeyWaiter instance, NOT by the window lock.  You
-     * can be holding the main window lock while acquire the KeyWaiter lock,
-     * but not the other way around.
-     */
-    final class KeyWaiter {
-        // NOSHIP debugging
-        public class DispatchState {
-            private KeyEvent event;
-            private WindowState focus;
-            private long time;
-            private WindowState lastWin;
-            private IBinder lastBinder;
-            private boolean finished;
-            private boolean gotFirstWindow;
-            private boolean eventDispatching;
-            private long timeToSwitch;
-            private boolean wasFrozen;
-            private boolean focusPaused;
-            private WindowState curFocus;
-
-            DispatchState(KeyEvent theEvent, WindowState theFocus) {
-                focus = theFocus;
-                event = theEvent;
-                time = System.currentTimeMillis();
-                // snapshot KeyWaiter state
-                lastWin = mLastWin;
-                lastBinder = mLastBinder;
-                finished = mFinished;
-                gotFirstWindow = mGotFirstWindow;
-                eventDispatching = mEventDispatching;
-                timeToSwitch = mTimeToSwitch;
-                wasFrozen = mWasFrozen;
-                curFocus = mCurrentFocus;
-                // cache the paused state at ctor time as well
-                if (theFocus == null || theFocus.mToken == null) {
-                    focusPaused = false;
-                } else {
-                    focusPaused = theFocus.mToken.paused;
-                }
-            }
-
-            public String toString() {
-                return "{{" + event + " to " + focus + " @ " + time
-                        + " lw=" + lastWin + " lb=" + lastBinder
-                        + " fin=" + finished + " gfw=" + gotFirstWindow
-                        + " ed=" + eventDispatching + " tts=" + timeToSwitch
-                        + " wf=" + wasFrozen + " fp=" + focusPaused
-                        + " mcf=" + curFocus + "}}";
-            }
-        };
-        private DispatchState mDispatchState = null;
-        public void recordDispatchState(KeyEvent theEvent, WindowState theFocus) {
-            mDispatchState = new DispatchState(theEvent, theFocus);
-        }
-        // END NOSHIP
-
-        public static final int RETURN_NOTHING = 0;
-        public static final int RETURN_PENDING_POINTER = 1;
-        public static final int RETURN_PENDING_TRACKBALL = 2;
-
-        final Object SKIP_TARGET_TOKEN = new Object();
-        final Object CONSUMED_EVENT_TOKEN = new Object();
-
-        private WindowState mLastWin = null;
-        private IBinder mLastBinder = null;
-        private boolean mFinished = true;
-        private boolean mGotFirstWindow = false;
-        private boolean mEventDispatching = true;
-        private long mTimeToSwitch = 0;
-        /* package */ boolean mWasFrozen = false;
-
-        // Target of Motion events
-        WindowState mMotionTarget;
-
-        // Windows above the target who would like to receive an "outside"
-        // touch event for any down events outside of them.
-        WindowState mOutsideTouchTargets;
-
-        /**
-         * Wait for the last event dispatch to complete, then find the next
-         * target that should receive the given event and wait for that one
-         * to be ready to receive it.
-         */
-        Object waitForNextEventTarget(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent,
-                boolean failIfTimeout, int callingPid, int callingUid) {
-            long startTime = SystemClock.uptimeMillis();
-            long keyDispatchingTimeout = 5 * 1000;
-            long waitedFor = 0;
-
-            while (true) {
-                // Figure out which window we care about.  It is either the
-                // last window we are waiting to have process the event or,
-                // if none, then the next window we think the event should go
-                // to.  Note: we retrieve mLastWin outside of the lock, so
-                // it may change before we lock.  Thus we must check it again.
-                WindowState targetWin = mLastWin;
-                boolean targetIsNew = targetWin == null;
-                if (DEBUG_INPUT) Slog.v(
-                        TAG, "waitForLastKey: mFinished=" + mFinished +
-                        ", mLastWin=" + mLastWin);
-                if (targetIsNew) {
-                    Object target = findTargetWindow(nextKey, qev, nextMotion,
-                            isPointerEvent, callingPid, callingUid);
-                    if (target == SKIP_TARGET_TOKEN) {
-                        // The user has pressed a special key, and we are
-                        // dropping all pending events before it.
-                        if (DEBUG_INPUT) Slog.v(TAG, "Skipping: " + nextKey
-                                + " " + nextMotion);
-                        return null;
-                    }
-                    if (target == CONSUMED_EVENT_TOKEN) {
-                        if (DEBUG_INPUT) Slog.v(TAG, "Consumed: " + nextKey
-                                + " " + nextMotion);
-                        return target;
-                    }
-                    targetWin = (WindowState)target;
-                }
-
-                AppWindowToken targetApp = null;
-
-                // Now: is it okay to send the next event to this window?
-                synchronized (this) {
-                    // First: did we come here based on the last window not
-                    // being null, but it changed by the time we got here?
-                    // If so, try again.
-                    if (!targetIsNew && mLastWin == null) {
-                        continue;
-                    }
-
-                    // We never dispatch events if not finished with the
-                    // last one, or the display is frozen.
-                    if (mFinished && !mDisplayFrozen) {
-                        // If event dispatching is disabled, then we
-                        // just consume the events.
-                        if (!mEventDispatching) {
-                            if (DEBUG_INPUT) Slog.v(TAG,
-                                    "Skipping event; dispatching disabled: "
-                                    + nextKey + " " + nextMotion);
-                            return null;
-                        }
-                        if (targetWin != null) {
-                            // If this is a new target, and that target is not
-                            // paused or unresponsive, then all looks good to
-                            // handle the event.
-                            if (targetIsNew && !targetWin.mToken.paused) {
-                                return targetWin;
-                            }
-
-                        // If we didn't find a target window, and there is no
-                        // focused app window, then just eat the events.
-                        } else if (mFocusedApp == null) {
-                            if (DEBUG_INPUT) Slog.v(TAG,
-                                    "Skipping event; no focused app: "
-                                    + nextKey + " " + nextMotion);
-                            return null;
-                        }
-                    }
-
-                    if (DEBUG_INPUT) Slog.v(
-                            TAG, "Waiting for last key in " + mLastBinder
-                            + " target=" + targetWin
-                            + " mFinished=" + mFinished
-                            + " mDisplayFrozen=" + mDisplayFrozen
-                            + " targetIsNew=" + targetIsNew
-                            + " paused="
-                            + (targetWin != null ? targetWin.mToken.paused : false)
-                            + " mFocusedApp=" + mFocusedApp
-                            + " mCurrentFocus=" + mCurrentFocus);
-
-                    targetApp = targetWin != null
-                            ? targetWin.mAppToken : mFocusedApp;
-
-                    long curTimeout = keyDispatchingTimeout;
-                    if (mTimeToSwitch != 0) {
-                        long now = SystemClock.uptimeMillis();
-                        if (mTimeToSwitch <= now) {
-                            // If an app switch key has been pressed, and we have
-                            // waited too long for the current app to finish
-                            // processing keys, then wait no more!
-                            doFinishedKeyLocked(false);
-                            continue;
-                        }
-                        long switchTimeout = mTimeToSwitch - now;
-                        if (curTimeout > switchTimeout) {
-                            curTimeout = switchTimeout;
-                        }
-                    }
-
-                    try {
-                        // after that continue
-                        // processing keys, so we don't get stuck.
-                        if (DEBUG_INPUT) Slog.v(
-                                TAG, "Waiting for key dispatch: " + curTimeout);
-                        wait(curTimeout);
-                        if (DEBUG_INPUT) Slog.v(TAG, "Finished waiting @"
-                                + SystemClock.uptimeMillis() + " startTime="
-                                + startTime + " switchTime=" + mTimeToSwitch
-                                + " target=" + targetWin + " mLW=" + mLastWin
-                                + " mLB=" + mLastBinder + " fin=" + mFinished
-                                + " mCurrentFocus=" + mCurrentFocus);
-                    } catch (InterruptedException e) {
-                    }
-                }
-
-                // If we were frozen during configuration change, restart the
-                // timeout checks from now; otherwise look at whether we timed
-                // out before awakening.
-                if (mWasFrozen) {
-                    waitedFor = 0;
-                    mWasFrozen = false;
-                } else {
-                    waitedFor = SystemClock.uptimeMillis() - startTime;
-                }
-
-                if (waitedFor >= keyDispatchingTimeout && mTimeToSwitch == 0) {
-                    IApplicationToken at = null;
-                    synchronized (this) {
-                        Slog.w(TAG, "Key dispatching timed out sending to " +
-                              (targetWin != null ? targetWin.mAttrs.getTitle()
-                              : "<null>: no window ready for key dispatch"));
-                        // NOSHIP debugging
-                        Slog.w(TAG, "Previous dispatch state: " + mDispatchState);
-                        Slog.w(TAG, "Current dispatch state: " +
-                                new DispatchState(nextKey, targetWin));
-                        // END NOSHIP
-                        //dump();
-                        if (targetWin != null) {
-                            at = targetWin.getAppToken();
-                        } else if (targetApp != null) {
-                            at = targetApp.appToken;
-                        }
-                    }
-
-                    boolean abort = true;
-                    if (at != null) {
-                        try {
-                            long timeout = at.getKeyDispatchingTimeout();
-                            if (timeout > waitedFor) {
-                                // we did not wait the proper amount of time for this application.
-                                // set the timeout to be the real timeout and wait again.
-                                keyDispatchingTimeout = timeout - waitedFor;
-                                continue;
-                            } else {
-                                abort = at.keyDispatchingTimedOut();
-                            }
-                        } catch (RemoteException ex) {
-                        }
-                    }
-
-                    synchronized (this) {
-                        if (abort && (mLastWin == targetWin || targetWin == null)) {
-                            mFinished = true;
-                            if (mLastWin != null) {
-                                if (DEBUG_INPUT) Slog.v(TAG,
-                                        "Window " + mLastWin +
-                                        " timed out on key input");
-                                if (mLastWin.mToken.paused) {
-                                    Slog.w(TAG, "Un-pausing dispatching to this window");
-                                    mLastWin.mToken.paused = false;
-                                }
-                            }
-                            if (mMotionTarget == targetWin) {
-                                mMotionTarget = null;
-                            }
-                            mLastWin = null;
-                            mLastBinder = null;
-                            if (failIfTimeout || targetWin == null) {
-                                return null;
-                            }
-                        } else {
-                            Slog.w(TAG, "Continuing to wait for key to be dispatched");
-                            startTime = SystemClock.uptimeMillis();
-                        }
-                    }
-                }
-            }
-        }
-
-        Object findTargetWindow(KeyEvent nextKey, QueuedEvent qev,
-                MotionEvent nextMotion, boolean isPointerEvent,
-                int callingPid, int callingUid) {
-            mOutsideTouchTargets = null;
-
-            if (nextKey != null) {
-                // Find the target window for a normal key event.
-                final int keycode = nextKey.getKeyCode();
-                final int repeatCount = nextKey.getRepeatCount();
-                final boolean down = nextKey.getAction() != KeyEvent.ACTION_UP;
-                boolean dispatch = mKeyWaiter.checkShouldDispatchKey(keycode);
-
-                if (!dispatch) {
-                    if (callingUid == 0 ||
-                            mContext.checkPermission(
-                                    android.Manifest.permission.INJECT_EVENTS,
-                                    callingPid, callingUid)
-                                    == PackageManager.PERMISSION_GRANTED) {
-                        mPolicy.interceptKeyTi(null, keycode,
-                                nextKey.getMetaState(), down, repeatCount,
-                                nextKey.getFlags());
-                    }
-                    Slog.w(TAG, "Event timeout during app switch: dropping "
-                            + nextKey);
-                    return SKIP_TARGET_TOKEN;
-                }
-
-                // System.out.println("##### [" + SystemClock.uptimeMillis() + "] WindowManagerService.dispatchKey(" + keycode + ", " + down + ", " + repeatCount + ")");
-
-                WindowState focus = null;
-                synchronized(mWindowMap) {
-                    focus = getFocusedWindowLocked();
-                }
-
-                wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-
-                if (callingUid == 0 ||
-                        (focus != null && callingUid == focus.mSession.mUid) ||
-                        mContext.checkPermission(
-                                android.Manifest.permission.INJECT_EVENTS,
-                                callingPid, callingUid)
-                                == PackageManager.PERMISSION_GRANTED) {
-                    if (mPolicy.interceptKeyTi(focus,
-                            keycode, nextKey.getMetaState(), down, repeatCount,
-                            nextKey.getFlags())) {
-                        return CONSUMED_EVENT_TOKEN;
-                    }
-                }
-
-                return focus;
-
-            } else if (!isPointerEvent) {
-                boolean dispatch = mKeyWaiter.checkShouldDispatchKey(-1);
-                if (!dispatch) {
-                    Slog.w(TAG, "Event timeout during app switch: dropping trackball "
-                            + nextMotion);
-                    return SKIP_TARGET_TOKEN;
-                }
-
-                WindowState focus = null;
-                synchronized(mWindowMap) {
-                    focus = getFocusedWindowLocked();
-                }
-
-                wakeupIfNeeded(focus, LocalPowerManager.BUTTON_EVENT);
-                return focus;
-            }
-
-            if (nextMotion == null) {
-                return SKIP_TARGET_TOKEN;
-            }
-
-            boolean dispatch = mKeyWaiter.checkShouldDispatchKey(
-                    KeyEvent.KEYCODE_UNKNOWN);
-            if (!dispatch) {
-                Slog.w(TAG, "Event timeout during app switch: dropping pointer "
-                        + nextMotion);
-                return SKIP_TARGET_TOKEN;
-            }
-
-            // Find the target window for a pointer event.
-            int action = nextMotion.getAction();
-            final float xf = nextMotion.getX();
-            final float yf = nextMotion.getY();
-            final long eventTime = nextMotion.getEventTime();
-
-            final boolean screenWasOff = qev != null
-                    && (qev.flags&WindowManagerPolicy.FLAG_BRIGHT_HERE) != 0;
-
-            WindowState target = null;
-
-            synchronized(mWindowMap) {
-                synchronized (this) {
-                    if (action == MotionEvent.ACTION_DOWN) {
-                        if (mMotionTarget != null) {
-                            // this is weird, we got a pen down, but we thought it was
-                            // already down!
-                            // XXX: We should probably send an ACTION_UP to the current
-                            // target.
-                            Slog.w(TAG, "Pointer down received while already down in: "
-                                    + mMotionTarget);
-                            mMotionTarget = null;
-                        }
-
-                        // ACTION_DOWN is special, because we need to lock next events to
-                        // the window we'll land onto.
-                        final int x = (int)xf;
-                        final int y = (int)yf;
-
-                        final ArrayList windows = mWindows;
-                        final int N = windows.size();
-                        WindowState topErrWindow = null;
-                        final Rect tmpRect = mTempRect;
-                        for (int i=N-1; i>=0; i--) {
-                            WindowState child = (WindowState)windows.get(i);
-                            //Slog.i(TAG, "Checking dispatch to: " + child);
-                            final int flags = child.mAttrs.flags;
-                            if ((flags & WindowManager.LayoutParams.FLAG_SYSTEM_ERROR) != 0) {
-                                if (topErrWindow == null) {
-                                    topErrWindow = child;
-                                }
-                            }
-                            if (!child.isVisibleLw()) {
-                                //Slog.i(TAG, "Not visible!");
-                                continue;
-                            }
-                            if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
-                                //Slog.i(TAG, "Not touchable!");
-                                if ((flags & WindowManager.LayoutParams
-                                        .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
-                                    child.mNextOutsideTouch = mOutsideTouchTargets;
-                                    mOutsideTouchTargets = child;
-                                }
-                                continue;
-                            }
-                            tmpRect.set(child.mFrame);
-                            if (child.mTouchableInsets == ViewTreeObserver
-                                        .InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT) {
-                                // The touch is inside of the window if it is
-                                // inside the frame, AND the content part of that
-                                // frame that was given by the application.
-                                tmpRect.left += child.mGivenContentInsets.left;
-                                tmpRect.top += child.mGivenContentInsets.top;
-                                tmpRect.right -= child.mGivenContentInsets.right;
-                                tmpRect.bottom -= child.mGivenContentInsets.bottom;
-                            } else if (child.mTouchableInsets == ViewTreeObserver
-                                        .InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE) {
-                                // The touch is inside of the window if it is
-                                // inside the frame, AND the visible part of that
-                                // frame that was given by the application.
-                                tmpRect.left += child.mGivenVisibleInsets.left;
-                                tmpRect.top += child.mGivenVisibleInsets.top;
-                                tmpRect.right -= child.mGivenVisibleInsets.right;
-                                tmpRect.bottom -= child.mGivenVisibleInsets.bottom;
-                            }
-                            final int touchFlags = flags &
-                                (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
-                            if (tmpRect.contains(x, y) || touchFlags == 0) {
-                                //Slog.i(TAG, "Using this target!");
-                                if (!screenWasOff || (flags &
-                                        WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING) != 0) {
-                                    mMotionTarget = child;
-                                } else {
-                                    //Slog.i(TAG, "Waking, skip!");
-                                    mMotionTarget = null;
-                                }
-                                break;
-                            }
-
-                            if ((flags & WindowManager.LayoutParams
-                                    .FLAG_WATCH_OUTSIDE_TOUCH) != 0) {
-                                child.mNextOutsideTouch = mOutsideTouchTargets;
-                                mOutsideTouchTargets = child;
-                                //Slog.i(TAG, "Adding to outside target list: " + child);
-                            }
-                        }
-
-                        // if there's an error window but it's not accepting
-                        // focus (typically because it is not yet visible) just
-                        // wait for it -- any other focused window may in fact
-                        // be in ANR state.
-                        if (topErrWindow != null && mMotionTarget != topErrWindow) {
-                            mMotionTarget = null;
-                        }
-                    }
-
-                    target = mMotionTarget;
-                }
-            }
-
-            wakeupIfNeeded(target, eventType(nextMotion));
-
-            // Pointer events are a little different -- if there isn't a
-            // target found for any event, then just drop it.
-            return target != null ? target : SKIP_TARGET_TOKEN;
-        }
-
-        boolean checkShouldDispatchKey(int keycode) {
-            synchronized (this) {
-                if (mPolicy.isAppSwitchKeyTqTiLwLi(keycode)) {
-                    mTimeToSwitch = 0;
-                    return true;
-                }
-                if (mTimeToSwitch != 0
-                        && mTimeToSwitch < SystemClock.uptimeMillis()) {
-                    return false;
-                }
-                return true;
-            }
-        }
-
-        void bindTargetWindowLocked(WindowState win,
-                int pendingWhat, QueuedEvent pendingMotion) {
-            synchronized (this) {
-                bindTargetWindowLockedLocked(win, pendingWhat, pendingMotion);
-            }
-        }
-
-        void bindTargetWindowLocked(WindowState win) {
-            synchronized (this) {
-                bindTargetWindowLockedLocked(win, RETURN_NOTHING, null);
-            }
-        }
-
-        void bindTargetWindowLockedLocked(WindowState win,
-                int pendingWhat, QueuedEvent pendingMotion) {
-            mLastWin = win;
-            mLastBinder = win.mClient.asBinder();
-            mFinished = false;
-            if (pendingMotion != null) {
-                final Session s = win.mSession;
-                if (pendingWhat == RETURN_PENDING_POINTER) {
-                    releasePendingPointerLocked(s);
-                    s.mPendingPointerMove = pendingMotion;
-                    s.mPendingPointerWindow = win;
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "bindTargetToWindow " + s.mPendingPointerMove);
-                } else if (pendingWhat == RETURN_PENDING_TRACKBALL) {
-                    releasePendingTrackballLocked(s);
-                    s.mPendingTrackballMove = pendingMotion;
-                    s.mPendingTrackballWindow = win;
-                }
-            }
-        }
-
-        void releasePendingPointerLocked(Session s) {
-            if (DEBUG_INPUT) Slog.v(TAG,
-                    "releasePendingPointer " + s.mPendingPointerMove);
-            if (s.mPendingPointerMove != null) {
-                mQueue.recycleEvent(s.mPendingPointerMove);
-                s.mPendingPointerMove = null;
-            }
-        }
-
-        void releasePendingTrackballLocked(Session s) {
-            if (s.mPendingTrackballMove != null) {
-                mQueue.recycleEvent(s.mPendingTrackballMove);
-                s.mPendingTrackballMove = null;
-            }
-        }
-
-        MotionEvent finishedKey(Session session, IWindow client, boolean force,
-                int returnWhat) {
-            if (DEBUG_INPUT) Slog.v(
-                TAG, "finishedKey: client=" + client + ", force=" + force);
-
-            if (client == null) {
-                return null;
-            }
-
-            MotionEvent res = null;
-            QueuedEvent qev = null;
-            WindowState win = null;
-
-            synchronized (this) {
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "finishedKey: client=" + client.asBinder()
-                    + ", force=" + force + ", last=" + mLastBinder
-                    + " (token=" + (mLastWin != null ? mLastWin.mToken : null) + ")");
-
-                if (returnWhat == RETURN_PENDING_POINTER) {
-                    qev = session.mPendingPointerMove;
-                    win = session.mPendingPointerWindow;
-                    session.mPendingPointerMove = null;
-                    session.mPendingPointerWindow = null;
-                } else if (returnWhat == RETURN_PENDING_TRACKBALL) {
-                    qev = session.mPendingTrackballMove;
-                    win = session.mPendingTrackballWindow;
-                    session.mPendingTrackballMove = null;
-                    session.mPendingTrackballWindow = null;
-                }
-
-                if (mLastBinder == client.asBinder()) {
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "finishedKey: last paused="
-                        + ((mLastWin != null) ? mLastWin.mToken.paused : "null"));
-                    if (mLastWin != null && (!mLastWin.mToken.paused || force
-                            || !mEventDispatching)) {
-                        doFinishedKeyLocked(true);
-                    } else {
-                        // Make sure to wake up anyone currently waiting to
-                        // dispatch a key, so they can re-evaluate their
-                        // current situation.
-                        mFinished = true;
-                        notifyAll();
-                    }
-                }
-
-                if (qev != null) {
-                    res = (MotionEvent)qev.event;
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "Returning pending motion: " + res);
-                    mQueue.recycleEvent(qev);
-                    if (win != null && returnWhat == RETURN_PENDING_POINTER) {
-                        res.offsetLocation(-win.mFrame.left, -win.mFrame.top);
-                    }
-                }
-            }
-
-            if (res != null && returnWhat == RETURN_PENDING_POINTER) {
-                synchronized (mWindowMap) {
-                    dispatchPointerElsewhereLocked(win, win, res, res.getEventTime(), false);
-                }
-            }
-
-            return res;
-        }
-
-        void tickle() {
-            synchronized (this) {
-                notifyAll();
-            }
-        }
-
-        void handleNewWindowLocked(WindowState newWindow) {
-            if (!newWindow.canReceiveKeys()) {
-                return;
-            }
-            synchronized (this) {
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "New key dispatch window: win="
-                    + newWindow.mClient.asBinder()
-                    + ", last=" + mLastBinder
-                    + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
-                    + "), finished=" + mFinished + ", paused="
-                    + newWindow.mToken.paused);
-
-                // Displaying a window implicitly causes dispatching to
-                // be unpaused.  (This is to protect against bugs if someone
-                // pauses dispatching but forgets to resume.)
-                newWindow.mToken.paused = false;
-
-                mGotFirstWindow = true;
-
-                if ((newWindow.mAttrs.flags & FLAG_SYSTEM_ERROR) != 0) {
-                    if (DEBUG_INPUT) Slog.v(TAG,
-                            "New SYSTEM_ERROR window; resetting state");
-                    mLastWin = null;
-                    mLastBinder = null;
-                    mMotionTarget = null;
-                    mFinished = true;
-                } else if (mLastWin != null) {
-                    // If the new window is above the window we are
-                    // waiting on, then stop waiting and let key dispatching
-                    // start on the new guy.
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "Last win layer=" + mLastWin.mLayer
-                        + ", new win layer=" + newWindow.mLayer);
-                    if (newWindow.mLayer >= mLastWin.mLayer) {
-                        // The new window is above the old; finish pending input to the last
-                        // window and start directing it to the new one.
-                        mLastWin.mToken.paused = false;
-                        doFinishedKeyLocked(false);  // does a notifyAll()
-                        return;
-                    }
-                }
-
-                // Now that we've put a new window state in place, make the event waiter
-                // take notice and retarget its attentions.
-                notifyAll();
-            }
-        }
-
-        void pauseDispatchingLocked(WindowToken token) {
-            synchronized (this)
-            {
-                if (DEBUG_INPUT) Slog.v(TAG, "Pausing WindowToken " + token);
-                token.paused = true;
-
-                /*
-                if (mLastWin != null && !mFinished && mLastWin.mBaseLayer <= layer) {
-                    mPaused = true;
-                } else {
-                    if (mLastWin == null) {
-                        Slog.i(TAG, "Key dispatching not paused: no last window.");
-                    } else if (mFinished) {
-                        Slog.i(TAG, "Key dispatching not paused: finished last key.");
-                    } else {
-                        Slog.i(TAG, "Key dispatching not paused: window in higher layer.");
-                    }
-                }
-                */
-            }
-        }
-
-        void resumeDispatchingLocked(WindowToken token) {
-            synchronized (this) {
-                if (token.paused) {
-                    if (DEBUG_INPUT) Slog.v(
-                        TAG, "Resuming WindowToken " + token
-                        + ", last=" + mLastBinder
-                        + " (token=" + (mLastWin != null ? mLastWin.mToken : null)
-                        + "), finished=" + mFinished + ", paused="
-                        + token.paused);
-                    token.paused = false;
-                    if (mLastWin != null && mLastWin.mToken == token && mFinished) {
-                        doFinishedKeyLocked(false);
-                    } else {
-                        notifyAll();
-                    }
-                }
-            }
-        }
-
-        void setEventDispatchingLocked(boolean enabled) {
-            synchronized (this) {
-                mEventDispatching = enabled;
-                notifyAll();
-            }
-        }
-
-        void appSwitchComing() {
-            synchronized (this) {
-                // Don't wait for more than .5 seconds for app to finish
-                // processing the pending events.
-                long now = SystemClock.uptimeMillis() + 500;
-                if (DEBUG_INPUT) Slog.v(TAG, "appSwitchComing: " + now);
-                if (mTimeToSwitch == 0 || now < mTimeToSwitch) {
-                    mTimeToSwitch = now;
-                }
-                notifyAll();
-            }
-        }
-
-        private final void doFinishedKeyLocked(boolean force) {
-            if (mLastWin != null) {
-                releasePendingPointerLocked(mLastWin.mSession);
-                releasePendingTrackballLocked(mLastWin.mSession);
-            }
-
-            if (force || mLastWin == null || !mLastWin.mToken.paused
-                    || !mLastWin.isVisibleLw()) {
-                // If the current window has been paused, we aren't -really-
-                // finished...  so let the waiters still wait.
-                mLastWin = null;
-                mLastBinder = null;
-            }
-            mFinished = true;
-            notifyAll();
-        }
-    }
-
-    private class KeyQ extends KeyInputQueue
-            implements KeyInputQueue.FilterCallback {
-        KeyQ() {
-            super(mContext, WindowManagerService.this);
-        }
-
-        @Override
-        boolean preprocessEvent(InputDevice device, RawInputEvent event) {
-            if (mPolicy.preprocessInputEventTq(event)) {
-                return true;
-            }
-
-            switch (event.type) {
-                case RawInputEvent.EV_KEY: {
-                    // XXX begin hack
-                    if (DEBUG) {
-                        if (event.keycode == KeyEvent.KEYCODE_G) {
-                            if (event.value != 0) {
-                                // G down
-                                mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-                            }
-                            return false;
-                        }
-                        if (event.keycode == KeyEvent.KEYCODE_D) {
-                            if (event.value != 0) {
-                                //dump();
-                            }
-                            return false;
-                        }
-                    }
-                    // XXX end hack
-
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
-
-                    if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
-                        mPowerManager.goToSleep(event.when);
-                    }
-
-                    if (screenIsOff) {
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
-                        mPowerManager.userActivity(event.when, false,
-                                LocalPowerManager.BUTTON_EVENT, false);
-                    }
-
-                    if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
-                        if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
-                            filterQueue(this);
-                            mKeyWaiter.appSwitchComing();
-                        }
-                        return true;
-                    } else {
-                        return false;
-                    }
-                }
-
-                case RawInputEvent.EV_REL: {
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    if (screenIsOff) {
-                        if (!mPolicy.isWakeRelMovementTq(event.deviceId,
-                                device.classes, event)) {
-                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
-                            return false;
-                        }
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    return true;
-                }
-
-                case RawInputEvent.EV_ABS: {
-                    boolean screenIsOff = !mPowerManager.isScreenOn();
-                    boolean screenIsDim = !mPowerManager.isScreenBright();
-                    if (screenIsOff) {
-                        if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
-                                device.classes, event)) {
-                            //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
-                            return false;
-                        }
-                        event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-                    }
-                    if (screenIsDim) {
-                        event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-                    }
-                    return true;
-                }
-
-                default:
-                    return true;
-            }
-        }
-
-        public int filterEvent(QueuedEvent ev) {
-            switch (ev.classType) {
-                case RawInputEvent.CLASS_KEYBOARD:
-                    KeyEvent ke = (KeyEvent)ev.event;
-                    if (mPolicy.isMovementKeyTi(ke.getKeyCode())) {
-                        Slog.w(TAG, "Dropping movement key during app switch: "
-                                + ke.getKeyCode() + ", action=" + ke.getAction());
-                        return FILTER_REMOVE;
-                    }
-                    return FILTER_ABORT;
-                default:
-                    return FILTER_KEEP;
-            }
-        }
-    }
-
     public boolean detectSafeMode() {
         mSafeMode = mPolicy.detectSafeMode();
         return mSafeMode;
@@ -7003,219 +5444,6 @@
         mPolicy.systemReady();
     }
 
-    private final class InputDispatcherThread extends Thread {
-        // Time to wait when there is nothing to do: 9999 seconds.
-        static final int LONG_WAIT=9999*1000;
-
-        public InputDispatcherThread() {
-            super("InputDispatcher");
-        }
-
-        @Override
-        public void run() {
-            while (true) {
-                try {
-                    process();
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception in input dispatcher", e);
-                }
-            }
-        }
-
-        private void process() {
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
-            // The last key event we saw
-            KeyEvent lastKey = null;
-
-            // Last keydown time for auto-repeating keys
-            long lastKeyTime = SystemClock.uptimeMillis();
-            long nextKeyTime = lastKeyTime+LONG_WAIT;
-            long downTime = 0;
-
-            // How many successive repeats we generated
-            int keyRepeatCount = 0;
-
-            // Need to report that configuration has changed?
-            boolean configChanged = false;
-
-            while (true) {
-                long curTime = SystemClock.uptimeMillis();
-
-                if (DEBUG_INPUT) Slog.v(
-                    TAG, "Waiting for next key: now=" + curTime
-                    + ", repeat @ " + nextKeyTime);
-
-                // Retrieve next event, waiting only as long as the next
-                // repeat timeout.  If the configuration has changed, then
-                // don't wait at all -- we'll report the change as soon as
-                // we have processed all events.
-                QueuedEvent ev = mQueue.getEvent(
-                    (int)((!configChanged && curTime < nextKeyTime)
-                            ? (nextKeyTime-curTime) : 0));
-
-                if (DEBUG_INPUT && ev != null) Slog.v(
-                        TAG, "Event: type=" + ev.classType + " data=" + ev.event);
-
-                if (MEASURE_LATENCY) {
-                    lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);
-                }
-
-                if (lastKey != null && !mPolicy.allowKeyRepeat()) {
-                    // cancel key repeat at the request of the policy.
-                    lastKey = null;
-                    downTime = 0;
-                    lastKeyTime = curTime;
-                    nextKeyTime = curTime + LONG_WAIT;
-                }
-                try {
-                    if (ev != null) {
-                        curTime = SystemClock.uptimeMillis();
-                        int eventType;
-                        if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
-                            eventType = eventType((MotionEvent)ev.event);
-                        } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
-                                    ev.classType == RawInputEvent.CLASS_TRACKBALL) {
-                            eventType = LocalPowerManager.BUTTON_EVENT;
-                        } else {
-                            eventType = LocalPowerManager.OTHER_EVENT;
-                        }
-                        try {
-                            if ((curTime - mLastBatteryStatsCallTime)
-                                    >= MIN_TIME_BETWEEN_USERACTIVITIES) {
-                                mLastBatteryStatsCallTime = curTime;
-                                mBatteryStats.noteInputEvent();
-                            }
-                        } catch (RemoteException e) {
-                            // Ignore
-                        }
-
-                        if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {
-                            // do not wake screen in this case
-                        } else if (eventType != TOUCH_EVENT
-                                && eventType != LONG_TOUCH_EVENT
-                                && eventType != CHEEK_EVENT) {
-                            mPowerManager.userActivity(curTime, false,
-                                    eventType, false);
-                        } else if (mLastTouchEventType != eventType
-                                || (curTime - mLastUserActivityCallTime)
-                                >= MIN_TIME_BETWEEN_USERACTIVITIES) {
-                            mLastUserActivityCallTime = curTime;
-                            mLastTouchEventType = eventType;
-                            mPowerManager.userActivity(curTime, false,
-                                    eventType, false);
-                        }
-
-                        switch (ev.classType) {
-                            case RawInputEvent.CLASS_KEYBOARD:
-                                KeyEvent ke = (KeyEvent)ev.event;
-                                if (ke.isDown()) {
-                                    lastKeyTime = curTime;
-                                    if (lastKey != null &&
-                                            ke.getKeyCode() == lastKey.getKeyCode()) {
-                                        keyRepeatCount++;
-                                        // Arbitrary long timeout to block
-                                        // repeating here since we know that
-                                        // the device driver takes care of it.
-                                        nextKeyTime = lastKeyTime + LONG_WAIT;
-                                        if (DEBUG_INPUT) Slog.v(
-                                                TAG, "Received repeated key down");
-                                    } else {
-                                        downTime = curTime;
-                                        keyRepeatCount = 0;
-                                        nextKeyTime = lastKeyTime
-                                                + ViewConfiguration.getLongPressTimeout();
-                                        if (DEBUG_INPUT) Slog.v(
-                                            TAG, "Received key down: first repeat @ "
-                                            + nextKeyTime);
-                                    }
-                                    lastKey = ke;
-                                } else {
-                                    lastKey = null;
-                                    downTime = 0;
-                                    keyRepeatCount = 0;
-                                    // Arbitrary long timeout.
-                                    lastKeyTime = curTime;
-                                    nextKeyTime = curTime + LONG_WAIT;
-                                    if (DEBUG_INPUT) Slog.v(
-                                        TAG, "Received key up: ignore repeat @ "
-                                        + nextKeyTime);
-                                }
-                                if (keyRepeatCount > 0) {
-                                    dispatchKey(KeyEvent.changeTimeRepeat(ke,
-                                            ke.getEventTime(), keyRepeatCount), 0, 0);
-                                } else {
-                                    dispatchKey(ke, 0, 0);
-                                }
-                                mQueue.recycleEvent(ev);
-                                break;
-                            case RawInputEvent.CLASS_TOUCHSCREEN:
-                                //Slog.i(TAG, "Read next event " + ev);
-                                dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
-                                break;
-                            case RawInputEvent.CLASS_TRACKBALL:
-                                dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
-                                break;
-                            case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
-                                configChanged = true;
-                                break;
-                            default:
-                                mQueue.recycleEvent(ev);
-                            break;
-                        }
-
-                    } else if (configChanged) {
-                        configChanged = false;
-                        sendNewConfiguration();
-
-                    } else if (lastKey != null) {
-                        curTime = SystemClock.uptimeMillis();
-
-                        // Timeout occurred while key was down.  If it is at or
-                        // past the key repeat time, dispatch the repeat.
-                        if (DEBUG_INPUT) Slog.v(
-                            TAG, "Key timeout: repeat=" + nextKeyTime
-                            + ", now=" + curTime);
-                        if (curTime < nextKeyTime) {
-                            continue;
-                        }
-
-                        lastKeyTime = nextKeyTime;
-                        nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
-                        keyRepeatCount++;
-                        if (DEBUG_INPUT) Slog.v(
-                            TAG, "Key repeat: count=" + keyRepeatCount
-                            + ", next @ " + nextKeyTime);
-                        KeyEvent newEvent;
-                        if (downTime != 0 && (downTime
-                                + ViewConfiguration.getLongPressTimeout())
-                                <= curTime) {
-                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
-                                    curTime, keyRepeatCount,
-                                    lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
-                            downTime = 0;
-                        } else {
-                            newEvent = KeyEvent.changeTimeRepeat(lastKey,
-                                    curTime, keyRepeatCount);
-                        }
-                        dispatchKey(newEvent, 0, 0);
-
-                    } else {
-                        curTime = SystemClock.uptimeMillis();
-
-                        lastKeyTime = curTime;
-                        nextKeyTime = curTime + LONG_WAIT;
-                    }
-
-                } catch (Exception e) {
-                    Slog.e(TAG,
-                        "Input thread received uncaught exception: " + e, e);
-                }
-            }
-        }
-    }
-
     // -------------------------------------------------------------
     // Client Session State
     // -------------------------------------------------------------
@@ -7231,20 +5459,6 @@
         int mNumWindow = 0;
         boolean mClientDead = false;
 
-        /**
-         * Current pointer move event being dispatched to client window...  must
-         * hold key lock to access.
-         */
-        QueuedEvent mPendingPointerMove;
-        WindowState mPendingPointerWindow;
-
-        /**
-         * Current trackball move event being dispatched to client window...  must
-         * hold key lock to access.
-         */
-        QueuedEvent mPendingTrackballMove;
-        WindowState mPendingTrackballWindow;
-
         public Session(IInputMethodClient client, IInputContext inputContext) {
             mClient = client;
             mInputContext = inputContext;
@@ -7363,36 +5577,6 @@
             finishDrawingWindow(this, window);
         }
 
-        public void finishKey(IWindow window) {
-            if (localLOGV) Slog.v(
-                TAG, "IWindow finishKey called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_NOTHING);
-        }
-
-        public MotionEvent getPendingPointerMove(IWindow window) {
-            if (localLOGV) Slog.v(
-                    TAG, "IWindow getPendingMotionEvent called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            return mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_PENDING_POINTER);
-        }
-
-        public MotionEvent getPendingTrackballMove(IWindow window) {
-            if (localLOGV) Slog.v(
-                    TAG, "IWindow getPendingMotionEvent called for " + window);
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                throw new IllegalStateException("Should not be called anymore.");
-            }
-            return mKeyWaiter.finishedKey(this, window, false,
-                    KeyWaiter.RETURN_PENDING_TRACKBALL);
-        }
-
         public void setInTouchMode(boolean mode) {
             synchronized(mWindowMap) {
                 mInTouchMode = mode;
@@ -7496,16 +5680,6 @@
             pw.print(prefix); pw.print("mNumWindow="); pw.print(mNumWindow);
                     pw.print(" mClientDead="); pw.print(mClientDead);
                     pw.print(" mSurfaceSession="); pw.println(mSurfaceSession);
-            if (mPendingPointerWindow != null || mPendingPointerMove != null) {
-                pw.print(prefix);
-                        pw.print("mPendingPointerWindow="); pw.print(mPendingPointerWindow);
-                        pw.print(" mPendingPointerMove="); pw.println(mPendingPointerMove);
-            }
-            if (mPendingTrackballWindow != null || mPendingTrackballMove != null) {
-                pw.print(prefix);
-                        pw.print("mPendingTrackballWindow="); pw.print(mPendingTrackballWindow);
-                        pw.print(" mPendingTrackballMove="); pw.println(mPendingTrackballMove);
-            }
         }
 
         @Override
@@ -7556,8 +5730,6 @@
         boolean mObscured;
         boolean mTurnOnScreen;
 
-        WindowState mNextOutsideTouch;
-
         int mLayoutSeq = -1;
         
         Configuration mConfiguration = null;
@@ -8074,16 +6246,6 @@
         }
 
         void destroySurfaceLocked() {
-            // Window is no longer on-screen, so can no longer receive
-            // key events...  if we were waiting for it to finish
-            // handling a key event, the wait is over!
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                mKeyWaiter.finishedKey(mSession, mClient, true,
-                        KeyWaiter.RETURN_NOTHING);
-                mKeyWaiter.releasePendingPointerLocked(mSession);
-                mKeyWaiter.releasePendingTrackballLocked(mSession);
-            }
-
             if (mAppToken != null && this == mAppToken.startingWindow) {
                 mAppToken.startingDisplayed = false;
             }
@@ -8099,9 +6261,7 @@
                     WindowState c = (WindowState)mChildWindows.get(i);
                     c.mAttachedHidden = true;
                     
-                    if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                        mInputMonitor.windowIsBecomingInvisibleLw(c);
-                    }
+                    mInputMonitor.windowIsBecomingInvisibleLw(c);
                 }
 
                 if (mReportDestroySurface) {
@@ -8410,12 +6570,8 @@
                 }
                 mLastHidden = true;
                 
-                if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                    for (int i=0; i<N; i++) {
-                        mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
-                    }
-                } else {
-                    mKeyWaiter.releasePendingPointerLocked(mSession);
+                for (int i=0; i<N; i++) {
+                    mInputMonitor.windowIsBecomingInvisibleLw((WindowState)mChildWindows.get(i));
                 }
             }
             mExiting = false;
@@ -8752,13 +6908,11 @@
                 // we are doing this as part of processing a death note.)
             }
             
-            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                if (mInputChannel != null) {
-                    mInputManager.unregisterInputChannel(mInputChannel);
-                    
-                    mInputChannel.dispose();
-                    mInputChannel = null;
-                }
+            if (mInputChannel != null) {
+                mInputManager.unregisterInputChannel(mInputChannel);
+                
+                mInputChannel.dispose();
+                mInputChannel = null;
             }
         }
 
@@ -10174,9 +8328,7 @@
         }
         
         // Window frames may have changed.  Tell the input dispatcher about it.
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.updateInputWindowsLw();
-        }
+        mInputMonitor.updateInputWindowsLw();
 
         return mPolicy.finishLayoutLw();
     }
@@ -10977,11 +9129,7 @@
                                     Slog.w(TAG, "Exception hiding surface in " + w);
                                 }
                             }
-                            if (ENABLE_NATIVE_INPUT_DISPATCH) {
-                                mInputMonitor.windowIsBecomingInvisibleLw(w);
-                            } else {
-                                mKeyWaiter.releasePendingPointerLocked(w.mSession);
-                            }
+                            mInputMonitor.windowIsBecomingInvisibleLw(w);
                         }
                         // If we are waiting for this window to handle an
                         // orientation change, well, it is hidden, so
@@ -11583,13 +9731,7 @@
     }
     
     private void finishUpdateFocusedWindowAfterAssignLayersLocked() {
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.setInputFocusLw(mCurrentFocus);
-        } else {
-            if (mCurrentFocus != null) {
-                mKeyWaiter.handleNewWindowLocked(mCurrentFocus);
-            }
-        }
+        mInputMonitor.setInputFocusLw(mCurrentFocus);
     }
 
     private WindowState computeFocusedWindowLocked() {
@@ -11663,17 +9805,6 @@
 
     private void startFreezingDisplayLocked() {
         if (mDisplayFrozen) {
-            // Freezing the display also suspends key event delivery, to
-            // keep events from going astray while the display is reconfigured.
-            // If someone has changed orientation again while the screen is
-            // still frozen, the events will continue to be blocked while the
-            // successive orientation change is processed.  To prevent spurious
-            // ANRs, we reset the event dispatch timeout in this case.
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                synchronized (mKeyWaiter) {
-                    mKeyWaiter.mWasFrozen = true;
-                }
-            }
             return;
         }
 
@@ -11696,9 +9827,7 @@
         
         mDisplayFrozen = true;
         
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.freezeInputDispatchingLw();
-        }
+        mInputMonitor.freezeInputDispatchingLw();
         
         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
@@ -11731,16 +9860,7 @@
         }
         Surface.unfreezeDisplay(0);
 
-        // Reset the key delivery timeout on unfreeze, too.  We force a wakeup here
-        // too because regular key delivery processing should resume immediately.
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            mInputMonitor.thawInputDispatchingLw();
-        } else {
-            synchronized (mKeyWaiter) {
-                mKeyWaiter.mWasFrozen = true;
-                mKeyWaiter.notifyAll();
-            }
-        }
+        mInputMonitor.thawInputDispatchingLw();
 
         // While the display is frozen we don't re-compute the orientation
         // to avoid inconsistent states.  However, something interesting
@@ -11772,13 +9892,8 @@
             return;
         }
 
-        if (ENABLE_NATIVE_INPUT_DISPATCH) {
-            pw.println("Input Dispatcher State:");
-            mInputManager.dump(pw);
-        } else {
-            pw.println("Input State:");
-            mQueue.dump(pw, "  ");
-        }
+        pw.println("Input Dispatcher State:");
+        mInputManager.dump(pw);
         pw.println(" ");
         
         synchronized(mWindowMap) {
@@ -11995,16 +10110,6 @@
             }
             pw.print("  DisplayWidth="); pw.print(mDisplay.getWidth());
                     pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
-
-            if (! ENABLE_NATIVE_INPUT_DISPATCH) {
-                pw.println("  KeyWaiter state:");
-                pw.print("    mLastWin="); pw.print(mKeyWaiter.mLastWin);
-                        pw.print(" mLastBinder="); pw.println(mKeyWaiter.mLastBinder);
-                pw.print("    mFinished="); pw.print(mKeyWaiter.mFinished);
-                        pw.print(" mGotFirstWindow="); pw.print(mKeyWaiter.mGotFirstWindow);
-                        pw.print(" mEventDispatching="); pw.print(mKeyWaiter.mEventDispatching);
-                        pw.print(" mTimeToSwitch="); pw.println(mKeyWaiter.mTimeToSwitch);
-            }
         }
     }
 
@@ -12012,12 +10117,6 @@
     public void monitor() {
         synchronized (mWindowMap) { }
         synchronized (mKeyguardTokenWatcher) { }
-        synchronized (mKeyWaiter) { }
-        synchronized (mInputMonitor) { }
-    }
-
-    public void virtualKeyFeedback(KeyEvent event) {
-        mPolicy.keyFeedbackFromInput(event);
     }
 
     /**
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 499ca86..0cf36b3 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,9 +4,9 @@
 LOCAL_SRC_FILES:= \
     com_android_server_AlarmManagerService.cpp \
     com_android_server_BatteryService.cpp \
-    com_android_server_KeyInputQueue.cpp \
     com_android_server_InputManager.cpp \
     com_android_server_LightsService.cpp \
+    com_android_server_PowerManagerService.cpp \
     com_android_server_SensorService.cpp \
     com_android_server_SystemServer.cpp \
     com_android_server_VibratorService.cpp \
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index d0f856b..fc901f4 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -40,6 +40,7 @@
 #include "../../core/jni/android_view_KeyEvent.h"
 #include "../../core/jni/android_view_MotionEvent.h"
 #include "../../core/jni/android_view_InputChannel.h"
+#include "com_android_server_PowerManagerService.h"
 
 namespace android {
 
@@ -107,16 +108,6 @@
     LAST_SYSTEM_WINDOW      = 2999,
 };
 
-enum {
-    POWER_MANAGER_OTHER_EVENT = 0,
-    POWER_MANAGER_CHEEK_EVENT = 1,
-    POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
-                                   // up events or LONG_TOUCH events.
-    POWER_MANAGER_LONG_TOUCH_EVENT = 3,
-    POWER_MANAGER_TOUCH_UP_EVENT = 4,
-    POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
-};
-
 // Delay between reporting long touch events to the power manager.
 const nsecs_t EVENT_IGNORE_DURATION = 300 * 1000000LL; // 300 ms
 
@@ -133,20 +124,16 @@
 static struct {
     jclass clazz;
 
-    jmethodID isScreenOn;
-    jmethodID isScreenBright;
     jmethodID notifyConfigurationChanged;
     jmethodID notifyLidSwitchChanged;
     jmethodID notifyInputChannelBroken;
     jmethodID notifyInputChannelANR;
     jmethodID notifyInputChannelRecoveredFromANR;
     jmethodID notifyANR;
-    jmethodID virtualKeyFeedback;
+    jmethodID virtualKeyDownFeedback;
     jmethodID interceptKeyBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID checkInjectEventsPermission;
-    jmethodID goToSleep;
-    jmethodID pokeUserActivity;
     jmethodID notifyAppSwitchComing;
     jmethodID filterTouchEvents;
     jmethodID filterJumpyTouchEvents;
@@ -228,9 +215,7 @@
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
-    virtual void virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-            int32_t action, int32_t flags, int32_t keyCode,
-            int32_t scanCode, int32_t metaState, nsecs_t downTime);
+    virtual void virtualKeyDownFeedback();
     virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
             bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags);
     virtual int32_t interceptTrackball(nsecs_t when, bool buttonChanged, bool buttonDown,
@@ -321,7 +306,7 @@
     int32_t mDisplayWidth, mDisplayHeight;
     int32_t mDisplayOrientation;
 
-    // Callbacks.
+    // Power manager interactions.
     bool isScreenOn();
     bool isScreenBright();
 
@@ -369,9 +354,9 @@
 
     void releaseTouchedWindowLd();
 
-    int32_t identifyTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
-    int32_t identifyTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
 
     bool interceptKeyBeforeDispatching(const InputTarget& target,
@@ -391,6 +376,7 @@
     }
 
     static bool isAppSwitchKey(int32_t keyCode);
+    static bool isPolicyKey(int32_t keyCode, bool isScreenOn);
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 };
 
@@ -422,6 +408,36 @@
     return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
 }
 
+bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
+    // Special keys that the WindowManagerPolicy might care about.
+    switch (keyCode) {
+    case KEYCODE_VOLUME_UP:
+    case KEYCODE_VOLUME_DOWN:
+    case KEYCODE_ENDCALL:
+    case KEYCODE_POWER:
+    case KEYCODE_CALL:
+    case KEYCODE_HOME:
+    case KEYCODE_MENU:
+    case KEYCODE_SEARCH:
+        // media keys
+    case KEYCODE_HEADSETHOOK:
+    case KEYCODE_MEDIA_PLAY_PAUSE:
+    case KEYCODE_MEDIA_STOP:
+    case KEYCODE_MEDIA_NEXT:
+    case KEYCODE_MEDIA_PREVIOUS:
+    case KEYCODE_MEDIA_REWIND:
+    case KEYCODE_MEDIA_FAST_FORWARD:
+        return true;
+    default:
+        // We need to pass all keys to the policy in the following cases:
+        // - screen is off
+        // - keyguard is visible
+        // - policy is performing key chording
+        //return ! isScreenOn || keyguardVisible || chording;
+        return true; // XXX stubbed out for now
+    }
+}
+
 bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
     if (env->ExceptionCheck()) {
         LOGE("An exception was thrown by callback '%s'.", methodName);
@@ -546,39 +562,22 @@
 }
 
 bool NativeInputManager::isScreenOn() {
-    JNIEnv* env = jniEnv();
-
-    jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenOn);
-    if (checkAndClearExceptionFromCallback(env, "isScreenOn")) {
-        return true;
-    }
-    return result;
+    return android_server_PowerManagerService_isScreenOn();
 }
 
 bool NativeInputManager::isScreenBright() {
-    JNIEnv* env = jniEnv();
-
-    jboolean result = env->CallBooleanMethod(mCallbacksObj, gCallbacksClassInfo.isScreenBright);
-    if (checkAndClearExceptionFromCallback(env, "isScreenBright")) {
-        return true;
-    }
-    return result;
+    return android_server_PowerManagerService_isScreenBright();
 }
 
-void NativeInputManager::virtualKeyFeedback(nsecs_t when, int32_t deviceId,
-        int32_t action, int32_t flags, int32_t keyCode,
-        int32_t scanCode, int32_t metaState, nsecs_t downTime) {
+void NativeInputManager::virtualKeyDownFeedback() {
 #if DEBUG_INPUT_READER_POLICY
-    LOGD("virtualKeyFeedback - when=%lld, deviceId=%d, action=%d, flags=%d, keyCode=%d, "
-            "scanCode=%d, metaState=%d, downTime=%lld",
-            when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
+    LOGD("virtualKeyDownFeedback");
 #endif
 
     JNIEnv* env = jniEnv();
 
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyFeedback,
-            when, deviceId, action, flags, keyCode, scanCode, metaState, downTime);
-    checkAndClearExceptionFromCallback(env, "virtualKeyFeedback");
+    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
+    checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
 }
 
 int32_t NativeInputManager::interceptKey(nsecs_t when,
@@ -593,16 +592,21 @@
     const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
     const int32_t WM_ACTION_GO_TO_SLEEP = 4;
 
-    JNIEnv* env = jniEnv();
-
     bool isScreenOn = this->isScreenOn();
     bool isScreenBright = this->isScreenBright();
 
-    jint wmActions = env->CallIntMethod(mCallbacksObj,
-            gCallbacksClassInfo.interceptKeyBeforeQueueing,
-            deviceId, EV_KEY, scanCode, keyCode, policyFlags, down ? 1 : 0, when, isScreenOn);
-    if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
-        wmActions = 0;
+    jint wmActions = 0;
+    if (isPolicyKey(keyCode, isScreenOn)) {
+        JNIEnv* env = jniEnv();
+
+        wmActions = env->CallIntMethod(mCallbacksObj,
+                gCallbacksClassInfo.interceptKeyBeforeQueueing,
+                when, keyCode, down, policyFlags, isScreenOn);
+        if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+            wmActions = 0;
+        }
+    } else {
+        wmActions = WM_ACTION_PASS_TO_USER;
     }
 
     int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
@@ -617,8 +621,7 @@
     }
 
     if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.goToSleep, when);
-        checkAndClearExceptionFromCallback(env, "goToSleep");
+        android_server_PowerManagerService_goToSleep(when);
     }
 
     if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
@@ -629,6 +632,8 @@
         actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
 
         if (down && isAppSwitchKey(keyCode)) {
+            JNIEnv* env = jniEnv();
+
             env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyAppSwitchComing);
             checkAndClearExceptionFromCallback(env, "notifyAppSwitchComing");
 
@@ -1531,11 +1536,13 @@
         windowType = focusedWindow->layoutParamsType;
     } // release lock
 
-    const InputTarget& target = outTargets.top();
-    bool consumed = interceptKeyBeforeDispatching(target, keyEvent, policyFlags);
-    if (consumed) {
-        outTargets.clear();
-        return INPUT_EVENT_INJECTION_SUCCEEDED;
+    if (isPolicyKey(keyEvent->getKeyCode(), isScreenOn())) {
+        const InputTarget& target = outTargets.top();
+        bool consumed = interceptKeyBeforeDispatching(target, keyEvent, policyFlags);
+        if (consumed) {
+            outTargets.clear();
+            return INPUT_EVENT_INJECTION_SUCCEEDED;
+        }
     }
 
     pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT);
@@ -1552,11 +1559,11 @@
 
     switch (motionEvent->getNature()) {
     case INPUT_EVENT_NATURE_TRACKBALL:
-        return identifyTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+        return waitForTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
 
     case INPUT_EVENT_NATURE_TOUCH:
-        return identifyTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+        return waitForTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
 
     default:
@@ -1565,11 +1572,11 @@
     }
 }
 
-int32_t NativeInputManager::identifyTrackballEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForTrackballEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("identifyTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1591,11 +1598,11 @@
     return INPUT_EVENT_INJECTION_SUCCEEDED;
 }
 
-int32_t NativeInputManager::identifyTouchEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForTouchEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("identifyTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1642,8 +1649,8 @@
     if (inputChannelObj) {
         jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeDispatching,
-                inputChannelObj, keyEvent->getKeyCode(), keyEvent->getMetaState(),
-                keyEvent->getAction() == KEY_EVENT_ACTION_DOWN,
+                inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
+                keyEvent->getKeyCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), policyFlags);
         bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
 
@@ -1665,10 +1672,7 @@
 }
 
 void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
-    JNIEnv* env = jniEnv();
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.pokeUserActivity,
-            eventTime, eventType);
-    checkAndClearExceptionFromCallback(env, "pokeUserActivity");
+    android_server_PowerManagerService_userActivity(eventTime, eventType);
 }
 
 void NativeInputManager::dumpDispatchStateLd() {
@@ -2082,12 +2086,6 @@
 
     FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks");
 
-    GET_METHOD_ID(gCallbacksClassInfo.isScreenOn, gCallbacksClassInfo.clazz,
-            "isScreenOn", "()Z");
-
-    GET_METHOD_ID(gCallbacksClassInfo.isScreenBright, gCallbacksClassInfo.clazz,
-            "isScreenBright", "()Z");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz,
             "notifyConfigurationChanged", "(JIII)V");
 
@@ -2106,24 +2104,18 @@
     GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
             "notifyANR", "(Ljava/lang/Object;)J");
 
-    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyFeedback, gCallbacksClassInfo.clazz,
-            "virtualKeyFeedback", "(JIIIIIIJ)V");
+    GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
+            "virtualKeyDownFeedback", "()V");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeQueueing", "(IIIIIIJZ)I");
+            "interceptKeyBeforeQueueing", "(JIZIZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIZII)Z");
+            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z");
 
     GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
             "checkInjectEventsPermission", "(II)Z");
 
-    GET_METHOD_ID(gCallbacksClassInfo.goToSleep, gCallbacksClassInfo.clazz,
-            "goToSleep", "(J)V");
-
-    GET_METHOD_ID(gCallbacksClassInfo.pokeUserActivity, gCallbacksClassInfo.clazz,
-            "pokeUserActivity", "(JI)V");
-
     GET_METHOD_ID(gCallbacksClassInfo.notifyAppSwitchComing, gCallbacksClassInfo.clazz,
             "notifyAppSwitchComing", "()V");
 
diff --git a/services/jni/com_android_server_KeyInputQueue.cpp b/services/jni/com_android_server_KeyInputQueue.cpp
deleted file mode 100644
index f9e3585..0000000
--- a/services/jni/com_android_server_KeyInputQueue.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2007 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 "jni.h"
-#include "JNIHelp.h"
-#include <utils/misc.h>
-#include <utils/Log.h>
-
-#include <ui/EventHub.h>
-#include <utils/threads.h>
-
-#include <stdio.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static struct input_offsets_t
-{
-    jfieldID mMinValue;
-    jfieldID mMaxValue;
-    jfieldID mFlat;
-    jfieldID mFuzz;
-    
-    jfieldID mDeviceId;
-    jfieldID mType;
-    jfieldID mScancode;
-    jfieldID mKeycode;
-    jfieldID mFlags;
-    jfieldID mValue;
-    jfieldID mWhen;
-} gInputOffsets;
-
-// ----------------------------------------------------------------------------
-
-static Mutex gLock;
-static sp<EventHub> gHub;
-
-static jboolean
-android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
-                                          jobject event)
-{
-    gLock.lock();
-    sp<EventHub> hub = gHub;
-    if (hub == NULL) {
-        hub = new EventHub;
-        gHub = hub;
-    }
-    gLock.unlock();
-
-    int32_t deviceId;
-    int32_t type;
-    int32_t scancode, keycode;
-    uint32_t flags;
-    int32_t value;
-    nsecs_t when;
-    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
-            &flags, &value, &when);
-
-    env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
-    env->SetIntField(event, gInputOffsets.mType, (jint)type);
-    env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
-    env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
-    env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
-    env->SetIntField(event, gInputOffsets.mValue, value);
-    env->SetLongField(event, gInputOffsets.mWhen,
-                        (jlong)(nanoseconds_to_milliseconds(when)));
-
-    return res;
-}
-
-static jint
-android_server_KeyInputQueue_getDeviceClasses(JNIEnv* env, jobject clazz,
-                                              jint deviceId)
-{
-    jint classes = 0;
-    gLock.lock();
-    if (gHub != NULL) classes = gHub->getDeviceClasses(deviceId);
-    gLock.unlock();
-    return classes;
-}
-
-static jstring
-android_server_KeyInputQueue_getDeviceName(JNIEnv* env, jobject clazz,
-                                              jint deviceId)
-{
-    String8 name;
-    gLock.lock();
-    if (gHub != NULL) name = gHub->getDeviceName(deviceId);
-    gLock.unlock();
-    
-    if (name.size() > 0) {
-        return env->NewStringUTF(name.string());
-    }
-    return NULL;
-}
-
-static void
-android_server_KeyInputQueue_addExcludedDevice(JNIEnv* env, jobject clazz,
-                                              jstring deviceName)
-{
-    gLock.lock();
-    sp<EventHub> hub = gHub;
-    if (hub == NULL) {
-        hub = new EventHub;
-        gHub = hub;
-    }
-    gLock.unlock();
-
-    const char* nameStr = env->GetStringUTFChars(deviceName, NULL);
-    gHub->addExcludedDevice(nameStr);
-    env->ReleaseStringUTFChars(deviceName, nameStr);
-}
-
-static jboolean
-android_server_KeyInputQueue_getAbsoluteInfo(JNIEnv* env, jobject clazz,
-                                             jint deviceId, jint axis,
-                                             jobject info)
-{
-    int32_t minValue, maxValue, flat, fuzz;
-    int res = -1;
-    gLock.lock();
-    if (gHub != NULL) {
-        res = gHub->getAbsoluteInfo(deviceId, axis,
-                &minValue, &maxValue, &flat, &fuzz);
-    }
-    gLock.unlock();
-    
-    if (res < 0) return JNI_FALSE;
-    
-    env->SetIntField(info, gInputOffsets.mMinValue, (jint)minValue);
-    env->SetIntField(info, gInputOffsets.mMaxValue, (jint)maxValue);
-    env->SetIntField(info, gInputOffsets.mFlat, (jint)flat);
-    env->SetIntField(info, gInputOffsets.mFuzz, (jint)fuzz);
-    return JNI_TRUE;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getSwitchState(-1, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getSwitchStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getSwitchState(deviceId, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getScanCodeState(0, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getScancodeStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getScanCodeState(deviceId, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeState(JNIEnv* env, jobject clazz,
-                                           jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getKeyCodeState(0, -1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_getKeycodeStateDevice(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint sw)
-{
-    jint st = -1;
-    gLock.lock();
-    if (gHub != NULL) st = gHub->getKeyCodeState(deviceId,-1, sw);
-    gLock.unlock();
-    
-    return st;
-}
-
-static jint
-android_server_KeyInputQueue_scancodeToKeycode(JNIEnv* env, jobject clazz,
-                                            jint deviceId, jint scancode)
-{
-    jint res = 0;
-    gLock.lock();
-    if (gHub != NULL) {
-        int32_t keycode;
-        uint32_t flags;
-        gHub->scancodeToKeycode(deviceId, scancode, &keycode, &flags);
-        res = keycode;
-    }
-    gLock.unlock();
-    
-    return res;
-}
-
-static jboolean
-android_server_KeyInputQueue_hasKeys(JNIEnv* env, jobject clazz,
-                                     jintArray keyCodes, jbooleanArray outFlags)
-{
-    jboolean ret = JNI_FALSE;
-
-    int32_t* codes = env->GetIntArrayElements(keyCodes, NULL);
-    uint8_t* flags = env->GetBooleanArrayElements(outFlags, NULL);
-    jsize numCodes = env->GetArrayLength(keyCodes);
-    if (numCodes == env->GetArrayLength(outFlags)) {
-        gLock.lock();
-        if (gHub != NULL) ret = gHub->hasKeys(numCodes, codes, flags);
-        gLock.unlock();
-    }
-
-    env->ReleaseBooleanArrayElements(outFlags, flags, 0);
-    env->ReleaseIntArrayElements(keyCodes, codes, 0);
-    return ret;
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gInputMethods[] = {
-    /* name, signature, funcPtr */
-    { "readEvent",       "(Landroid/view/RawInputEvent;)Z",
-            (void*) android_server_KeyInputQueue_readEvent },
-    { "getDeviceClasses", "(I)I",
-        (void*) android_server_KeyInputQueue_getDeviceClasses },
-    { "getDeviceName", "(I)Ljava/lang/String;",
-        (void*) android_server_KeyInputQueue_getDeviceName },
-    { "addExcludedDevice", "(Ljava/lang/String;)V",
-        (void*) android_server_KeyInputQueue_addExcludedDevice },
-    { "getAbsoluteInfo", "(IILcom/android/server/InputDevice$AbsoluteInfo;)Z",
-        (void*) android_server_KeyInputQueue_getAbsoluteInfo },
-    { "getSwitchState", "(I)I",
-        (void*) android_server_KeyInputQueue_getSwitchState },
-    { "getSwitchState", "(II)I",
-        (void*) android_server_KeyInputQueue_getSwitchStateDevice },
-    { "nativeGetScancodeState", "(I)I",
-        (void*) android_server_KeyInputQueue_getScancodeState },
-    { "nativeGetScancodeState", "(II)I",
-        (void*) android_server_KeyInputQueue_getScancodeStateDevice },
-    { "nativeGetKeycodeState", "(I)I",
-        (void*) android_server_KeyInputQueue_getKeycodeState },
-    { "nativeGetKeycodeState", "(II)I",
-        (void*) android_server_KeyInputQueue_getKeycodeStateDevice },
-    { "hasKeys", "([I[Z)Z",
-        (void*) android_server_KeyInputQueue_hasKeys },
-    { "scancodeToKeycode", "(II)I",
-        (void*) android_server_KeyInputQueue_scancodeToKeycode },
-};
-
-int register_android_server_KeyInputQueue(JNIEnv* env)
-{
-    jclass input = env->FindClass("com/android/server/KeyInputQueue");
-    LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/KeyInputQueue");
-    int res = jniRegisterNativeMethods(env, "com/android/server/KeyInputQueue",
-                                        gInputMethods, NELEM(gInputMethods));
-
-    jclass absoluteInfo = env->FindClass("com/android/server/InputDevice$AbsoluteInfo");
-    LOG_FATAL_IF(absoluteInfo == NULL, "Unable to find class com/android/server/InputDevice$AbsoluteInfo");
-    
-    gInputOffsets.mMinValue
-        = env->GetFieldID(absoluteInfo, "minValue", "I");
-    LOG_FATAL_IF(gInputOffsets.mMinValue == NULL, "Unable to find InputDevice.AbsoluteInfo.minValue");
-    
-    gInputOffsets.mMaxValue
-        = env->GetFieldID(absoluteInfo, "maxValue", "I");
-    LOG_FATAL_IF(gInputOffsets.mMaxValue == NULL, "Unable to find InputDevice.AbsoluteInfo.maxValue");
-    
-    gInputOffsets.mFlat
-        = env->GetFieldID(absoluteInfo, "flat", "I");
-    LOG_FATAL_IF(gInputOffsets.mFlat == NULL, "Unable to find InputDevice.AbsoluteInfo.flat");
-    
-    gInputOffsets.mFuzz
-        = env->GetFieldID(absoluteInfo, "fuzz", "I");
-    LOG_FATAL_IF(gInputOffsets.mFuzz == NULL, "Unable to find InputDevice.AbsoluteInfo.fuzz");
-    
-    jclass inputEvent = env->FindClass("android/view/RawInputEvent");
-    LOG_FATAL_IF(inputEvent == NULL, "Unable to find class android/view/RawInputEvent");
-
-    gInputOffsets.mDeviceId
-        = env->GetFieldID(inputEvent, "deviceId", "I");
-    LOG_FATAL_IF(gInputOffsets.mDeviceId == NULL, "Unable to find RawInputEvent.deviceId");
-    
-    gInputOffsets.mType
-        = env->GetFieldID(inputEvent, "type", "I");
-    LOG_FATAL_IF(gInputOffsets.mType == NULL, "Unable to find RawInputEvent.type");
-    
-    gInputOffsets.mScancode
-        = env->GetFieldID(inputEvent, "scancode", "I");
-    LOG_FATAL_IF(gInputOffsets.mScancode == NULL, "Unable to find RawInputEvent.scancode");
-
-    gInputOffsets.mKeycode
-        = env->GetFieldID(inputEvent, "keycode", "I");
-    LOG_FATAL_IF(gInputOffsets.mKeycode == NULL, "Unable to find RawInputEvent.keycode");
-
-    gInputOffsets.mFlags
-        = env->GetFieldID(inputEvent, "flags", "I");
-    LOG_FATAL_IF(gInputOffsets.mFlags == NULL, "Unable to find RawInputEvent.flags");
-
-    gInputOffsets.mValue
-        = env->GetFieldID(inputEvent, "value", "I");
-    LOG_FATAL_IF(gInputOffsets.mValue == NULL, "Unable to find RawInputEvent.value");
-    
-    gInputOffsets.mWhen
-        = env->GetFieldID(inputEvent, "when", "J");
-    LOG_FATAL_IF(gInputOffsets.mWhen == NULL, "Unable to find RawInputEvent.when");
-
-    return res;
-}
-
-}; // namespace android
-
diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp
new file mode 100644
index 0000000..b80dbc5
--- /dev/null
+++ b/services/jni/com_android_server_PowerManagerService.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PowerManagerService-JNI"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include <limits.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "com_android_server_PowerManagerService.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static struct {
+    jclass clazz;
+
+    jmethodID goToSleep;
+    jmethodID userActivity;
+} gPowerManagerServiceClassInfo;
+
+// ----------------------------------------------------------------------------
+
+static jobject gPowerManagerServiceObj;
+
+static Mutex gPowerManagerLock;
+static bool gScreenOn;
+static bool gScreenBright;
+
+// ----------------------------------------------------------------------------
+
+static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+        return true;
+    }
+    return false;
+}
+
+bool android_server_PowerManagerService_isScreenOn() {
+    AutoMutex _l(gPowerManagerLock);
+    return gScreenOn;
+}
+
+bool android_server_PowerManagerService_isScreenBright() {
+    AutoMutex _l(gPowerManagerLock);
+    return gScreenBright;
+}
+
+void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.userActivity,
+                nanoseconds_to_milliseconds(eventTime), false, eventType, false);
+        checkAndClearExceptionFromCallback(env, "userActivity");
+    }
+}
+
+void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
+                nanoseconds_to_milliseconds(eventTime));
+        checkAndClearExceptionFromCallback(env, "goToSleep");
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+static void android_server_PowerManagerService_nativeInit(JNIEnv* env, jobject obj) {
+    gPowerManagerServiceObj = env->NewGlobalRef(obj);
+}
+
+static void android_server_PowerManagerService_nativeSetPowerState(JNIEnv* env,
+        jobject serviceObj, jboolean screenOn, jboolean screenBright) {
+    AutoMutex _l(gPowerManagerLock);
+    gScreenOn = screenOn;
+    gScreenBright = screenBright;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gPowerManagerServiceMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit", "()V",
+            (void*) android_server_PowerManagerService_nativeInit },
+    { "nativeSetPowerState", "(ZZ)V",
+            (void*) android_server_PowerManagerService_nativeSetPowerState },
+};
+
+#define FIND_CLASS(var, className) \
+        var = env->FindClass(className); \
+        LOG_FATAL_IF(! var, "Unable to find class " className); \
+        var = jclass(env->NewGlobalRef(var));
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+int register_android_server_PowerManagerService(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/PowerManagerService",
+            gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    // Callbacks
+
+    FIND_CLASS(gPowerManagerServiceClassInfo.clazz, "com/android/server/PowerManagerService");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, gPowerManagerServiceClassInfo.clazz,
+            "goToSleep", "(J)V");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, gPowerManagerServiceClassInfo.clazz,
+            "userActivity", "(JZIZ)V");
+
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h
new file mode 100644
index 0000000..9b05f38
--- /dev/null
+++ b/services/jni/com_android_server_PowerManagerService.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+#define _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+namespace android {
+
+enum {
+    POWER_MANAGER_OTHER_EVENT = 0,
+    POWER_MANAGER_CHEEK_EVENT = 1,
+    POWER_MANAGER_TOUCH_EVENT = 2, // touch events are TOUCH for 300ms, and then either
+                                   // up events or LONG_TOUCH events.
+    POWER_MANAGER_LONG_TOUCH_EVENT = 3,
+    POWER_MANAGER_TOUCH_UP_EVENT = 4,
+    POWER_MANAGER_BUTTON_EVENT = 5, // Button and trackball events.
+};
+
+extern bool android_server_PowerManagerService_isScreenOn();
+extern bool android_server_PowerManagerService_isScreenBright();
+extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
+extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
+
+} // namespace android
+
+#endif // _ANDROID_SERVER_POWER_MANAGER_SERVICE_H
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index a1a6838..1a2d8b6 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -6,9 +6,9 @@
 namespace android {
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_BatteryService(JNIEnv* env);
-int register_android_server_KeyInputQueue(JNIEnv* env);
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
+int register_android_server_PowerManagerService(JNIEnv* env);
 int register_android_server_SensorService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
@@ -28,7 +28,7 @@
     }
     LOG_ASSERT(env, "Could not retrieve the env!");
 
-    register_android_server_KeyInputQueue(env);
+    register_android_server_PowerManagerService(env);
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
index a74c5c2..de59b81 100644
--- a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java
@@ -496,9 +496,11 @@
         assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
         assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
         assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
-        TelephonyManager mTelephonyManager =
+        // This test fails on a device without a sim card
+        /*TelephonyManager mTelephonyManager =
             (TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
         String mVoiceMailNumber = mTelephonyManager.getDefault().getVoiceMailNumber();
         assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+        */
     }
 }
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 63d50c7..70d1643 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -496,9 +496,18 @@
         return null;
     }
 
+    /**
+     * Initialize the current thread as a looper.
+     * <p/>
+     * Exposed for unit testing.
+     */
+    void prepareLooper() {
+        Looper.prepare();
+    }
+
     @Override
     public void onStart() {
-        Looper.prepare();
+        prepareLooper();
 
         if (mJustCount) {
             mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -521,6 +530,11 @@
                 long runTime = System.currentTimeMillis() - startTime;
 
                 resultPrinter.print(mTestRunner.getTestResult(), runTime);
+            } catch (Throwable t) {
+                // catch all exceptions so a more verbose error message can be outputted
+                writer.println(String.format("Test run aborted due to unexpected exception: %s",
+                                t.getMessage()));
+                t.printStackTrace(writer);
             } finally {
                 mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
                         String.format("\nTest results for %s=%s",
@@ -762,9 +776,11 @@
                             TimedTest.class).includeDetailedStats();
                 }
             } catch (SecurityException e) {
-                throw new IllegalStateException(e);
+                // ignore - the test with given name cannot be accessed. Will be handled during
+                // test execution
             } catch (NoSuchMethodException e) {
-                throw new IllegalStateException(e);
+                // ignore- the test with given name does not exist. Will be handled during test
+                // execution
             }
 
             if (mIsTimedTest && mIncludeDetailedStats) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3e77b9b..e96173b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -483,4 +483,9 @@
     public boolean isSafeMode() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public void setPackageObbPath(String packageName, String path) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
index 6db72ad..d98b217 100644
--- a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
@@ -16,6 +16,7 @@
 
 package android.test;
 
+import android.app.Instrumentation;
 import android.content.Context;
 import android.os.Bundle;
 import android.test.mock.MockContext;
@@ -89,6 +90,42 @@
         
     }
 
+    /**
+     * Test that runtime exceptions during runTest are handled gracefully
+     */
+    public void testUnhandledException() throws Exception {
+        StubAndroidTestRunner stubAndroidTestRunner = new StubAndroidTestRunner() {
+            @Override
+            public void runTest() {
+                throw new RuntimeException();
+            }
+        };
+        StubInstrumentationTestRunner instrumentationTestRunner = new StubInstrumentationTestRunner(
+                new StubContext("com.google.foo.tests"),
+                new StubContext(mTargetContextPackageName), stubAndroidTestRunner);
+        instrumentationTestRunner.onCreate(new Bundle());
+        instrumentationTestRunner.onStart();
+        assertTrue("Instrumentation did not finish", instrumentationTestRunner.isFinished());
+        // ensure a meaningful error message placed in results
+        String resultsData = instrumentationTestRunner.mResults.getString(
+                Instrumentation.REPORT_KEY_STREAMRESULT);
+        assertTrue("Instrumentation results is missing RuntimeException",
+                resultsData.contains("RuntimeException"));
+    }
+
+    /**
+     * Test that specifying a method which does not exist is handled gracefully
+     */
+    public void testBadMethodArgument() throws Exception {
+        String testClassName = PlaceHolderTest.class.getName();
+        String invalidMethodName = "testNoExist";
+        String classAndMethod = testClassName + "#" + invalidMethodName;
+        mInstrumentationTestRunner.onCreate(createBundle(
+                InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod));
+        assertTestRunnerCalledWithExpectedParameters(testClassName,
+                invalidMethodName);
+    }
+
     public void testDelayParameter() throws Exception {
         int delayMsec = 1000;
         Bundle args = new Bundle();
@@ -170,6 +207,7 @@
         private TestSuite mTestSuite;
         private TestSuite mDefaultTestSuite;
         private String mPackageNameForDefaultTests;
+        private Bundle mResults;
 
         public StubInstrumentationTestRunner(Context context, Context targetContext,
                 AndroidTestRunner androidTestRunner) {
@@ -200,6 +238,7 @@
 
         public void finish(int resultCode, Bundle results) {
             mFinished = true;
+            mResults = results;
         }
 
         public boolean isStarted() {
@@ -221,6 +260,11 @@
         public String getPackageNameForDefaultTests() {
             return mPackageNameForDefaultTests;
         }
+
+        @Override
+        void prepareLooper() {
+            // ignore
+        }
     }
 
     private static class StubContext extends MockContext {