am 9f187296: Merge "DOC CHANGE: Fix 4084450 monkeyrunner_concepts" into honeycomb

* commit '9f18729676a58cdfcee98db3329de3397c657d48':
  DOC CHANGE: Fix 4084450 monkeyrunner_concepts
diff --git a/NOTICE b/NOTICE
index 462d5ae..152be20 100644
--- a/NOTICE
+++ b/NOTICE
@@ -56,16 +56,6 @@
    =========================================================================
    ==  NOTICE file corresponding to the section 4 d of                    ==
    ==  the Apache License, Version 2.0,                                   ==
-   ==  in this case for Additional Codecs code.                           ==
-   =========================================================================
-
-Additional Codecs
-These files are Copyright 2003-2010 VisualOn, but released under
-the Apache2 License.
-
-   =========================================================================
-   ==  NOTICE file corresponding to the section 4 d of                    ==
-   ==  the Apache License, Version 2.0,                                   ==
    ==  in this case for the TagSoup code.                                 ==
    =========================================================================
 
@@ -82,6 +72,16 @@
 OF ANY KIND, either express or implied; not even the implied warranty
 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for Additional Codecs code.                           ==
+   =========================================================================
+
+Additional Codecs
+These files are Copyright 2003-2010 VisualOn, but released under
+the Apache2 License.
+
   =========================================================================
   ==  NOTICE file corresponding to the section 4 d of                    ==
   ==  the Apache License, Version 2.0,                                   ==
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 749a977..81b56c2 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -98,7 +98,7 @@
      * Register the @a recipient for a notification if this binder
      * goes away.  If this binder object unexpectedly goes away
      * (typically because its hosting process has been killed),
-     * then DeathRecipient::binderDied() will be called with a referene
+     * then DeathRecipient::binderDied() will be called with a reference
      * to this.
      *
      * The @a cookie is optional -- if non-NULL, it should be a
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 31615d0..9bf38f7 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -37,7 +37,8 @@
 
 class SurfaceTexture : public BnSurfaceTexture {
 public:
-    enum { MIN_BUFFER_SLOTS = 3 };
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+    enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1 };
     enum { NUM_BUFFER_SLOTS = 32 };
 
     struct FrameAvailableListener : public virtual RefBase {
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index ff2251d..4cdece9 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -40,40 +40,41 @@
     SurfaceTextureClient(const SurfaceTextureClient& rhs);
 
     // ANativeWindow hooks
-    static int setSwapInterval(ANativeWindow* window, int interval);
-    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
     static int cancelBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int dequeueBuffer(ANativeWindow* window, android_native_buffer_t** buffer);
     static int lockBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
-    static int query(ANativeWindow* window, int what, int* value);
     static int perform(ANativeWindow* window, int operation, ...);
+    static int query(ANativeWindow* window, int what, int* value);
+    static int queueBuffer(ANativeWindow* window, android_native_buffer_t* buffer);
+    static int setSwapInterval(ANativeWindow* window, int interval);
 
-    int setSwapInterval(int interval);
+    int cancelBuffer(android_native_buffer_t* buffer);
     int dequeueBuffer(android_native_buffer_t** buffer);
     int lockBuffer(android_native_buffer_t* buffer);
-    int queueBuffer(android_native_buffer_t* buffer);
-    int cancelBuffer(android_native_buffer_t* buffer);
-    int query(int what, int* value);
     int perform(int operation, va_list args);
+    int query(int what, int* value);
+    int queueBuffer(android_native_buffer_t* buffer);
+    int setSwapInterval(int interval);
 
-    int dispatchSetUsage(va_list args);
     int dispatchConnect(va_list args);
     int dispatchDisconnect(va_list args);
-    int dispatchSetCrop(va_list args);
     int dispatchSetBufferCount(va_list args);
     int dispatchSetBuffersGeometry(va_list args);
     int dispatchSetBuffersTransform(va_list args);
+    int dispatchSetCrop(va_list args);
+    int dispatchSetUsage(va_list args);
 
     int connect(int api);
     int disconnect(int api);
-    int setUsage(uint32_t reqUsage);
-    int setCrop(Rect const* rect);
     int setBufferCount(int bufferCount);
     int setBuffersGeometry(int w, int h, int format);
     int setBuffersTransform(int transform);
+    int setCrop(Rect const* rect);
+    int setUsage(uint32_t reqUsage);
 
     void freeAllBuffers();
 
+    enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
     enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
     enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index eb599b5..717f837 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -65,7 +65,7 @@
     // When changing these values, the COMPILE_TIME_ASSERT at the end of this
     // file need to be updated.
     static const unsigned int NUM_LAYERS_MAX  = 31;
-    static const unsigned int NUM_BUFFER_MAX  = 16;
+    static const unsigned int NUM_BUFFER_MAX  = 32;
     static const unsigned int NUM_BUFFER_MIN  = 2;
     static const unsigned int NUM_DISPLAY_MAX = 4;
 
@@ -123,7 +123,7 @@
 
 // ----------------------------------------------------------------------------
 
-// 32 KB max
+// 64 KB max
 class SharedClient
 {
 public:
@@ -394,7 +394,7 @@
 
 // ---------------------------------------------------------------------------
 
-COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 32768)
+COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 65536)
 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
 
 // ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 56ed3a4..dea1b10 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -44,6 +44,8 @@
         eSecure             = 0x00000080,
         eNonPremultiplied   = 0x00000100,
         eOpaque             = 0x00000400,
+        eProtectedByApp     = 0x00000800,
+        eProtectedByDRM     = 0x00001000,
 
         eFXSurfaceNormal    = 0x00000000,
         eFXSurfaceBlur      = 0x00010000,
@@ -136,6 +138,10 @@
      * This is an ASYNCHRONOUS call.
      */
     virtual void signal() const = 0;
+
+    /* verify that an ISurface was created by SurfaceFlinger.
+     */
+    virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -159,7 +165,8 @@
         SIGNAL,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
-        TURN_ELECTRON_BEAM_ON
+        TURN_ELECTRON_BEAM_ON,
+        AUTHENTICATE_SURFACE,
     };
 
     virtual status_t    onTransact( uint32_t code,
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index d783caf..9e0b5bb 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -242,6 +242,10 @@
     status_t validate(bool inCancelBuffer = false) const;
     sp<ISurface> getISurface() const;
 
+    // When the buffer pool is a fixed size we want to make sure SurfaceFlinger
+    // won't stall clients, so we require an extra buffer.
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
     inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
 
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 8b256f4..02d6f8f 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -54,9 +54,11 @@
         USAGE_SW_WRITE_RARELY   = GRALLOC_USAGE_SW_WRITE_RARELY,
         USAGE_SW_WRITE_OFTEN    = GRALLOC_USAGE_SW_WRITE_OFTEN,
         USAGE_SW_WRITE_MASK     = GRALLOC_USAGE_SW_WRITE_MASK,
-        
+
         USAGE_SOFTWARE_MASK     = USAGE_SW_READ_MASK|USAGE_SW_WRITE_MASK,
-        
+
+        USAGE_PROTECTED         = GRALLOC_USAGE_PROTECTED,
+
         USAGE_HW_TEXTURE        = GRALLOC_USAGE_HW_TEXTURE,
         USAGE_HW_RENDER         = GRALLOC_USAGE_HW_RENDER,
         USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 2012fcc..d9d77c4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -28,6 +28,10 @@
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 
+#ifdef HAVE_ANDROID_OS
+class SkMatrix;
+#endif
+
 /*
  * Additional private constants not defined in ndk/ui/input.h.
  */
@@ -48,6 +52,14 @@
 };
 
 /*
+ * SystemUiVisibility constants from View.
+ */
+enum {
+    ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
+    ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
+};
+
+/*
  * Maximum number of pointers supported per motion event.
  * Smallest number of pointers is 1.
  * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
@@ -79,6 +91,10 @@
 
 namespace android {
 
+#ifdef HAVE_ANDROID_OS
+class Parcel;
+#endif
+
 /*
  * Flags that flow alongside events in the input dispatch system to help with certain
  * policy decisions such as waking from device sleep.
@@ -128,6 +144,14 @@
 };
 
 /*
+ * Button state.
+ */
+enum {
+    // Primary button pressed (left mouse button).
+    BUTTON_STATE_PRIMARY = 1 << 0,
+};
+
+/*
  * Describes the basic configuration of input devices that are present.
  */
 struct InputConfiguration {
@@ -162,15 +186,30 @@
  * Pointer coordinate data.
  */
 struct PointerCoords {
-    float x;
-    float y;
-    float pressure;
-    float size;
-    float touchMajor;
-    float touchMinor;
-    float toolMajor;
-    float toolMinor;
-    float orientation;
+    enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64
+
+    // Bitfield of axes that are present in this structure.
+    uint64_t bits;
+
+    // Values of axes that are stored in this structure packed in order by axis id
+    // for each axis that is present in the structure according to 'bits'.
+    float values[MAX_AXES];
+
+    inline void clear() {
+        bits = 0;
+    }
+
+    float getAxisValue(int32_t axis) const;
+    status_t setAxisValue(int32_t axis, float value);
+    float* editAxisValue(int32_t axis);
+
+#ifdef HAVE_ANDROID_OS
+    status_t readFromParcel(Parcel* parcel);
+    status_t writeToParcel(Parcel* parcel) const;
+#endif
+
+private:
+    void tooManyAxes(int axis);
 };
 
 /*
@@ -185,12 +224,13 @@
     inline int32_t getDeviceId() const { return mDeviceId; }
 
     inline int32_t getSource() const { return mSource; }
-    
+
+    inline void setSource(int32_t source) { mSource = source; }
+
 protected:
     void initialize(int32_t deviceId, int32_t source);
     void initialize(const InputEvent& from);
 
-private:
     int32_t mDeviceId;
     int32_t mSource;
 };
@@ -241,7 +281,7 @@
             nsecs_t eventTime);
     void initialize(const KeyEvent& from);
 
-private:
+protected:
     int32_t mAction;
     int32_t mFlags;
     int32_t mKeyCode;
@@ -263,12 +303,18 @@
 
     inline int32_t getAction() const { return mAction; }
 
+    inline void setAction(int32_t action) { mAction = action; }
+
     inline int32_t getFlags() const { return mFlags; }
 
     inline int32_t getEdgeFlags() const { return mEdgeFlags; }
 
+    inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; }
+
     inline int32_t getMetaState() const { return mMetaState; }
 
+    inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
+
     inline float getXOffset() const { return mXOffset; }
 
     inline float getYOffset() const { return mYOffset; }
@@ -285,48 +331,54 @@
 
     inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
 
+    const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
+
+    float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
+
     inline float getRawX(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).x;
+        return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
     }
 
     inline float getRawY(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).y;
+        return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
     }
 
+    float getAxisValue(int32_t axis, size_t pointerIndex) const;
+
     inline float getX(size_t pointerIndex) const {
-        return getRawX(pointerIndex) + mXOffset;
+        return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
     }
 
     inline float getY(size_t pointerIndex) const {
-        return getRawY(pointerIndex) + mYOffset;
+        return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
     }
 
     inline float getPressure(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).pressure;
+        return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex);
     }
 
     inline float getSize(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).size;
+        return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex);
     }
 
     inline float getTouchMajor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).touchMajor;
+        return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex);
     }
 
     inline float getTouchMinor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).touchMinor;
+        return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex);
     }
 
     inline float getToolMajor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).toolMajor;
+        return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex);
     }
 
     inline float getToolMinor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).toolMinor;
+        return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex);
     }
 
     inline float getOrientation(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).orientation;
+        return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex);
     }
 
     inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
@@ -335,48 +387,67 @@
         return mSampleEventTimes[historicalIndex];
     }
 
+    const PointerCoords* getHistoricalRawPointerCoords(
+            size_t pointerIndex, size_t historicalIndex) const;
+
+    float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
+            size_t historicalIndex) const;
+
     inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).x;
+        return getHistoricalRawAxisValue(
+                AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).y;
+        return getHistoricalRawAxisValue(
+                AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
     }
 
+    float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const;
+
     inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalRawX(pointerIndex, historicalIndex) + mXOffset;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalRawY(pointerIndex, historicalIndex) + mYOffset;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).size;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMajor;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMinor;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMajor;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMinor;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).orientation;
+        return getHistoricalAxisValue(
+                AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex);
     }
 
     void initialize(
@@ -396,12 +467,28 @@
             const int32_t* pointerIds,
             const PointerCoords* pointerCoords);
 
+    void copyFrom(const MotionEvent* other, bool keepHistory);
+
     void addSample(
             nsecs_t eventTime,
             const PointerCoords* pointerCoords);
 
     void offsetLocation(float xOffset, float yOffset);
 
+    void scale(float scaleFactor);
+
+#ifdef HAVE_ANDROID_OS
+    void transform(const SkMatrix* matrix);
+
+    status_t readFromParcel(Parcel* parcel);
+    status_t writeToParcel(Parcel* parcel) const;
+#endif
+
+    static bool isTouchEvent(int32_t source, int32_t action);
+    inline bool isTouchEvent() const {
+        return isTouchEvent(mSource, mAction);
+    }
+
     // Low-level accessors.
     inline const int32_t* getPointerIds() const { return mPointerIds.array(); }
     inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
@@ -409,7 +496,7 @@
             return mSamplePointerCoords.array();
     }
 
-private:
+protected:
     int32_t mAction;
     int32_t mFlags;
     int32_t mEdgeFlags;
@@ -422,15 +509,6 @@
     Vector<int32_t> mPointerIds;
     Vector<nsecs_t> mSampleEventTimes;
     Vector<PointerCoords> mSamplePointerCoords;
-
-    inline const PointerCoords& getCurrentPointerCoords(size_t pointerIndex) const {
-        return mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
-    }
-
-    inline const PointerCoords& getHistoricalPointerCoords(
-            size_t pointerIndex, size_t historicalIndex) const {
-        return mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
-    }
 };
 
 /*
@@ -474,6 +552,8 @@
     ~InputDeviceInfo();
 
     struct MotionRange {
+        int32_t axis;
+        uint32_t source;
         float min;
         float max;
         float flat;
@@ -486,16 +566,17 @@
     inline const String8 getName() const { return mName; }
     inline uint32_t getSources() const { return mSources; }
 
-    const MotionRange* getMotionRange(int32_t rangeType) const;
+    const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
 
     void addSource(uint32_t source);
-    void addMotionRange(int32_t rangeType, float min, float max, float flat, float fuzz);
-    void addMotionRange(int32_t rangeType, const MotionRange& range);
+    void addMotionRange(int32_t axis, uint32_t source,
+            float min, float max, float flat, float fuzz);
+    void addMotionRange(const MotionRange& range);
 
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
 
-    inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const {
+    inline const Vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
 
@@ -505,7 +586,7 @@
     uint32_t mSources;
     int32_t mKeyboardType;
 
-    KeyedVector<int32_t, MotionRange> mMotionRanges;
+    Vector<MotionRange> mMotionRanges;
 };
 
 /*
diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h
index f0a6d00..d82d0c8 100644
--- a/include/ui/KeyLayoutMap.h
+++ b/include/ui/KeyLayoutMap.h
@@ -24,8 +24,38 @@
 
 namespace android {
 
+struct AxisInfo {
+    enum Mode {
+        // Axis value is reported directly.
+        MODE_NORMAL = 0,
+        // Axis value should be inverted before reporting.
+        MODE_INVERT = 1,
+        // Axis value should be split into two axes
+        MODE_SPLIT = 2,
+    };
+
+    // Axis mode.
+    Mode mode;
+
+    // Axis id.
+    // When split, this is the axis used for values smaller than the split position.
+    int32_t axis;
+
+    // When split, this is the axis used for values after higher than the split position.
+    int32_t highAxis;
+
+    // The split value, or 0 if not split.
+    int32_t splitValue;
+
+    // The flat value, or -1 if none.
+    int32_t flatOverride;
+
+    AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
+    }
+};
+
 /**
- * Describes a mapping from keyboard scan codes to Android key codes.
+ * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
  */
 class KeyLayoutMap {
 public:
@@ -33,8 +63,10 @@
 
     static status_t load(const String8& filename, KeyLayoutMap** outMap);
 
-    status_t map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
-    status_t findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
+    status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
+    status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
+
+    status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
 
 private:
     struct Key {
@@ -42,7 +74,8 @@
         uint32_t flags;
     };
 
-    KeyedVector<int32_t,Key> mKeys;
+    KeyedVector<int32_t, Key> mKeys;
+    KeyedVector<int32_t, AxisInfo> mAxes;
 
     KeyLayoutMap();
 
@@ -57,6 +90,7 @@
 
     private:
         status_t parseKey();
+        status_t parseAxis();
     };
 };
 
diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h
index 50296e2..609f319 100644
--- a/include/ui/Keyboard.h
+++ b/include/ui/Keyboard.h
@@ -111,10 +111,27 @@
 extern uint32_t getKeyFlagByLabel(const char* label);
 
 /**
+ * Gets a axis by its short form label, eg. "X".
+ * Returns -1 if unknown.
+ */
+extern int32_t getAxisByLabel(const char* label);
+
+/**
+ * Gets a axis label by its id.
+ * Returns NULL if unknown.
+ */
+extern const char* getAxisLabel(int32_t axisId);
+
+/**
  * Updates a meta state field when a key is pressed or released.
  */
 extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
 
+/**
+ * Returns true if a key is a meta key like ALT or CAPS_LOCK.
+ */
+extern bool isMetaKey(int32_t keyCode);
+
 } // namespace android
 
 #endif // _UI_KEYBOARD_H
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 9b1a897..b912e9b 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -212,6 +212,22 @@
     { "PROG_YELLOW", 185 },
     { "PROG_BLUE", 186 },
     { "APP_SWITCH", 187 },
+    { "BUTTON_1", 188 },
+    { "BUTTON_2", 189 },
+    { "BUTTON_3", 190 },
+    { "BUTTON_4", 191 },
+    { "BUTTON_5", 192 },
+    { "BUTTON_6", 193 },
+    { "BUTTON_7", 194 },
+    { "BUTTON_8", 195 },
+    { "BUTTON_9", 196 },
+    { "BUTTON_10", 197 },
+    { "BUTTON_11", 198 },
+    { "BUTTON_12", 199 },
+    { "BUTTON_13", 200 },
+    { "BUTTON_14", 201 },
+    { "BUTTON_15", 202 },
+    { "BUTTON_16", 203 },
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
@@ -234,4 +250,52 @@
     { NULL, 0 }
 };
 
+static const KeycodeLabel AXES[] = {
+    { "X", 0 },
+    { "Y", 1 },
+    { "PRESSURE", 2 },
+    { "SIZE", 3 },
+    { "TOUCH_MAJOR", 4 },
+    { "TOUCH_MINOR", 5 },
+    { "TOOL_MAJOR", 6 },
+    { "TOOL_MINOR", 7 },
+    { "ORIENTATION", 8 },
+    { "VSCROLL", 9 },
+    { "HSCROLL", 10 },
+    { "Z", 11 },
+    { "RX", 12 },
+    { "RY", 13 },
+    { "RZ", 14 },
+    { "HAT_X", 15 },
+    { "HAT_Y", 16 },
+    { "LTRIGGER", 17 },
+    { "RTRIGGER", 18 },
+    { "THROTTLE", 19 },
+    { "RUDDER", 20 },
+    { "WHEEL", 21 },
+    { "GAS", 22 },
+    { "BRAKE", 23 },
+    { "GENERIC_1", 32 },
+    { "GENERIC_2", 33 },
+    { "GENERIC_3", 34 },
+    { "GENERIC_4", 35 },
+    { "GENERIC_5", 36 },
+    { "GENERIC_6", 37 },
+    { "GENERIC_7", 38 },
+    { "GENERIC_8", 39 },
+    { "GENERIC_9", 40 },
+    { "GENERIC_10", 41 },
+    { "GENERIC_11", 42 },
+    { "GENERIC_12", 43 },
+    { "GENERIC_13", 44 },
+    { "GENERIC_14", 45 },
+    { "GENERIC_15", 46 },
+    { "GENERIC_16", 47 },
+
+    // NOTE: If you add a new axis here you must also add it to several other files.
+    //       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
+
+    { NULL, -1 }
+};
+
 #endif // _UI_KEYCODE_LABELS_H
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index fdc8105..0ac34d0 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -75,6 +75,41 @@
     NATIVE_WINDOW_WIDTH     = 0,
     NATIVE_WINDOW_HEIGHT,
     NATIVE_WINDOW_FORMAT,
+
+    /* The minimum number of buffers that must remain un-dequeued after a buffer
+     * has been queued.  This value applies only if set_buffer_count was used to
+     * override the number of buffers and if a buffer has since been queued.
+     * Users of the set_buffer_count ANativeWindow method should query this
+     * value before calling set_buffer_count.  If it is necessary to have N
+     * buffers simultaneously dequeued as part of the steady-state operation,
+     * and this query returns M then N+M buffers should be requested via
+     * native_window_set_buffer_count.
+     *
+     * Note that this value does NOT apply until a single buffer has been
+     * queued.  In particular this means that it is possible to:
+     *
+     * 1. Query M = min undequeued buffers
+     * 2. Set the buffer count to N + M
+     * 3. Dequeue all N + M buffers
+     * 4. Cancel M buffers
+     * 5. Queue, dequeue, queue, dequeue, ad infinitum
+     */
+    NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+
+    /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+     * to the window compositor.  The query sets the returned 'value' argument
+     * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+     * compositor and 0 if the buffers do not go directly to the window
+     * compositor.
+     *
+     * This can be used to determine whether protected buffer content should be
+     * sent to the ANativeWindow.  Note, however, that a result of 1 does NOT
+     * indicate that queued buffers will be protected from applications or users
+     * capturing their contents.  If that behavior is desired then some other
+     * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+     * conjunction with this query.
+     */
+    NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
 };
 
 /* valid operations for the (*perform)() hook */
diff --git a/include/utils/Functor.h b/include/utils/Functor.h
index 3955bc3..565f4a3 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -26,6 +26,7 @@
     Functor() {}
     virtual ~Functor() {}
     virtual status_t operator ()() { return true; }
+    virtual status_t operator ()(float* data, uint32_t len) { return true; }
 };
 
 }; // namespace android
diff --git a/include/utils/Looper.h b/include/utils/Looper.h
index eefff31..3c2905d 100644
--- a/include/utils/Looper.h
+++ b/include/utils/Looper.h
@@ -45,6 +45,51 @@
 namespace android {
 
 /**
+ * A message that can be posted to a Looper.
+ */
+struct Message {
+    Message() : what(0) { }
+    Message(int what) : what(what) { }
+
+    /* The message type. (interpretation is left up to the handler) */
+    int what;
+};
+
+
+/**
+ * Interface for a Looper message handler.
+ *
+ * The Looper holds a strong reference to the message handler whenever it has
+ * a message to deliver to it.  Make sure to call Looper::removeMessages
+ * to remove any pending messages destined for the handler so that the handler
+ * can be destroyed.
+ */
+class MessageHandler : public virtual RefBase {
+protected:
+    virtual ~MessageHandler() { }
+
+public:
+    /**
+     * Handles a message.
+     */
+    virtual void handleMessage(const Message& message) = 0;
+};
+
+
+/**
+ * A simple proxy that holds a weak reference to a message handler.
+ */
+class WeakMessageHandler : public MessageHandler {
+public:
+    WeakMessageHandler(const wp<MessageHandler>& handler);
+    virtual void handleMessage(const Message& message);
+
+private:
+    wp<MessageHandler> mHandler;
+};
+
+
+/**
  * A polling loop that supports monitoring file descriptor events, optionally
  * using callbacks.  The implementation uses epoll() internally.
  *
@@ -166,6 +211,52 @@
     int removeFd(int fd);
 
     /**
+     * Enqueues a message to be processed by the specified handler.
+     *
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void sendMessage(const sp<MessageHandler>& handler, const Message& message);
+
+    /**
+     * Enqueues a message to be processed by the specified handler after all pending messages
+     * after the specified delay.
+     *
+     * The time delay is specified in uptime nanoseconds.
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
+            const Message& message);
+
+    /**
+     * Enqueues a message to be processed by the specified handler after all pending messages
+     * at the specified time.
+     *
+     * The time is specified in uptime nanoseconds.
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
+            const Message& message);
+
+    /**
+     * Removes all messages for the specified handler from the queue.
+     *
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void removeMessages(const sp<MessageHandler>& handler);
+
+    /**
+     * Removes all messages of a particular type for the specified handler from the queue.
+     *
+     * The handler must not be null.
+     * This method can be called on any thread.
+     */
+    void removeMessages(const sp<MessageHandler>& handler, int what);
+
+    /**
      * Prepares a looper associated with the calling thread, and returns it.
      * If the thread already has a looper, it is returned.  Otherwise, a new
      * one is created, associated with the thread, and returned.
@@ -201,12 +292,27 @@
         Request request;
     };
 
+    struct MessageEnvelope {
+        MessageEnvelope() : uptime(0) { }
+
+        MessageEnvelope(nsecs_t uptime, const sp<MessageHandler> handler,
+                const Message& message) : uptime(uptime), handler(handler), message(message) {
+        }
+
+        nsecs_t uptime;
+        sp<MessageHandler> handler;
+        Message message;
+    };
+
     const bool mAllowNonCallbacks; // immutable
 
     int mWakeReadPipeFd;  // immutable
     int mWakeWritePipeFd; // immutable
     Mutex mLock;
 
+    Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock
+    bool mSendingMessage; // guarded by mLock
+
 #ifdef LOOPER_USES_EPOLL
     int mEpollFd; // immutable
 
@@ -256,6 +362,7 @@
     // it runs on a single thread.
     Vector<Response> mResponses;
     size_t mResponseIndex;
+    nsecs_t mNextMessageUptime; // set to LLONG_MAX when none
 
     int pollInner(int timeoutMillis);
     void awoken();
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index c24c0db..f355087 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -18,16 +18,19 @@
 #define ANDROID_REF_BASE_H
 
 #include <cutils/atomic.h>
-#include <utils/TextOutput.h>
 
 #include <stdint.h>
 #include <sys/types.h>
 #include <stdlib.h>
+#include <string.h>
+
+#include <utils/StrongPointer.h>
 
 // ---------------------------------------------------------------------------
 namespace android {
 
-template<typename T> class wp;
+class TextOutput;
+TextOutput& printWeakPointer(TextOutput& to, const void* val);
 
 // ---------------------------------------------------------------------------
 
@@ -47,15 +50,15 @@
     return m_ptr _op_ o;                                        \
 }
 
-#define COMPARE(_op_)                                           \
-COMPARE_WEAK(_op_)                                              \
-inline bool operator _op_ (const wp<T>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}                                                               \
-template<typename U>                                            \
-inline bool operator _op_ (const wp<U>& o) const {              \
-    return m_ptr _op_ o.m_ptr;                                  \
-}
+// ---------------------------------------------------------------------------
+
+class ReferenceMover;
+class ReferenceConverterBase {
+public:
+    virtual size_t getReferenceTypeSize() const = 0;
+    virtual void* getReferenceBase(void const*) const = 0;
+    inline virtual ~ReferenceConverterBase() { }
+};
 
 // ---------------------------------------------------------------------------
 
@@ -112,6 +115,8 @@
         getWeakRefs()->trackMe(enable, retain); 
     }
 
+    typedef RefBase basetype;
+
 protected:
                             RefBase();
     virtual                 ~RefBase();
@@ -135,6 +140,11 @@
     virtual void            onLastWeakRef(const void* id);
 
 private:
+    friend class ReferenceMover;
+    static void moveReferences(void* d, void const* s, size_t n,
+            const ReferenceConverterBase& caster);
+
+private:
     friend class weakref_type;
     class weakref_impl;
     
@@ -163,10 +173,17 @@
     inline int32_t getStrongCount() const {
         return mCount;
     }
-    
+
+    typedef LightRefBase<T> basetype;
+
 protected:
     inline ~LightRefBase() { }
-    
+
+private:
+    friend class ReferenceMover;
+    inline static void moveReferences(void* d, void const* s, size_t n,
+            const ReferenceConverterBase& caster) { }
+
 private:
     mutable volatile int32_t mCount;
 };
@@ -174,66 +191,6 @@
 // ---------------------------------------------------------------------------
 
 template <typename T>
-class sp
-{
-public:
-    typedef typename RefBase::weakref_type weakref_type;
-    
-    inline sp() : m_ptr(0) { }
-
-    sp(T* other);
-    sp(const sp<T>& other);
-    template<typename U> sp(U* other);
-    template<typename U> sp(const sp<U>& other);
-
-    ~sp();
-    
-    // Assignment
-
-    sp& operator = (T* other);
-    sp& operator = (const sp<T>& other);
-    
-    template<typename U> sp& operator = (const sp<U>& other);
-    template<typename U> sp& operator = (U* other);
-    
-    //! Special optimization for use by ProcessState (and nobody else).
-    void force_set(T* other);
-    
-    // Reset
-    
-    void clear();
-    
-    // Accessors
-
-    inline  T&      operator* () const  { return *m_ptr; }
-    inline  T*      operator-> () const { return m_ptr;  }
-    inline  T*      get() const         { return m_ptr; }
-
-    // Operators
-        
-    COMPARE(==)
-    COMPARE(!=)
-    COMPARE(>)
-    COMPARE(<)
-    COMPARE(<=)
-    COMPARE(>=)
-
-private:    
-    template<typename Y> friend class sp;
-    template<typename Y> friend class wp;
-
-    // Optimization for wp::promote().
-    sp(T* p, weakref_type* refs);
-    
-    T*              m_ptr;
-};
-
-template <typename T>
-TextOutput& operator<<(TextOutput& to, const sp<T>& val);
-
-// ---------------------------------------------------------------------------
-
-template <typename T>
 class wp
 {
 public:
@@ -326,114 +283,12 @@
 template <typename T>
 TextOutput& operator<<(TextOutput& to, const wp<T>& val);
 
-#undef COMPARE
 #undef COMPARE_WEAK
 
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
 
 template<typename T>
-sp<T>::sp(T* other)
-    : m_ptr(other)
-{
-    if (other) other->incStrong(this);
-}
-
-template<typename T>
-sp<T>::sp(const sp<T>& other)
-    : m_ptr(other.m_ptr)
-{
-    if (m_ptr) m_ptr->incStrong(this);
-}
-
-template<typename T> template<typename U>
-sp<T>::sp(U* other) : m_ptr(other)
-{
-    if (other) other->incStrong(this);
-}
-
-template<typename T> template<typename U>
-sp<T>::sp(const sp<U>& other)
-    : m_ptr(other.m_ptr)
-{
-    if (m_ptr) m_ptr->incStrong(this);
-}
-
-template<typename T>
-sp<T>::~sp()
-{
-    if (m_ptr) m_ptr->decStrong(this);
-}
-
-template<typename T>
-sp<T>& sp<T>::operator = (const sp<T>& other) {
-    T* otherPtr(other.m_ptr);
-    if (otherPtr) otherPtr->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = otherPtr;
-    return *this;
-}
-
-template<typename T>
-sp<T>& sp<T>::operator = (T* other)
-{
-    if (other) other->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = other;
-    return *this;
-}
-
-template<typename T> template<typename U>
-sp<T>& sp<T>::operator = (const sp<U>& other)
-{
-    U* otherPtr(other.m_ptr);
-    if (otherPtr) otherPtr->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = otherPtr;
-    return *this;
-}
-
-template<typename T> template<typename U>
-sp<T>& sp<T>::operator = (U* other)
-{
-    if (other) other->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = other;
-    return *this;
-}
-
-template<typename T>    
-void sp<T>::force_set(T* other)
-{
-    other->forceIncStrong(this);
-    m_ptr = other;
-}
-
-template<typename T>
-void sp<T>::clear()
-{
-    if (m_ptr) {
-        m_ptr->decStrong(this);
-        m_ptr = 0;
-    }
-}
-
-template<typename T>
-sp<T>::sp(T* p, weakref_type* refs)
-    : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0)
-{
-}
-
-template <typename T>
-inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
-{
-    to << "sp<>(" << val.get() << ")";
-    return to;
-}
-
-// ---------------------------------------------------------------------------
-
-template<typename T>
 wp<T>::wp(T* other)
     : m_ptr(other)
 {
@@ -570,7 +425,11 @@
 template<typename T>
 sp<T> wp<T>::promote() const
 {
-    return sp<T>(m_ptr, m_refs);
+    sp<T> result;
+    if (m_ptr && m_refs->attemptIncStrong(&result)) {
+        result.set_pointer(m_ptr);
+    }
+    return result;
 }
 
 template<typename T>
@@ -585,10 +444,80 @@
 template <typename T>
 inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
 {
-    to << "wp<>(" << val.unsafe_get() << ")";
-    return to;
+    return printWeakPointer(to, val.unsafe_get());
 }
 
+// ---------------------------------------------------------------------------
+
+// this class just serves as a namespace so TYPE::moveReferences can stay
+// private.
+
+class ReferenceMover {
+    // StrongReferenceCast and WeakReferenceCast do the impedance matching
+    // between the generic (void*) implementation in Refbase and the strongly typed
+    // template specializations below.
+
+    template <typename TYPE>
+    struct StrongReferenceCast : public ReferenceConverterBase {
+        virtual size_t getReferenceTypeSize() const { return sizeof( sp<TYPE> ); }
+        virtual void* getReferenceBase(void const* p) const {
+            sp<TYPE> const* sptr(reinterpret_cast<sp<TYPE> const*>(p));
+            return static_cast<typename TYPE::basetype *>(sptr->get());
+        }
+    };
+
+    template <typename TYPE>
+    struct WeakReferenceCast : public ReferenceConverterBase {
+        virtual size_t getReferenceTypeSize() const { return sizeof( wp<TYPE> ); }
+        virtual void* getReferenceBase(void const* p) const {
+            wp<TYPE> const* sptr(reinterpret_cast<wp<TYPE> const*>(p));
+            return static_cast<typename TYPE::basetype *>(sptr->unsafe_get());
+        }
+    };
+
+public:
+    template<typename TYPE> static inline
+    void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+        memmove(d, s, n*sizeof(sp<TYPE>));
+        StrongReferenceCast<TYPE> caster;
+        TYPE::moveReferences(d, s, n, caster);
+    }
+    template<typename TYPE> static inline
+    void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+        memmove(d, s, n*sizeof(wp<TYPE>));
+        WeakReferenceCast<TYPE> caster;
+        TYPE::moveReferences(d, s, n, caster);
+    }
+};
+
+// specialization for moving sp<> and wp<> types.
+// these are used by the [Sorted|Keyed]Vector<> implementations
+// sp<> and wp<> need to be handled specially, because they do not
+// have trivial copy operation in the general case (see RefBase.cpp
+// when DEBUG ops are enabled), but can be implemented very
+// efficiently in most cases.
+
+template<typename TYPE> inline
+void move_forward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_backward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_forward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+template<typename TYPE> inline
+void move_backward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+    ReferenceMover::move_references(d, s, n);
+}
+
+
 }; // namespace android
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index ed7f53d..6227f3e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1985,6 +1985,7 @@
 
 #ifndef HAVE_ANDROID_OS
     void print(bool inclValues) const;
+    static String8 normalizeForOutput(const char* input);
 #endif
 
 private:
diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h
new file mode 100644
index 0000000..49fa3a8
--- /dev/null
+++ b/include/utils/StrongPointer.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2005 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_STRONG_POINTER_H
+#define ANDROID_STRONG_POINTER_H
+
+#include <cutils/atomic.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class TextOutput;
+TextOutput& printStrongPointer(TextOutput& to, const void* val);
+
+template<typename T> class wp;
+
+// ---------------------------------------------------------------------------
+
+#define COMPARE(_op_)                                           \
+inline bool operator _op_ (const sp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+inline bool operator _op_ (const T* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const sp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const U* o) const {                  \
+    return m_ptr _op_ o;                                        \
+}                                                               \
+inline bool operator _op_ (const wp<T>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}                                                               \
+template<typename U>                                            \
+inline bool operator _op_ (const wp<U>& o) const {              \
+    return m_ptr _op_ o.m_ptr;                                  \
+}
+
+// ---------------------------------------------------------------------------
+
+template <typename T>
+class sp
+{
+public:
+    inline sp() : m_ptr(0) { }
+
+    sp(T* other);
+    sp(const sp<T>& other);
+    template<typename U> sp(U* other);
+    template<typename U> sp(const sp<U>& other);
+
+    ~sp();
+
+    // Assignment
+
+    sp& operator = (T* other);
+    sp& operator = (const sp<T>& other);
+
+    template<typename U> sp& operator = (const sp<U>& other);
+    template<typename U> sp& operator = (U* other);
+
+    //! Special optimization for use by ProcessState (and nobody else).
+    void force_set(T* other);
+
+    // Reset
+
+    void clear();
+
+    // Accessors
+
+    inline  T&      operator* () const  { return *m_ptr; }
+    inline  T*      operator-> () const { return m_ptr;  }
+    inline  T*      get() const         { return m_ptr; }
+
+    // Operators
+
+    COMPARE(==)
+    COMPARE(!=)
+    COMPARE(>)
+    COMPARE(<)
+    COMPARE(<=)
+    COMPARE(>=)
+
+private:    
+    template<typename Y> friend class sp;
+    template<typename Y> friend class wp;
+    void set_pointer(T* ptr);
+    T* m_ptr;
+};
+
+#undef COMPARE
+
+template <typename T>
+TextOutput& operator<<(TextOutput& to, const sp<T>& val);
+
+// ---------------------------------------------------------------------------
+// No user serviceable parts below here.
+
+template<typename T>
+sp<T>::sp(T* other)
+: m_ptr(other)
+  {
+    if (other) other->incStrong(this);
+  }
+
+template<typename T>
+sp<T>::sp(const sp<T>& other)
+: m_ptr(other.m_ptr)
+  {
+    if (m_ptr) m_ptr->incStrong(this);
+  }
+
+template<typename T> template<typename U>
+sp<T>::sp(U* other) : m_ptr(other)
+{
+    if (other) ((T*)other)->incStrong(this);
+}
+
+template<typename T> template<typename U>
+sp<T>::sp(const sp<U>& other)
+: m_ptr(other.m_ptr)
+  {
+    if (m_ptr) m_ptr->incStrong(this);
+  }
+
+template<typename T>
+sp<T>::~sp()
+{
+    if (m_ptr) m_ptr->decStrong(this);
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (const sp<T>& other) {
+    T* otherPtr(other.m_ptr);
+    if (otherPtr) otherPtr->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = otherPtr;
+    return *this;
+}
+
+template<typename T>
+sp<T>& sp<T>::operator = (T* other)
+{
+    if (other) other->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (const sp<U>& other)
+{
+    T* otherPtr(other.m_ptr);
+    if (otherPtr) otherPtr->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = otherPtr;
+    return *this;
+}
+
+template<typename T> template<typename U>
+sp<T>& sp<T>::operator = (U* other)
+{
+    if (other) ((T*)other)->incStrong(this);
+    if (m_ptr) m_ptr->decStrong(this);
+    m_ptr = other;
+    return *this;
+}
+
+template<typename T>    
+void sp<T>::force_set(T* other)
+{
+    other->forceIncStrong(this);
+    m_ptr = other;
+}
+
+template<typename T>
+void sp<T>::clear()
+{
+    if (m_ptr) {
+        m_ptr->decStrong(this);
+        m_ptr = 0;
+    }
+}
+
+template<typename T>
+void sp<T>::set_pointer(T* ptr) {
+    m_ptr = ptr;
+}
+
+template <typename T>
+inline TextOutput& operator<<(TextOutput& to, const sp<T>& val)
+{
+    return printStrongPointer(to, val.get());
+}
+
+}; // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_STRONG_POINTER_H
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index 2ff2749..a1663f3 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -37,18 +37,6 @@
 template <typename T> struct trait_pointer      { enum { value = false }; };    
 template <typename T> struct trait_pointer<T*>  { enum { value = true }; };
 
-// sp<> can be trivially moved
-template <typename T> class sp;
-template <typename T> struct trait_trivial_move< sp<T> >{
-    enum { value = true }; 
-};
-
-// wp<> can be trivially moved
-template <typename T> class wp;
-template <typename T> struct trait_trivial_move< wp<T> >{ 
-    enum { value = true }; 
-};
-
 template <typename TYPE>
 struct traits {
     enum {
@@ -217,7 +205,6 @@
     }
 }
 
-
 // ---------------------------------------------------------------------------
 
 /*
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 1bcfaed..41e5766 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -527,9 +527,10 @@
     static  int             _threadLoop(void* user);
     const   bool            mCanCallJava;
             thread_id_t     mThread;
-            Mutex           mLock;
+    mutable Mutex           mLock;
             Condition       mThreadExitedCondition;
             status_t        mStatus;
+    // note that all accesses of mExitPending and mRunning need to hold mLock
     volatile bool           mExitPending;
     volatile bool           mRunning;
             sp<Thread>      mHoldSelf;
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 624f7eb..9f501e2 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -31,7 +31,7 @@
 
 #include <binder/MemoryHeapBase.h>
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
 #include <linux/android_pmem.h>
 #endif
 
@@ -108,7 +108,7 @@
 {
     if (size == 0) {
         // try to figure out the size automatically
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
         // first try the PMEM ioctl
         pmem_region reg;
         int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, &reg);
diff --git a/libs/binder/MemoryHeapPmem.cpp b/libs/binder/MemoryHeapPmem.cpp
index 16e92f9..03322ea 100644
--- a/libs/binder/MemoryHeapPmem.cpp
+++ b/libs/binder/MemoryHeapPmem.cpp
@@ -30,7 +30,7 @@
 #include <binder/MemoryHeapPmem.h>
 #include <binder/MemoryHeapBase.h>
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
 #include <linux/android_pmem.h>
 #endif
 
@@ -72,7 +72,7 @@
     memset(start_ptr, 0xda, size);
 #endif
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     if (size > 0) {
         const size_t pagesize = getpagesize();
         size = (size + pagesize-1) & ~(pagesize-1);
@@ -107,7 +107,7 @@
     // which means MemoryHeapPmem::revoke() wouldn't have been able to 
     // promote() it.
     
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     if (mSize != 0) {
         const sp<MemoryHeapPmem>& heap(getHeap());
         int our_fd = heap->heapID();
@@ -130,7 +130,7 @@
     : MemoryHeapBase()
 {
     char const * const device = pmemHeap->getDevice();
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     if (device) {
         int fd = open(device, O_RDWR | (flags & NO_CACHING ? O_SYNC : 0));
         LOGE_IF(fd<0, "couldn't open %s (%s)", device, strerror(errno));
@@ -187,7 +187,7 @@
 
 status_t MemoryHeapPmem::slap()
 {
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     size_t size = getSize();
     const size_t pagesize = getpagesize();
     size = (size + pagesize-1) & ~(pagesize-1);
@@ -205,7 +205,7 @@
 
 status_t MemoryHeapPmem::unslap()
 {
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     size_t size = getSize();
     const size_t pagesize = getpagesize();
     size = (size + pagesize-1) & ~(pagesize-1);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index d6cc8ce..3bed959 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -96,6 +96,11 @@
 
 status_t SurfaceTexture::setBufferCount(int bufferCount) {
     LOGV("SurfaceTexture::setBufferCount");
+
+    if (bufferCount < MIN_BUFFER_SLOTS) {
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock lock(mMutex);
     freeAllBuffers();
     mBufferCount = bufferCount;
@@ -220,11 +225,19 @@
             mSlots[mLastQueued].mEglImage = image;
             mSlots[mLastQueued].mEglDisplay = dpy;
         }
+
+        GLint error;
+        while ((error = glGetError()) != GL_NO_ERROR) {
+            LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
+        }
         glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
-        GLint error = glGetError();
-        if (error != GL_NO_ERROR) {
+        bool failed = false;
+        while ((error = glGetError()) != GL_NO_ERROR) {
             LOGE("error binding external texture image %p (slot %d): %#04x",
                     image, mLastQueued, error);
+            failed = true;
+        }
+        if (failed) {
             return -EINVAL;
         }
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index ee14ac9..a40fac9 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -143,8 +143,25 @@
 int SurfaceTextureClient::query(int what, int* value) {
     LOGV("SurfaceTextureClient::query");
     Mutex::Autolock lock(mMutex);
-    // XXX: Implement this!
-    return INVALID_OPERATION;
+    switch (what) {
+    case NATIVE_WINDOW_WIDTH:
+    case NATIVE_WINDOW_HEIGHT:
+        // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
+        // override the size?
+        *value = 0;
+        return NO_ERROR;
+    case NATIVE_WINDOW_FORMAT:
+        *value = DEFAULT_FORMAT;
+        return NO_ERROR;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        *value = MIN_UNDEQUEUED_BUFFERS;
+        return NO_ERROR;
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        // SurfaceTextureClient currently never queues frames to SurfaceFlinger.
+        *value = 0;
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
 }
 
 int SurfaceTextureClient::perform(int operation, va_list args)
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
new file mode 100644
index 0000000..1dd8885
--- /dev/null
+++ b/libs/gui/tests/Android.mk
@@ -0,0 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+    SurfaceTextureClient_test.cpp \
+
+shared_libraries := \
+	libcutils \
+	libutils \
+	libbinder \
+	libgui \
+	libstlport \
+
+static_libraries := \
+	libgtest \
+	libgtest_main \
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
new file mode 100644
index 0000000..0f140ff
--- /dev/null
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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 <gui/SurfaceTextureClient.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+class SurfaceTextureClientTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mST = new SurfaceTexture(123);
+        mSTC = new SurfaceTextureClient(mST);
+    }
+
+    virtual void TearDown() {
+        mST.clear();
+        mSTC.clear();
+    }
+
+    sp<SurfaceTexture> mST;
+    sp<SurfaceTextureClient> mSTC;
+};
+
+TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
+    sp<ANativeWindow> anw(mSTC);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(0, result);
+}
+
+}
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 01ae23f..8951c3f 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -25,9 +25,11 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
+#include <surfaceflinger/ISurfaceComposer.h>
+
 #include <ui/DisplayInfo.h>
 
-#include <surfaceflinger/ISurfaceComposer.h>
+#include <utils/Log.h>
 
 // ---------------------------------------------------------------------------
 
@@ -178,6 +180,40 @@
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual bool authenticateSurface(const sp<ISurface>& surface) const
+    {
+        Parcel data, reply;
+        int err = NO_ERROR;
+        err = data.writeInterfaceToken(
+                ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error writing "
+                    "interface descriptor: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        err = data.writeStrongBinder(surface->asBinder());
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error writing strong "
+                    "binder to parcel: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data,
+                &reply);
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error performing "
+                    "transaction: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error retrieving "
+                    "result: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        return result != 0;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -273,6 +309,12 @@
             status_t res = turnElectronBeamOn(mode);
             reply->writeInt32(res);
         } break;
+        case AUTHENTICATE_SURFACE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            int32_t result = authenticateSurface(surface) ? 1 : 0;
+            reply->writeInt32(result);
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
index 2cc1f8e..7730eb1 100644
--- a/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposerClient.cpp
@@ -157,7 +157,7 @@
      const int pid = ipc->getCallingPid();
      const int uid = ipc->getCallingUid();
      const int self_pid = getpid();
-     if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS)) {
+     if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
          // we're called from a different process, do the real check
          if (!checkCallingPermission(
                  String16("android.permission.ACCESS_SURFACE_FLINGER")))
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 1e9bd74..afabbf4 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -709,6 +709,13 @@
     case NATIVE_WINDOW_FORMAT:
         *value = int(mFormat);
         return NO_ERROR;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        *value = MIN_UNDEQUEUED_BUFFERS;
+        return NO_ERROR;
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        *value = sf->authenticateSurface(mSurface) ? 1 : 0;
+        return NO_ERROR;
     }
     return BAD_VALUE;
 }
@@ -1040,7 +1047,7 @@
         // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
         // was dequeued from an ANativeWindow.
         for (size_t i = 0; i < mBuffers.size(); i++) {
-            if (buffer->handle == mBuffers[i]->handle) {
+            if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
                 idx = mBuffers[i]->getIndex();
                 break;
             }
diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk
index 5053e7d..212b8e7 100644
--- a/libs/surfaceflinger_client/tests/Android.mk
+++ b/libs/surfaceflinger_client/tests/Android.mk
@@ -1 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+    Surface_test.cpp \
+
+shared_libraries := \
+	libcutils \
+	libutils \
+	libbinder \
+	libsurfaceflinger_client \
+	libstlport \
+
+static_libraries := \
+	libgtest \
+	libgtest_main \
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
 include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/surfaceflinger_client/tests/Surface_test.cpp
new file mode 100644
index 0000000..74ebf4e
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/Surface_test.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011 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 <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class SurfaceTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        mSurfaceControl = mComposerClient->createSurface(getpid(),
+                String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0);
+
+        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl->isValid());
+
+        ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+        ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+
+        mSurface = mSurfaceControl->getSurface();
+        ASSERT_TRUE(mSurface != NULL);
+    }
+
+    virtual void TearDown() {
+        mComposerClient->dispose();
+    }
+
+    sp<Surface> mSurface;
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mSurfaceControl;
+};
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
+    mSurfaceControl.clear();
+
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
+// This test probably doesn't belong here.
+TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) {
+    sp<ANativeWindow> anw(mSurface);
+
+    // Verify the screenshot works with no protected buffers.
+    sp<IMemoryHeap> heap;
+    uint32_t w=0, h=0;
+    PixelFormat fmt=0;
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+            40000));
+    ASSERT_TRUE(heap != NULL);
+
+    // Set the PROTECTED usage bit and verify that the screenshot fails.  Note
+    // that we need to dequeue a buffer in order for it to actually get
+    // allocated in SurfaceFlinger.
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
+            GRALLOC_USAGE_PROTECTED));
+    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+    android_native_buffer_t* buf = 0;
+    for (int i = 0; i < 4; i++) {
+        // Loop to make sure SurfaceFlinger has retired a protected buffer.
+        ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+        ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+        ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+    }
+    heap = 0;
+    w = h = fmt = 0;
+    ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt,
+            64, 64, 0, 40000));
+    ASSERT_TRUE(heap == NULL);
+
+    // XXX: This should not be needed, but it seems that the new buffers don't
+    // correctly show up after the upcoming dequeue/lock/queue loop without it.
+    // We should look into this at some point.
+    ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+
+    // Un-set the PROTECTED usage bit and verify that the screenshot works
+    // again.  Note that we have to change the buffers geometry to ensure that
+    // the buffers get reallocated, as the new usage bits are a subset of the
+    // old.
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(anw.get(), 32, 32, 0));
+    for (int i = 0; i < 4; i++) {
+        // Loop to make sure SurfaceFlinger has retired a protected buffer.
+        ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+        ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+        ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+    }
+    heap = 0;
+    w = h = fmt = 0;
+    ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+            40000));
+    ASSERT_TRUE(heap != NULL);
+}
+
+}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 0d55f08..f9990bb 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -60,7 +60,12 @@
 	libEGL \
 	libpixelflinger \
 	libhardware \
-	libhardware_legacy
+	libhardware_legacy \
+	libskia \
+	libbinder
+
+LOCAL_C_INCLUDES := \
+    external/skia/include/core
 
 LOCAL_MODULE:= libui
 
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index b8d59e6..e2e698e 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -15,6 +15,16 @@
 
 #include <ui/Input.h>
 
+#include <math.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <binder/Parcel.h>
+
+#include "SkPoint.h"
+#include "SkMatrix.h"
+#include "SkScalar.h"
+#endif
+
 namespace android {
 
 static const char* CONFIGURATION_FILE_DIR[] = {
@@ -237,6 +247,89 @@
     mEventTime = from.mEventTime;
 }
 
+
+// --- PointerCoords ---
+
+float PointerCoords::getAxisValue(int32_t axis) const {
+    if (axis < 0 || axis > 63) {
+        return 0;
+    }
+
+    uint64_t axisBit = 1LL << axis;
+    if (!(bits & axisBit)) {
+        return 0;
+    }
+    uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
+    return values[index];
+}
+
+status_t PointerCoords::setAxisValue(int32_t axis, float value) {
+    if (axis < 0 || axis > 63) {
+        return NAME_NOT_FOUND;
+    }
+
+    uint64_t axisBit = 1LL << axis;
+    uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
+    if (!(bits & axisBit)) {
+        uint32_t count = __builtin_popcountll(bits);
+        if (count >= MAX_AXES) {
+            tooManyAxes(axis);
+            return NO_MEMORY;
+        }
+        bits |= axisBit;
+        for (uint32_t i = count; i > index; i--) {
+            values[i] = values[i - 1];
+        }
+    }
+    values[index] = value;
+    return OK;
+}
+
+float* PointerCoords::editAxisValue(int32_t axis) {
+    if (axis < 0 || axis > 63) {
+        return NULL;
+    }
+
+    uint64_t axisBit = 1LL << axis;
+    if (!(bits & axisBit)) {
+        return NULL;
+    }
+    uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
+    return &values[index];
+}
+
+#ifdef HAVE_ANDROID_OS
+status_t PointerCoords::readFromParcel(Parcel* parcel) {
+    bits = parcel->readInt64();
+
+    uint32_t count = __builtin_popcountll(bits);
+    if (count > MAX_AXES) {
+        return BAD_VALUE;
+    }
+
+    for (uint32_t i = 0; i < count; i++) {
+        values[i] = parcel->readInt32();
+    }
+    return OK;
+}
+
+status_t PointerCoords::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt64(bits);
+
+    uint32_t count = __builtin_popcountll(bits);
+    for (uint32_t i = 0; i < count; i++) {
+        parcel->writeInt32(values[i]);
+    }
+    return OK;
+}
+#endif
+
+void PointerCoords::tooManyAxes(int axis) {
+    LOGW("Could not set value for axis %d because the PointerCoords structure is full and "
+            "cannot contain more than %d axis values.", axis, int(MAX_AXES));
+}
+
+
 // --- MotionEvent ---
 
 void MotionEvent::initialize(
@@ -272,6 +365,33 @@
     addSample(eventTime, pointerCoords);
 }
 
+void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
+    InputEvent::initialize(other->mDeviceId, other->mSource);
+    mAction = other->mAction;
+    mFlags = other->mFlags;
+    mEdgeFlags = other->mEdgeFlags;
+    mMetaState = other->mMetaState;
+    mXOffset = other->mXOffset;
+    mYOffset = other->mYOffset;
+    mXPrecision = other->mXPrecision;
+    mYPrecision = other->mYPrecision;
+    mDownTime = other->mDownTime;
+    mPointerIds = other->mPointerIds;
+
+    if (keepHistory) {
+        mSampleEventTimes = other->mSampleEventTimes;
+        mSamplePointerCoords = other->mSamplePointerCoords;
+    } else {
+        mSampleEventTimes.clear();
+        mSampleEventTimes.push(other->getEventTime());
+        mSamplePointerCoords.clear();
+        size_t pointerCount = other->getPointerCount();
+        size_t historySize = other->getHistorySize();
+        mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
+                + (historySize * pointerCount), pointerCount);
+    }
+}
+
 void MotionEvent::addSample(
         int64_t eventTime,
         const PointerCoords* pointerCoords) {
@@ -279,11 +399,241 @@
     mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
 }
 
+const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
+    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
+}
+
+float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
+    return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+}
+
+float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
+    float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+    switch (axis) {
+    case AMOTION_EVENT_AXIS_X:
+        value += mXOffset;
+        break;
+    case AMOTION_EVENT_AXIS_Y:
+        value += mYOffset;
+        break;
+    }
+    return value;
+}
+
+const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
+        size_t pointerIndex, size_t historicalIndex) const {
+    return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
+}
+
+float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
+        size_t historicalIndex) const {
+    return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+}
+
+float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
+        size_t historicalIndex) const {
+    float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+    switch (axis) {
+    case AMOTION_EVENT_AXIS_X:
+        value += mXOffset;
+        break;
+    case AMOTION_EVENT_AXIS_Y:
+        value += mYOffset;
+        break;
+    }
+    return value;
+}
+
 void MotionEvent::offsetLocation(float xOffset, float yOffset) {
     mXOffset += xOffset;
     mYOffset += yOffset;
 }
 
+static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
+    float* value = c.editAxisValue(axis);
+    if (value) {
+        *value *= scaleFactor;
+    }
+}
+
+void MotionEvent::scale(float scaleFactor) {
+    mXOffset *= scaleFactor;
+    mYOffset *= scaleFactor;
+    mXPrecision *= scaleFactor;
+    mYPrecision *= scaleFactor;
+
+    size_t numSamples = mSamplePointerCoords.size();
+    for (size_t i = 0; i < numSamples; i++) {
+        PointerCoords& c = mSamplePointerCoords.editItemAt(i);
+        // No need to scale pressure or size since they are normalized.
+        // No need to scale orientation since it is meaningless to do so.
+        scaleAxisValue(c, AMOTION_EVENT_AXIS_X, scaleFactor);
+        scaleAxisValue(c, AMOTION_EVENT_AXIS_Y, scaleFactor);
+        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor);
+        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor);
+        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor);
+        scaleAxisValue(c, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor);
+    }
+}
+
+#ifdef HAVE_ANDROID_OS
+static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
+    // Construct and transform a vector oriented at the specified clockwise angle from vertical.
+    // Coordinate system: down is increasing Y, right is increasing X.
+    SkPoint vector;
+    vector.fX = SkFloatToScalar(sinf(angleRadians));
+    vector.fY = SkFloatToScalar(-cosf(angleRadians));
+    matrix->mapVectors(& vector, 1);
+
+    // Derive the transformed vector's clockwise angle from vertical.
+    float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
+    if (result < - M_PI_2) {
+        result += M_PI;
+    } else if (result > M_PI_2) {
+        result -= M_PI;
+    }
+    return result;
+}
+
+void MotionEvent::transform(const SkMatrix* matrix) {
+    float oldXOffset = mXOffset;
+    float oldYOffset = mYOffset;
+
+    // The tricky part of this implementation is to preserve the value of
+    // rawX and rawY.  So we apply the transformation to the first point
+    // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
+    SkPoint point;
+    float rawX = getRawX(0);
+    float rawY = getRawY(0);
+    matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
+            & point);
+    float newX = SkScalarToFloat(point.fX);
+    float newY = SkScalarToFloat(point.fY);
+    float newXOffset = newX - rawX;
+    float newYOffset = newY - rawY;
+
+    mXOffset = newXOffset;
+    mYOffset = newYOffset;
+
+    // Apply the transformation to all samples.
+    size_t numSamples = mSamplePointerCoords.size();
+    for (size_t i = 0; i < numSamples; i++) {
+        PointerCoords& c = mSamplePointerCoords.editItemAt(i);
+        float* xPtr = c.editAxisValue(AMOTION_EVENT_AXIS_X);
+        float* yPtr = c.editAxisValue(AMOTION_EVENT_AXIS_Y);
+        if (xPtr && yPtr) {
+            float x = *xPtr + oldXOffset;
+            float y = *yPtr + oldYOffset;
+            matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point);
+            *xPtr = SkScalarToFloat(point.fX) - newXOffset;
+            *yPtr = SkScalarToFloat(point.fY) - newYOffset;
+        }
+
+        float* orientationPtr = c.editAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+        if (orientationPtr) {
+            *orientationPtr = transformAngle(matrix, *orientationPtr);
+        }
+    }
+}
+
+status_t MotionEvent::readFromParcel(Parcel* parcel) {
+    size_t pointerCount = parcel->readInt32();
+    size_t sampleCount = parcel->readInt32();
+    if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
+        return BAD_VALUE;
+    }
+
+    mDeviceId = parcel->readInt32();
+    mSource = parcel->readInt32();
+    mAction = parcel->readInt32();
+    mFlags = parcel->readInt32();
+    mEdgeFlags = parcel->readInt32();
+    mMetaState = parcel->readInt32();
+    mXOffset = parcel->readFloat();
+    mYOffset = parcel->readFloat();
+    mXPrecision = parcel->readFloat();
+    mYPrecision = parcel->readFloat();
+    mDownTime = parcel->readInt64();
+
+    mPointerIds.clear();
+    mPointerIds.setCapacity(pointerCount);
+    mSampleEventTimes.clear();
+    mSampleEventTimes.setCapacity(sampleCount);
+    mSamplePointerCoords.clear();
+    mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
+
+    for (size_t i = 0; i < pointerCount; i++) {
+        mPointerIds.push(parcel->readInt32());
+    }
+
+    while (sampleCount-- > 0) {
+        mSampleEventTimes.push(parcel->readInt64());
+        for (size_t i = 0; i < pointerCount; i++) {
+            mSamplePointerCoords.push();
+            status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
+            if (status) {
+                return status;
+            }
+        }
+    }
+    return OK;
+}
+
+status_t MotionEvent::writeToParcel(Parcel* parcel) const {
+    size_t pointerCount = mPointerIds.size();
+    size_t sampleCount = mSampleEventTimes.size();
+
+    parcel->writeInt32(pointerCount);
+    parcel->writeInt32(sampleCount);
+
+    parcel->writeInt32(mDeviceId);
+    parcel->writeInt32(mSource);
+    parcel->writeInt32(mAction);
+    parcel->writeInt32(mFlags);
+    parcel->writeInt32(mEdgeFlags);
+    parcel->writeInt32(mMetaState);
+    parcel->writeFloat(mXOffset);
+    parcel->writeFloat(mYOffset);
+    parcel->writeFloat(mXPrecision);
+    parcel->writeFloat(mYPrecision);
+    parcel->writeInt64(mDownTime);
+
+    for (size_t i = 0; i < pointerCount; i++) {
+        parcel->writeInt32(mPointerIds.itemAt(i));
+    }
+
+    const PointerCoords* pc = mSamplePointerCoords.array();
+    for (size_t h = 0; h < sampleCount; h++) {
+        parcel->writeInt64(mSampleEventTimes.itemAt(h));
+        for (size_t i = 0; i < pointerCount; i++) {
+            status_t status = (pc++)->writeToParcel(parcel);
+            if (status) {
+                return status;
+            }
+        }
+    }
+    return OK;
+}
+#endif
+
+bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
+    if (source & AINPUT_SOURCE_CLASS_POINTER) {
+        // Specifically excludes HOVER_MOVE and SCROLL.
+        switch (action & AMOTION_EVENT_ACTION_MASK) {
+        case AMOTION_EVENT_ACTION_DOWN:
+        case AMOTION_EVENT_ACTION_MOVE:
+        case AMOTION_EVENT_ACTION_UP:
+        case AMOTION_EVENT_ACTION_POINTER_DOWN:
+        case AMOTION_EVENT_ACTION_POINTER_UP:
+        case AMOTION_EVENT_ACTION_CANCEL:
+        case AMOTION_EVENT_ACTION_OUTSIDE:
+            return true;
+        }
+    }
+    return false;
+}
+
+
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
@@ -307,23 +657,30 @@
     mMotionRanges.clear();
 }
 
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t rangeType) const {
-    ssize_t index = mMotionRanges.indexOfKey(rangeType);
-    return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
+        int32_t axis, uint32_t source) const {
+    size_t numRanges = mMotionRanges.size();
+    for (size_t i = 0; i < numRanges; i++) {
+        const MotionRange& range = mMotionRanges.itemAt(i);
+        if (range.axis == axis && range.source == source) {
+            return &range;
+        }
+    }
+    return NULL;
 }
 
 void InputDeviceInfo::addSource(uint32_t source) {
     mSources |= source;
 }
 
-void InputDeviceInfo::addMotionRange(int32_t rangeType, float min, float max,
+void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
         float flat, float fuzz) {
-    MotionRange range = { min, max, flat, fuzz };
-    addMotionRange(rangeType, range);
+    MotionRange range = { axis, source, min, max, flat, fuzz };
+    mMotionRanges.add(range);
 }
 
-void InputDeviceInfo::addMotionRange(int32_t rangeType, const MotionRange& range) {
-    mMotionRanges.add(rangeType, range);
+void InputDeviceInfo::addMotionRange(const MotionRange& range) {
+    mMotionRanges.add(range);
 }
 
 } // namespace android
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 83d9556..5c57a76 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -412,7 +412,8 @@
     // Cache essential information about the motion event to ensure that a malicious consumer
     // cannot confuse the publisher by modifying the contents of the shared memory buffer while
     // it is being updated.
-    if (action == AMOTION_EVENT_ACTION_MOVE) {
+    if (action == AMOTION_EVENT_ACTION_MOVE
+            || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
         mMotionEventPointerCount = pointerCount;
         mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
         mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp
index 56bc26f..8626a03 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/ui/KeyLayoutMap.cpp
@@ -82,11 +82,11 @@
     return status;
 }
 
-status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
+status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const {
     ssize_t index = mKeys.indexOfKey(scanCode);
     if (index < 0) {
 #if DEBUG_MAPPING
-        LOGD("map: scanCode=%d ~ Failed.", scanCode);
+        LOGD("mapKey: scanCode=%d ~ Failed.", scanCode);
 #endif
         *keyCode = AKEYCODE_UNKNOWN;
         *flags = 0;
@@ -98,12 +98,12 @@
     *flags = k.flags;
 
 #if DEBUG_MAPPING
-    LOGD("map: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
+    LOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags);
 #endif
     return NO_ERROR;
 }
 
-status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
+status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
     const size_t N = mKeys.size();
     for (size_t i=0; i<N; i++) {
         if (mKeys.valueAt(i).keyCode == keyCode) {
@@ -113,6 +113,28 @@
     return NO_ERROR;
 }
 
+status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
+    ssize_t index = mAxes.indexOfKey(scanCode);
+    if (index < 0) {
+#if DEBUG_MAPPING
+        LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
+#endif
+        return NAME_NOT_FOUND;
+    }
+
+    *outAxisInfo = mAxes.valueAt(index);
+
+#if DEBUG_MAPPING
+    LOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
+            "splitValue=%d, flatOverride=%d.",
+            scanCode,
+            outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
+            outAxisInfo->splitValue, outAxisInfo->flatOverride);
+#endif
+    return NO_ERROR;
+}
+
+
 // --- KeyLayoutMap::Parser ---
 
 KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) :
@@ -137,6 +159,10 @@
                 mTokenizer->skipDelimiters(WHITESPACE);
                 status_t status = parseKey();
                 if (status) return status;
+            } else if (keywordToken == "axis") {
+                mTokenizer->skipDelimiters(WHITESPACE);
+                status_t status = parseAxis();
+                if (status) return status;
             } else {
                 LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
                         keywordToken.string());
@@ -162,12 +188,12 @@
     char* end;
     int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
     if (*end) {
-        LOGE("%s: Expected scan code number, got '%s'.", mTokenizer->getLocation().string(),
+        LOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
                 scanCodeToken.string());
         return BAD_VALUE;
     }
     if (mMap->mKeys.indexOfKey(scanCode) >= 0) {
-        LOGE("%s: Duplicate entry for scan code '%s'.", mTokenizer->getLocation().string(),
+        LOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
                 scanCodeToken.string());
         return BAD_VALUE;
     }
@@ -189,12 +215,12 @@
         String8 flagToken = mTokenizer->nextToken(WHITESPACE);
         uint32_t flag = getKeyFlagByLabel(flagToken.string());
         if (!flag) {
-            LOGE("%s: Expected flag label, got '%s'.", mTokenizer->getLocation().string(),
+            LOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
                     flagToken.string());
             return BAD_VALUE;
         }
         if (flags & flag) {
-            LOGE("%s: Duplicate flag '%s'.", mTokenizer->getLocation().string(),
+            LOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
                     flagToken.string());
             return BAD_VALUE;
         }
@@ -211,4 +237,105 @@
     return NO_ERROR;
 }
 
+status_t KeyLayoutMap::Parser::parseAxis() {
+    String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
+    char* end;
+    int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+    if (*end) {
+        LOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(),
+                scanCodeToken.string());
+        return BAD_VALUE;
+    }
+    if (mMap->mAxes.indexOfKey(scanCode) >= 0) {
+        LOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(),
+                scanCodeToken.string());
+        return BAD_VALUE;
+    }
+
+    AxisInfo axisInfo;
+
+    mTokenizer->skipDelimiters(WHITESPACE);
+    String8 token = mTokenizer->nextToken(WHITESPACE);
+    if (token == "invert") {
+        axisInfo.mode = AxisInfo::MODE_INVERT;
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 axisToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.axis = getAxisByLabel(axisToken.string());
+        if (axisInfo.axis < 0) {
+            LOGE("%s: Expected inverted axis label, got '%s'.",
+                    mTokenizer->getLocation().string(), axisToken.string());
+            return BAD_VALUE;
+        }
+    } else if (token == "split") {
+        axisInfo.mode = AxisInfo::MODE_SPLIT;
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 splitToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
+        if (*end) {
+            LOGE("%s: Expected split value, got '%s'.",
+                    mTokenizer->getLocation().string(), splitToken.string());
+            return BAD_VALUE;
+        }
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.axis = getAxisByLabel(lowAxisToken.string());
+        if (axisInfo.axis < 0) {
+            LOGE("%s: Expected low axis label, got '%s'.",
+                    mTokenizer->getLocation().string(), lowAxisToken.string());
+            return BAD_VALUE;
+        }
+
+        mTokenizer->skipDelimiters(WHITESPACE);
+        String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
+        axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
+        if (axisInfo.highAxis < 0) {
+            LOGE("%s: Expected high axis label, got '%s'.",
+                    mTokenizer->getLocation().string(), highAxisToken.string());
+            return BAD_VALUE;
+        }
+    } else {
+        axisInfo.axis = getAxisByLabel(token.string());
+        if (axisInfo.axis < 0) {
+            LOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
+                    mTokenizer->getLocation().string(), token.string());
+            return BAD_VALUE;
+        }
+    }
+
+    for (;;) {
+        mTokenizer->skipDelimiters(WHITESPACE);
+        if (mTokenizer->isEol()) {
+            break;
+        }
+        String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+        if (keywordToken == "flat") {
+            mTokenizer->skipDelimiters(WHITESPACE);
+            String8 flatToken = mTokenizer->nextToken(WHITESPACE);
+            axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
+            if (*end) {
+                LOGE("%s: Expected flat value, got '%s'.",
+                        mTokenizer->getLocation().string(), flatToken.string());
+                return BAD_VALUE;
+            }
+        } else {
+            LOGE("%s: Expected keyword 'flat', got '%s'.",
+                    mTokenizer->getLocation().string(), keywordToken.string());
+            return BAD_VALUE;
+        }
+    }
+
+#if DEBUG_PARSER
+    LOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
+            "splitValue=%d, flatOverride=%d.",
+            scanCode,
+            axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
+            axisInfo.splitValue, axisInfo.flatOverride);
+#endif
+    mMap->mAxes.add(scanCode, axisInfo);
+    return NO_ERROR;
+}
+
 };
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index 6faa600..600a951 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -217,7 +217,7 @@
     return NAME_NOT_FOUND;
 }
 
-static int lookupLabel(const char* literal, const KeycodeLabel *list) {
+static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
     while (list->literal) {
         if (strcmp(literal, list->literal) == 0) {
             return list->value;
@@ -227,12 +227,30 @@
     return list->value;
 }
 
+static const char* lookupLabelByValue(int value, const KeycodeLabel *list) {
+    while (list->literal) {
+        if (list->value == value) {
+            return list->literal;
+        }
+        list++;
+    }
+    return NULL;
+}
+
 int32_t getKeyCodeByLabel(const char* label) {
-    return int32_t(lookupLabel(label, KEYCODES));
+    return int32_t(lookupValueByLabel(label, KEYCODES));
 }
 
 uint32_t getKeyFlagByLabel(const char* label) {
-    return uint32_t(lookupLabel(label, FLAGS));
+    return uint32_t(lookupValueByLabel(label, FLAGS));
+}
+
+int32_t getAxisByLabel(const char* label) {
+    return int32_t(lookupValueByLabel(label, AXES));
+}
+
+const char* getAxisLabel(int32_t axisId) {
+    return lookupLabelByValue(axisId, AXES);
 }
 
 static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
@@ -304,5 +322,26 @@
     }
 }
 
+bool isMetaKey(int32_t keyCode) {
+    switch (keyCode) {
+    case AKEYCODE_ALT_LEFT:
+    case AKEYCODE_ALT_RIGHT:
+    case AKEYCODE_SHIFT_LEFT:
+    case AKEYCODE_SHIFT_RIGHT:
+    case AKEYCODE_SYM:
+    case AKEYCODE_FUNCTION:
+    case AKEYCODE_CTRL_LEFT:
+    case AKEYCODE_CTRL_RIGHT:
+    case AKEYCODE_META_LEFT:
+    case AKEYCODE_META_RIGHT:
+    case AKEYCODE_CAPS_LOCK:
+    case AKEYCODE_NUM_LOCK:
+    case AKEYCODE_SCROLL_LOCK:
+        return true;
+    default:
+        return false;
+    }
+}
+
 
 } // namespace android
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 580d73c..e231971 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -7,6 +7,7 @@
 # Build the unit tests.
 test_src_files := \
     InputChannel_test.cpp \
+    InputEvent_test.cpp \
     InputPublisherAndConsumer_test.cpp
 
 shared_libraries := \
@@ -18,7 +19,8 @@
 	libhardware \
 	libhardware_legacy \
 	libui \
-	libstlport
+	libstlport \
+	libskia
 
 static_libraries := \
 	libgtest \
@@ -28,7 +30,8 @@
     bionic \
     bionic/libstdc++/include \
     external/gtest/include \
-    external/stlport/stlport
+    external/stlport/stlport \
+    external/skia/include/core
 
 module_tags := eng tests
 
diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp
index 6cec1c0..eff22ee 100644
--- a/libs/ui/tests/InputChannel_test.cpp
+++ b/libs/ui/tests/InputChannel_test.cpp
@@ -1,6 +1,18 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
+/*
+ * 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 <ui/InputTransport.h>
 #include <utils/Timers.h>
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
new file mode 100644
index 0000000..b77489e
--- /dev/null
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2011 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 <ui/Input.h>
+#include <gtest/gtest.h>
+#include <binder/Parcel.h>
+
+#include <math.h>
+#include <SkMatrix.h>
+
+namespace android {
+
+class BaseTest : public testing::Test {
+protected:
+    virtual void SetUp() { }
+    virtual void TearDown() { }
+};
+
+// --- PointerCoordsTest ---
+
+class PointerCoordsTest : public BaseTest {
+};
+
+TEST_F(PointerCoordsTest, ClearSetsBitsToZero) {
+    PointerCoords coords;
+    coords.clear();
+
+    ASSERT_EQ(0ULL, coords.bits);
+}
+
+TEST_F(PointerCoordsTest, AxisValues) {
+    float* valuePtr;
+    PointerCoords coords;
+    coords.clear();
+
+    // Check invariants when no axes are present.
+    ASSERT_EQ(0, coords.getAxisValue(0))
+            << "getAxisValue should return zero because axis is not present";
+    ASSERT_EQ(0, coords.getAxisValue(1))
+            << "getAxisValue should return zero because axis is not present";
+
+    ASSERT_EQ(NULL, coords.editAxisValue(0))
+            << "editAxisValue should return null because axis is not present";
+
+    // Set first axis.
+    ASSERT_EQ(OK, coords.setAxisValue(1, 5));
+    ASSERT_EQ(0x00000002ULL, coords.bits);
+    ASSERT_EQ(5, coords.values[0]);
+
+    ASSERT_EQ(0, coords.getAxisValue(0))
+            << "getAxisValue should return zero because axis is not present";
+    ASSERT_EQ(5, coords.getAxisValue(1))
+            << "getAxisValue should return value of axis";
+
+    // Set an axis with a higher id than all others.  (appending value at the end)
+    ASSERT_EQ(OK, coords.setAxisValue(3, 2));
+    ASSERT_EQ(0x0000000aULL, coords.bits);
+    ASSERT_EQ(5, coords.values[0]);
+    ASSERT_EQ(2, coords.values[1]);
+
+    ASSERT_EQ(0, coords.getAxisValue(0))
+            << "getAxisValue should return zero because axis is not present";
+    ASSERT_EQ(5, coords.getAxisValue(1))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(0, coords.getAxisValue(2))
+            << "getAxisValue should return zero because axis is not present";
+    ASSERT_EQ(2, coords.getAxisValue(3))
+            << "getAxisValue should return value of axis";
+
+    // Set an axis with an id lower than all others.  (prepending value at beginning)
+    ASSERT_EQ(OK, coords.setAxisValue(0, 4));
+    ASSERT_EQ(0x0000000bULL, coords.bits);
+    ASSERT_EQ(4, coords.values[0]);
+    ASSERT_EQ(5, coords.values[1]);
+    ASSERT_EQ(2, coords.values[2]);
+
+    ASSERT_EQ(4, coords.getAxisValue(0))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(5, coords.getAxisValue(1))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(0, coords.getAxisValue(2))
+            << "getAxisValue should return zero because axis is not present";
+    ASSERT_EQ(2, coords.getAxisValue(3))
+            << "getAxisValue should return value of axis";
+
+    // Edit an existing axis value in place.
+    valuePtr = coords.editAxisValue(1);
+    ASSERT_EQ(5, *valuePtr)
+            << "editAxisValue should return pointer to axis value";
+
+    *valuePtr = 7;
+    ASSERT_EQ(7, coords.getAxisValue(1))
+            << "getAxisValue should return value of axis";
+
+    // Set an axis with an id between the others.  (inserting value in the middle)
+    ASSERT_EQ(OK, coords.setAxisValue(2, 1));
+    ASSERT_EQ(0x0000000fULL, coords.bits);
+    ASSERT_EQ(4, coords.values[0]);
+    ASSERT_EQ(7, coords.values[1]);
+    ASSERT_EQ(1, coords.values[2]);
+    ASSERT_EQ(2, coords.values[3]);
+
+    ASSERT_EQ(4, coords.getAxisValue(0))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(7, coords.getAxisValue(1))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(1, coords.getAxisValue(2))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(2, coords.getAxisValue(3))
+            << "getAxisValue should return value of axis";
+
+    // Set an existing axis value in place.
+    ASSERT_EQ(OK, coords.setAxisValue(1, 6));
+    ASSERT_EQ(0x0000000fULL, coords.bits);
+    ASSERT_EQ(4, coords.values[0]);
+    ASSERT_EQ(6, coords.values[1]);
+    ASSERT_EQ(1, coords.values[2]);
+    ASSERT_EQ(2, coords.values[3]);
+
+    ASSERT_EQ(4, coords.getAxisValue(0))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(6, coords.getAxisValue(1))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(1, coords.getAxisValue(2))
+            << "getAxisValue should return value of axis";
+    ASSERT_EQ(2, coords.getAxisValue(3))
+            << "getAxisValue should return value of axis";
+
+    // Set maximum number of axes.
+    for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) {
+        ASSERT_EQ(OK, coords.setAxisValue(axis, axis));
+    }
+    ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
+
+    // Try to set one more axis beyond maximum number.
+    // Ensure bits are unchanged.
+    ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100));
+    ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits));
+}
+
+TEST_F(PointerCoordsTest, Parcel) {
+    Parcel parcel;
+
+    PointerCoords inCoords;
+    inCoords.clear();
+    PointerCoords outCoords;
+
+    // Round trip with empty coords.
+    inCoords.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    outCoords.readFromParcel(&parcel);
+
+    ASSERT_EQ(0ULL, outCoords.bits);
+
+    // Round trip with some values.
+    parcel.freeData();
+    inCoords.setAxisValue(2, 5);
+    inCoords.setAxisValue(5, 8);
+
+    inCoords.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    outCoords.readFromParcel(&parcel);
+
+    ASSERT_EQ(outCoords.bits, inCoords.bits);
+    ASSERT_EQ(outCoords.values[0], inCoords.values[0]);
+    ASSERT_EQ(outCoords.values[1], inCoords.values[1]);
+}
+
+
+// --- KeyEventTest ---
+
+class KeyEventTest : public BaseTest {
+};
+
+TEST_F(KeyEventTest, Properties) {
+    KeyEvent event;
+
+    // Initialize and get properties.
+    const nsecs_t ARBITRARY_DOWN_TIME = 1;
+    const nsecs_t ARBITRARY_EVENT_TIME = 2;
+    event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
+            AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
+            AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
+
+    ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
+    ASSERT_EQ(2, event.getDeviceId());
+    ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
+    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
+    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
+    ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
+    ASSERT_EQ(121, event.getScanCode());
+    ASSERT_EQ(AMETA_ALT_ON, event.getMetaState());
+    ASSERT_EQ(1, event.getRepeatCount());
+    ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime());
+    ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getEventTime());
+
+    // Set source.
+    event.setSource(AINPUT_SOURCE_JOYSTICK);
+    ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+}
+
+
+// --- MotionEventTest ---
+
+class MotionEventTest : public BaseTest {
+protected:
+    static const nsecs_t ARBITRARY_DOWN_TIME;
+    static const nsecs_t ARBITRARY_EVENT_TIME;
+    static const float X_OFFSET;
+    static const float Y_OFFSET;
+
+    void initializeEventWithHistory(MotionEvent* event);
+    void assertEqualsEventWithHistory(const MotionEvent* event);
+};
+
+const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1;
+const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2;
+const float MotionEventTest::X_OFFSET = 1.0f;
+const float MotionEventTest::Y_OFFSET = 1.1f;
+
+void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
+    int32_t pointerIds[] = { 1, 2 };
+    PointerCoords pointerCoords[2];
+    pointerCoords[0].clear();
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 11);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 12);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 13);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 14);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 15);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 16);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 17);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 18);
+    pointerCoords[1].clear();
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 20);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 21);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 22);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 23);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 24);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 25);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
+    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+            AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
+            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON,
+            X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+            ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
+            2, pointerIds, pointerCoords);
+
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 112);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 113);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 114);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 115);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 116);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 117);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 118);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 120);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 121);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 122);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 123);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 124);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 125);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128);
+    event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords);
+
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 212);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 213);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 214);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 215);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 216);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 217);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 218);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 220);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 221);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 222);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 223);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 224);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 225);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227);
+    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228);
+    event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords);
+}
+
+void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) {
+    // Check properties.
+    ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
+    ASSERT_EQ(2, event->getDeviceId());
+    ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
+    ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
+    ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
+    ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
+    ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
+    ASSERT_EQ(X_OFFSET, event->getXOffset());
+    ASSERT_EQ(Y_OFFSET, event->getYOffset());
+    ASSERT_EQ(2.0f, event->getXPrecision());
+    ASSERT_EQ(2.1f, event->getYPrecision());
+    ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime());
+
+    ASSERT_EQ(2U, event->getPointerCount());
+    ASSERT_EQ(1, event->getPointerId(0));
+    ASSERT_EQ(2, event->getPointerId(1));
+
+    ASSERT_EQ(2U, event->getHistorySize());
+
+    // Check data.
+    ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0));
+    ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1));
+    ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime());
+
+    ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->
+            getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->
+            getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->
+            getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->
+            getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(211, event->getRawPointerCoords(0)->
+            getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(221, event->getRawPointerCoords(1)->
+            getAxisValue(AMOTION_EVENT_AXIS_Y));
+
+    ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
+    ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
+    ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
+    ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
+    ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
+    ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
+
+    ASSERT_EQ(10, event->getHistoricalRawX(0, 0));
+    ASSERT_EQ(20, event->getHistoricalRawX(1, 0));
+    ASSERT_EQ(110, event->getHistoricalRawX(0, 1));
+    ASSERT_EQ(120, event->getHistoricalRawX(1, 1));
+    ASSERT_EQ(210, event->getRawX(0));
+    ASSERT_EQ(220, event->getRawX(1));
+
+    ASSERT_EQ(11, event->getHistoricalRawY(0, 0));
+    ASSERT_EQ(21, event->getHistoricalRawY(1, 0));
+    ASSERT_EQ(111, event->getHistoricalRawY(0, 1));
+    ASSERT_EQ(121, event->getHistoricalRawY(1, 1));
+    ASSERT_EQ(211, event->getRawY(0));
+    ASSERT_EQ(221, event->getRawY(1));
+
+    ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0));
+    ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0));
+    ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1));
+    ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1));
+    ASSERT_EQ(X_OFFSET + 210, event->getX(0));
+    ASSERT_EQ(X_OFFSET + 220, event->getX(1));
+
+    ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0));
+    ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0));
+    ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1));
+    ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1));
+    ASSERT_EQ(Y_OFFSET + 211, event->getY(0));
+    ASSERT_EQ(Y_OFFSET + 221, event->getY(1));
+
+    ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
+    ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
+    ASSERT_EQ(112, event->getHistoricalPressure(0, 1));
+    ASSERT_EQ(122, event->getHistoricalPressure(1, 1));
+    ASSERT_EQ(212, event->getPressure(0));
+    ASSERT_EQ(222, event->getPressure(1));
+
+    ASSERT_EQ(13, event->getHistoricalSize(0, 0));
+    ASSERT_EQ(23, event->getHistoricalSize(1, 0));
+    ASSERT_EQ(113, event->getHistoricalSize(0, 1));
+    ASSERT_EQ(123, event->getHistoricalSize(1, 1));
+    ASSERT_EQ(213, event->getSize(0));
+    ASSERT_EQ(223, event->getSize(1));
+
+    ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0));
+    ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0));
+    ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1));
+    ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1));
+    ASSERT_EQ(214, event->getTouchMajor(0));
+    ASSERT_EQ(224, event->getTouchMajor(1));
+
+    ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0));
+    ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0));
+    ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1));
+    ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1));
+    ASSERT_EQ(215, event->getTouchMinor(0));
+    ASSERT_EQ(225, event->getTouchMinor(1));
+
+    ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0));
+    ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0));
+    ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1));
+    ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1));
+    ASSERT_EQ(216, event->getToolMajor(0));
+    ASSERT_EQ(226, event->getToolMajor(1));
+
+    ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0));
+    ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0));
+    ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1));
+    ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1));
+    ASSERT_EQ(217, event->getToolMinor(0));
+    ASSERT_EQ(227, event->getToolMinor(1));
+
+    ASSERT_EQ(18, event->getHistoricalOrientation(0, 0));
+    ASSERT_EQ(28, event->getHistoricalOrientation(1, 0));
+    ASSERT_EQ(118, event->getHistoricalOrientation(0, 1));
+    ASSERT_EQ(128, event->getHistoricalOrientation(1, 1));
+    ASSERT_EQ(218, event->getOrientation(0));
+    ASSERT_EQ(228, event->getOrientation(1));
+}
+
+TEST_F(MotionEventTest, Properties) {
+    MotionEvent event;
+
+    // Initialize, add samples and check properties.
+    initializeEventWithHistory(&event);
+    ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
+
+    // Set source.
+    event.setSource(AINPUT_SOURCE_JOYSTICK);
+    ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
+
+    // Set action.
+    event.setAction(AMOTION_EVENT_ACTION_CANCEL);
+    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
+
+    // Set meta state.
+    event.setMetaState(AMETA_CTRL_ON);
+    ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState());
+}
+
+TEST_F(MotionEventTest, CopyFrom_KeepHistory) {
+    MotionEvent event;
+    initializeEventWithHistory(&event);
+
+    MotionEvent copy;
+    copy.copyFrom(&event, true /*keepHistory*/);
+
+    ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event));
+}
+
+TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) {
+    MotionEvent event;
+    initializeEventWithHistory(&event);
+
+    MotionEvent copy;
+    copy.copyFrom(&event, false /*keepHistory*/);
+
+    ASSERT_EQ(event.getPointerCount(), copy.getPointerCount());
+    ASSERT_EQ(0U, copy.getHistorySize());
+
+    ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0));
+    ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1));
+
+    ASSERT_EQ(event.getEventTime(), copy.getEventTime());
+
+    ASSERT_EQ(event.getX(0), copy.getX(0));
+}
+
+TEST_F(MotionEventTest, OffsetLocation) {
+    MotionEvent event;
+    initializeEventWithHistory(&event);
+
+    event.offsetLocation(5.0f, -2.0f);
+
+    ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset());
+    ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset());
+}
+
+TEST_F(MotionEventTest, Scale) {
+    MotionEvent event;
+    initializeEventWithHistory(&event);
+
+    event.scale(2.0f);
+
+    ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
+    ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
+
+    ASSERT_EQ(210 * 2, event.getRawX(0));
+    ASSERT_EQ(211 * 2, event.getRawY(0));
+    ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0));
+    ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0));
+    ASSERT_EQ(212, event.getPressure(0));
+    ASSERT_EQ(213, event.getSize(0));
+    ASSERT_EQ(214 * 2, event.getTouchMajor(0));
+    ASSERT_EQ(215 * 2, event.getTouchMinor(0));
+    ASSERT_EQ(216 * 2, event.getToolMajor(0));
+    ASSERT_EQ(217 * 2, event.getToolMinor(0));
+    ASSERT_EQ(218, event.getOrientation(0));
+}
+
+TEST_F(MotionEventTest, Parcel) {
+    Parcel parcel;
+
+    MotionEvent inEvent;
+    initializeEventWithHistory(&inEvent);
+    MotionEvent outEvent;
+
+    // Round trip.
+    inEvent.writeToParcel(&parcel);
+    parcel.setDataPosition(0);
+    outEvent.readFromParcel(&parcel);
+
+    ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent));
+}
+
+TEST_F(MotionEventTest, Transform) {
+    // Generate some points on a circle.
+    // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
+    // of ARC * i degrees clockwise relative to the Y axis.
+    // The geometrical representation is irrelevant to the test, it's just easy to generate
+    // and check rotation.  We set the orientation to the same angle.
+    // Coordinate system: down is increasing Y, right is increasing X.
+    const float PI_180 = float(M_PI / 180);
+    const float RADIUS = 10;
+    const float ARC = 36;
+    const float ROTATION = ARC * 2;
+
+    const size_t pointerCount = 11;
+    int pointerIds[pointerCount];
+    PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        float angle = float(i * ARC * PI_180);
+        pointerIds[i] = i;
+        pointerCoords[i].clear();
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2);
+        pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
+    }
+    MotionEvent event;
+    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+    float originalRawX = 0 + 3;
+    float originalRawY = -RADIUS + 2;
+
+    // Check original raw X and Y assumption.
+    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
+    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
+
+    // Now translate the motion event so the circle's origin is at (0,0).
+    event.offsetLocation(-3, -2);
+
+    // Offsetting the location should preserve the raw X and Y of the first point.
+    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
+    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
+
+    // Apply a rotation about the origin by ROTATION degrees clockwise.
+    SkMatrix matrix;
+    matrix.setRotate(ROTATION);
+    event.transform(&matrix);
+
+    // Check the points.
+    for (size_t i = 0; i < pointerCount; i++) {
+        float angle = float((i * ARC + ROTATION) * PI_180);
+        ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001);
+        ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001);
+        ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
+    }
+
+    // Applying the transformation should preserve the raw X and Y of the first point.
+    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
+    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
+}
+
+} // namespace android
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 903fcaf..6e18a4f 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -1,6 +1,18 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
+/*
+ * 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 <ui/InputTransport.h>
 #include <utils/Timers.h>
@@ -159,15 +171,17 @@
         sampleEventTimes.push(i + 10);
         for (size_t j = 0; j < pointerCount; j++) {
             samplePointerCoords.push();
-            samplePointerCoords.editTop().x = 100 * i + j;
-            samplePointerCoords.editTop().y = 200 * i + j;
-            samplePointerCoords.editTop().pressure = 0.5 * i + j;
-            samplePointerCoords.editTop().size = 0.7 * i + j;
-            samplePointerCoords.editTop().touchMajor = 1.5 * i + j;
-            samplePointerCoords.editTop().touchMinor = 1.7 * i + j;
-            samplePointerCoords.editTop().toolMajor = 2.5 * i + j;
-            samplePointerCoords.editTop().toolMinor = 2.7 * i + j;
-            samplePointerCoords.editTop().orientation = 3.5 * i + j;
+            PointerCoords& pc = samplePointerCoords.editTop();
+            pc.clear();
+            pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i + j);
+            pc.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i + j);
         }
     }
 
@@ -239,27 +253,27 @@
         for (size_t i = 0; i < pointerCount; i++) {
             SCOPED_TRACE(i);
             size_t offset = sampleIndex * pointerCount + i;
-            EXPECT_EQ(samplePointerCoords[offset].x,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
                     motionEvent->getHistoricalRawX(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].y,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
                     motionEvent->getHistoricalRawY(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].x + xOffset,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
                     motionEvent->getHistoricalX(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].y + yOffset,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
                     motionEvent->getHistoricalY(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].pressure,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
                     motionEvent->getHistoricalPressure(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].size,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
                     motionEvent->getHistoricalSize(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].touchMajor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
                     motionEvent->getHistoricalTouchMajor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].touchMinor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
                     motionEvent->getHistoricalTouchMinor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].toolMajor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
                     motionEvent->getHistoricalToolMajor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].toolMinor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
                     motionEvent->getHistoricalToolMinor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].orientation,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
                     motionEvent->getHistoricalOrientation(i, sampleIndex));
         }
     }
@@ -269,17 +283,28 @@
     for (size_t i = 0; i < pointerCount; i++) {
         SCOPED_TRACE(i);
         size_t offset = lastSampleIndex * pointerCount + i;
-        EXPECT_EQ(samplePointerCoords[offset].x, motionEvent->getRawX(i));
-        EXPECT_EQ(samplePointerCoords[offset].y, motionEvent->getRawY(i));
-        EXPECT_EQ(samplePointerCoords[offset].x + xOffset, motionEvent->getX(i));
-        EXPECT_EQ(samplePointerCoords[offset].y + yOffset, motionEvent->getY(i));
-        EXPECT_EQ(samplePointerCoords[offset].pressure, motionEvent->getPressure(i));
-        EXPECT_EQ(samplePointerCoords[offset].size, motionEvent->getSize(i));
-        EXPECT_EQ(samplePointerCoords[offset].touchMajor, motionEvent->getTouchMajor(i));
-        EXPECT_EQ(samplePointerCoords[offset].touchMinor, motionEvent->getTouchMinor(i));
-        EXPECT_EQ(samplePointerCoords[offset].toolMajor, motionEvent->getToolMajor(i));
-        EXPECT_EQ(samplePointerCoords[offset].toolMinor, motionEvent->getToolMinor(i));
-        EXPECT_EQ(samplePointerCoords[offset].orientation, motionEvent->getOrientation(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
+                motionEvent->getRawX(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
+                motionEvent->getRawY(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
+                motionEvent->getX(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
+                motionEvent->getY(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+                motionEvent->getPressure(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+                motionEvent->getSize(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+                motionEvent->getTouchMajor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+                motionEvent->getTouchMinor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+                motionEvent->getToolMajor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+                motionEvent->getToolMinor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
+                motionEvent->getOrientation(i));
     }
 
     status = mConsumer->sendFinishedSignal(false);
@@ -328,7 +353,8 @@
 
     const size_t pointerCount = 1;
     int32_t pointerIds[pointerCount] = { 0 };
-    PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
+    PointerCoords pointerCoords[pointerCount];
+    pointerCoords[0].clear();
 
     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerIds, pointerCoords);
diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp
index a5363d6..18f858b 100644
--- a/libs/utils/Looper.cpp
+++ b/libs/utils/Looper.cpp
@@ -19,10 +19,27 @@
 
 #include <unistd.h>
 #include <fcntl.h>
+#include <limits.h>
 
 
 namespace android {
 
+// --- WeakMessageHandler ---
+
+WeakMessageHandler::WeakMessageHandler(const wp<MessageHandler>& handler) :
+        mHandler(handler) {
+}
+
+void WeakMessageHandler::handleMessage(const Message& message) {
+    sp<MessageHandler> handler = mHandler.promote();
+    if (handler != NULL) {
+        handler->handleMessage(message);
+    }
+}
+
+
+// --- Looper ---
+
 #ifdef LOOPER_USES_EPOLL
 // Hint for number of file descriptors to be associated with the epoll instance.
 static const int EPOLL_SIZE_HINT = 8;
@@ -35,8 +52,8 @@
 static pthread_key_t gTLSKey = 0;
 
 Looper::Looper(bool allowNonCallbacks) :
-        mAllowNonCallbacks(allowNonCallbacks),
-        mResponseIndex(0) {
+        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
+        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {
     int wakeFds[2];
     int result = pipe(wakeFds);
     LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe.  errno=%d", errno);
@@ -161,17 +178,21 @@
     for (;;) {
         while (mResponseIndex < mResponses.size()) {
             const Response& response = mResponses.itemAt(mResponseIndex++);
-            if (! response.request.callback) {
+            ALooper_callbackFunc callback = response.request.callback;
+            if (!callback) {
+                int ident = response.request.ident;
+                int fd = response.request.fd;
+                int events = response.events;
+                void* data = response.request.data;
 #if DEBUG_POLL_AND_WAKE
                 LOGD("%p ~ pollOnce - returning signalled identifier %d: "
-                        "fd=%d, events=0x%x, data=%p", this,
-                        response.request.ident, response.request.fd,
-                        response.events, response.request.data);
+                        "fd=%d, events=0x%x, data=%p",
+                        this, ident, fd, events, data);
 #endif
-                if (outFd != NULL) *outFd = response.request.fd;
-                if (outEvents != NULL) *outEvents = response.events;
-                if (outData != NULL) *outData = response.request.data;
-                return response.request.ident;
+                if (outFd != NULL) *outFd = fd;
+                if (outEvents != NULL) *outEvents = events;
+                if (outData != NULL) *outData = data;
+                return ident;
             }
         }
 
@@ -194,6 +215,25 @@
     LOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis);
 #endif
 
+    // Adjust the timeout based on when the next message is due.
+    if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        if (mNextMessageUptime <= now) {
+            timeoutMillis = 0;
+        } else {
+            uint64_t delay = (mNextMessageUptime - now + 999999LL) / 1000000LL;
+            if (delay < INT_MAX
+                    && (timeoutMillis < 0 || int(delay) < timeoutMillis)) {
+                timeoutMillis = int(delay);
+            }
+        }
+#if DEBUG_POLL_AND_WAKE
+        LOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d",
+                this, mNextMessageUptime - now, timeoutMillis);
+#endif
+    }
+
+    // Poll.
     int result = ALOOPER_POLL_WAKE;
     mResponses.clear();
     mResponseIndex = 0;
@@ -205,7 +245,6 @@
 #ifdef LOOPER_USES_EPOLL
     struct epoll_event eventItems[EPOLL_MAX_EVENTS];
     int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
-    bool acquiredLock = false;
 #else
     // Wait for wakeAndLock() waiters to run then set mPolling to true.
     mLock.lock();
@@ -219,16 +258,20 @@
     int eventCount = poll(mRequestedFds.editArray(), requestedCount, timeoutMillis);
 #endif
 
+    // Acquire lock.
+    mLock.lock();
+
+    // Check for poll error.
     if (eventCount < 0) {
         if (errno == EINTR) {
             goto Done;
         }
-
         LOGW("Poll failed with an unexpected error, errno=%d", errno);
         result = ALOOPER_POLL_ERROR;
         goto Done;
     }
 
+    // Check for poll timeout.
     if (eventCount == 0) {
 #if DEBUG_POLL_AND_WAKE
         LOGD("%p ~ pollOnce - timeout", this);
@@ -237,6 +280,7 @@
         goto Done;
     }
 
+    // Handle all events.
 #if DEBUG_POLL_AND_WAKE
     LOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount);
 #endif
@@ -252,11 +296,6 @@
                 LOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);
             }
         } else {
-            if (! acquiredLock) {
-                mLock.lock();
-                acquiredLock = true;
-            }
-
             ssize_t requestIndex = mRequests.indexOfKey(fd);
             if (requestIndex >= 0) {
                 int events = 0;
@@ -271,9 +310,6 @@
             }
         }
     }
-    if (acquiredLock) {
-        mLock.unlock();
-    }
 Done: ;
 #else
     for (size_t i = 0; i < requestedCount; i++) {
@@ -301,15 +337,12 @@
             }
         }
     }
-
 Done:
     // Set mPolling to false and wake up the wakeAndLock() waiters.
-    mLock.lock();
     mPolling = false;
     if (mWaiters != 0) {
         mAwake.broadcast();
     }
-    mLock.unlock();
 #endif
 
 #ifdef LOOPER_STATISTICS
@@ -335,19 +368,59 @@
     }
 #endif
 
+    // Invoke pending message callbacks.
+    mNextMessageUptime = LLONG_MAX;
+    while (mMessageEnvelopes.size() != 0) {
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
+        if (messageEnvelope.uptime <= now) {
+            // Remove the envelope from the list.
+            // We keep a strong reference to the handler until the call to handleMessage
+            // finishes.  Then we drop it so that the handler can be deleted *before*
+            // we reacquire our lock.
+            { // obtain handler
+                sp<MessageHandler> handler = messageEnvelope.handler;
+                Message message = messageEnvelope.message;
+                mMessageEnvelopes.removeAt(0);
+                mSendingMessage = true;
+                mLock.unlock();
+
+#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
+                LOGD("%p ~ pollOnce - sending message: handler=%p, what=%d",
+                        this, handler.get(), message.what);
+#endif
+                handler->handleMessage(message);
+            } // release handler
+
+            mLock.lock();
+            mSendingMessage = false;
+            result = ALOOPER_POLL_CALLBACK;
+        } else {
+            // The last message left at the head of the queue determines the next wakeup time.
+            mNextMessageUptime = messageEnvelope.uptime;
+            break;
+        }
+    }
+
+    // Release lock.
+    mLock.unlock();
+
+    // Invoke all response callbacks.
     for (size_t i = 0; i < mResponses.size(); i++) {
         const Response& response = mResponses.itemAt(i);
-        if (response.request.callback) {
+        ALooper_callbackFunc callback = response.request.callback;
+        if (callback) {
+            int fd = response.request.fd;
+            int events = response.events;
+            void* data = response.request.data;
 #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
-            LOGD("%p ~ pollOnce - invoking callback: fd=%d, events=0x%x, data=%p", this,
-                    response.request.fd, response.events, response.request.data);
+            LOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
+                    this, callback, fd, events, data);
 #endif
-            int callbackResult = response.request.callback(
-                    response.request.fd, response.events, response.request.data);
+            int callbackResult = callback(fd, events, data);
             if (callbackResult == 0) {
-                removeFd(response.request.fd);
+                removeFd(fd);
             }
-
             result = ALOOPER_POLL_CALLBACK;
         }
     }
@@ -593,4 +666,83 @@
 }
 #endif
 
+void Looper::sendMessage(const sp<MessageHandler>& handler, const Message& message) {
+    sendMessageAtTime(LLONG_MIN, handler, message);
+}
+
+void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp<MessageHandler>& handler,
+        const Message& message) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sendMessageAtTime(now + uptimeDelay, handler, message);
+}
+
+void Looper::sendMessageAtTime(nsecs_t uptime, const sp<MessageHandler>& handler,
+        const Message& message) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d",
+            this, uptime, handler.get(), message.what);
+#endif
+
+    size_t i = 0;
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        size_t messageCount = mMessageEnvelopes.size();
+        while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) {
+            i += 1;
+        }
+
+        MessageEnvelope messageEnvelope(uptime, handler, message);
+        mMessageEnvelopes.insertAt(messageEnvelope, i, 1);
+
+        // Optimization: If the Looper is currently sending a message, then we can skip
+        // the call to wake() because the next thing the Looper will do after processing
+        // messages is to decide when the next wakeup time should be.  In fact, it does
+        // not even matter whether this code is running on the Looper thread.
+        if (mSendingMessage) {
+            return;
+        }
+    } // release lock
+
+    // Wake the poll loop only when we enqueue a new message at the head.
+    if (i == 0) {
+        wake();
+    }
+}
+
+void Looper::removeMessages(const sp<MessageHandler>& handler) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ removeMessages - handler=%p", this, handler.get());
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
+            const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
+            if (messageEnvelope.handler == handler) {
+                mMessageEnvelopes.removeAt(i);
+            }
+        }
+    } // release lock
+}
+
+void Looper::removeMessages(const sp<MessageHandler>& handler, int what) {
+#if DEBUG_CALLBACKS
+    LOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what);
+#endif
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        for (size_t i = mMessageEnvelopes.size(); i != 0; ) {
+            const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i);
+            if (messageEnvelope.handler == handler
+                    && messageEnvelope.message.what == what) {
+                mMessageEnvelopes.removeAt(i);
+            }
+        }
+    } // release lock
+}
+
 } // namespace android
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 0bd1af4..bb6c125 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -20,9 +20,9 @@
 
 #include <utils/Atomic.h>
 #include <utils/CallStack.h>
-#include <utils/KeyedVector.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
+#include <utils/TextOutput.h>
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -34,6 +34,7 @@
 
 // compile with refcounting debugging enabled
 #define DEBUG_REFS                      0
+#define DEBUG_REFS_FATAL_SANITY_CHECKS  0
 #define DEBUG_REFS_ENABLED_BY_DEFAULT   1
 #define DEBUG_REFS_CALLSTACK_ENABLED    1
 
@@ -69,8 +70,10 @@
 
     void addStrongRef(const void* /*id*/) { }
     void removeStrongRef(const void* /*id*/) { }
+    void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
     void addWeakRef(const void* /*id*/) { }
     void removeWeakRef(const void* /*id*/) { }
+    void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
     void printRefs() const { }
     void trackMe(bool, bool) { }
 
@@ -86,39 +89,91 @@
         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
         , mRetain(false)
     {
-        //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
     }
     
     ~weakref_impl()
     {
-        LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
-        LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
+        bool dumpStack = false;
+        if (!mRetain && mStrongRefs != NULL) {
+            dumpStack = true;
+#if DEBUG_REFS_FATAL_SANITY_CHECKS
+            LOG_ALWAYS_FATAL("Strong references remain!");
+#else
+            LOGE("Strong references remain:");
+#endif
+            ref_entry* refs = mStrongRefs;
+            while (refs) {
+                char inc = refs->ref >= 0 ? '+' : '-';
+                LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+                refs->stack.dump();
+#endif;
+                refs = refs->next;
+            }
+        }
+
+        if (!mRetain && mWeakRefs != NULL) {
+            dumpStack = true;
+#if DEBUG_REFS_FATAL_SANITY_CHECKS
+            LOG_ALWAYS_FATAL("Weak references remain:");
+#else
+            LOGE("Weak references remain!");
+#endif
+            ref_entry* refs = mWeakRefs;
+            while (refs) {
+                char inc = refs->ref >= 0 ? '+' : '-';
+                LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
+#if DEBUG_REFS_CALLSTACK_ENABLED
+                refs->stack.dump();
+#endif;
+                refs = refs->next;
+            }
+        }
+        if (dumpStack) {
+            LOGE("above errors at:");
+            CallStack stack;
+            stack.update();
+            stack.dump();
+        }
     }
 
-    void addStrongRef(const void* id)
-    {
+    void addStrongRef(const void* id) {
+        //LOGD_IF(mTrackEnabled,
+        //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
         addRef(&mStrongRefs, id, mStrong);
     }
 
-    void removeStrongRef(const void* id)
-    {
-        if (!mRetain)
+    void removeStrongRef(const void* id) {
+        //LOGD_IF(mTrackEnabled,
+        //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
+        if (!mRetain) {
             removeRef(&mStrongRefs, id);
-        else
+        } else {
             addRef(&mStrongRefs, id, -mStrong);
+        }
     }
 
-    void addWeakRef(const void* id)
-    {
+    void renameStrongRefId(const void* old_id, const void* new_id) {
+        //LOGD_IF(mTrackEnabled,
+        //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
+        //        mBase, old_id, new_id);
+        renameRefsId(mStrongRefs, old_id, new_id);
+    }
+
+    void addWeakRef(const void* id) {
         addRef(&mWeakRefs, id, mWeak);
     }
 
-    void removeWeakRef(const void* id)
-    {
-        if (!mRetain)
+    void removeWeakRef(const void* id) {
+        if (!mRetain) {
             removeRef(&mWeakRefs, id);
-        else
+        } else {
             addRef(&mWeakRefs, id, -mWeak);
+        }
+    }
+
+    void renameWeakRefId(const void* old_id, const void* new_id) {
+        renameRefsId(mWeakRefs, old_id, new_id);
     }
 
     void trackMe(bool track, bool retain)
@@ -132,8 +187,7 @@
         String8 text;
 
         {
-            AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
-    
+            Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
             char buf[128];
             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
             text.append(buf);
@@ -172,6 +226,7 @@
     {
         if (mTrackEnabled) {
             AutoMutex _l(mMutex);
+
             ref_entry* ref = new ref_entry;
             // Reference count at the time of the snapshot, but before the
             // update.  Positive value means we increment, negative--we
@@ -181,7 +236,6 @@
 #if DEBUG_REFS_CALLSTACK_ENABLED
             ref->stack.update(2);
 #endif
-            
             ref->next = *refs;
             *refs = ref;
         }
@@ -192,20 +246,52 @@
         if (mTrackEnabled) {
             AutoMutex _l(mMutex);
             
-            ref_entry* ref = *refs;
+            ref_entry* const head = *refs;
+            ref_entry* ref = head;
             while (ref != NULL) {
                 if (ref->id == id) {
                     *refs = ref->next;
                     delete ref;
                     return;
                 }
-                
                 refs = &ref->next;
                 ref = *refs;
             }
-            
-            LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
-                             id, mBase, this);
+
+#if DEBUG_REFS_FATAL_SANITY_CHECKS
+            LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
+                    "(weakref_type %p) that doesn't exist!",
+                    id, mBase, this);
+#endif
+
+            LOGE("RefBase: removing id %p on RefBase %p"
+                    "(weakref_type %p) that doesn't exist!",
+                    id, mBase, this);
+
+            ref = head;
+            while (ref) {
+                char inc = ref->ref >= 0 ? '+' : '-';
+                LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
+                ref = ref->next;
+            }
+
+            CallStack stack;
+            stack.update();
+            stack.dump();
+        }
+    }
+
+    void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
+    {
+        if (mTrackEnabled) {
+            AutoMutex _l(mMutex);
+            ref_entry* ref = r;
+            while (ref != NULL) {
+                if (ref->id == old_id) {
+                    ref->id = new_id;
+                }
+                ref = ref->next;
+            }
         }
     }
 
@@ -235,44 +321,6 @@
     // on removeref that match the address ones.
     bool mRetain;
 
-#if 0
-    void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
-    {
-        AutoMutex _l(mMutex);
-        ssize_t i = refs->indexOfKey(id);
-        if (i >= 0) {
-            ++(refs->editValueAt(i));
-        } else {
-            i = refs->add(id, 1);
-        }
-    }
-
-    void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
-    {
-        AutoMutex _l(mMutex);
-        ssize_t i = refs->indexOfKey(id);
-        LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
-        if (i >= 0) {
-            int32_t val = --(refs->editValueAt(i));
-            if (val == 0) {
-                refs->removeItemsAt(i);
-            }
-        }
-    }
-
-    void printRefs(const KeyedVector<const void*, int32_t>& refs)
-    {
-        const size_t N=refs.size();
-        for (size_t i=0; i<N; i++) {
-            printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
-        }
-    }
-
-    mutable Mutex mMutex;
-    KeyedVector<const void*, int32_t> mStrongRefs;
-    KeyedVector<const void*, int32_t> mWeakRefs;
-#endif
-
 #endif
 };
 
@@ -281,7 +329,6 @@
 void RefBase::incStrong(const void* id) const
 {
     weakref_impl* const refs = mRefs;
-    refs->addWeakRef(id);
     refs->incWeak(id);
     
     refs->addStrongRef(id);
@@ -313,14 +360,12 @@
             delete this;
         }
     }
-    refs->removeWeakRef(id);
     refs->decWeak(id);
 }
 
 void RefBase::forceIncStrong(const void* id) const
 {
     weakref_impl* const refs = mRefs;
-    refs->addWeakRef(id);
     refs->incWeak(id);
     
     refs->addStrongRef(id);
@@ -372,7 +417,7 @@
         if (impl->mStrong == INITIAL_STRONG_VALUE)
             delete impl->mBase;
         else {
-//            LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
+            // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
             delete impl;
         }
     } else {
@@ -432,7 +477,6 @@
         }
     }
     
-    impl->addWeakRef(id);
     impl->addStrongRef(id);
 
 #if PRINT_REFS
@@ -450,7 +494,7 @@
 bool RefBase::weakref_type::attemptIncWeak(const void* id)
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
-    
+
     int32_t curCount = impl->mWeak;
     LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
                this);
@@ -497,14 +541,11 @@
 RefBase::RefBase()
     : mRefs(new weakref_impl(this))
 {
-//    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
 }
 
 RefBase::~RefBase()
 {
-//    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
     if (mRefs->mWeak == 0) {
-//        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
         delete mRefs;
     }
 }
@@ -530,5 +571,37 @@
 void RefBase::onLastWeakRef(const void* /*id*/)
 {
 }
-        
+
+// ---------------------------------------------------------------------------
+
+void RefBase::moveReferences(void* dst, void const* src, size_t n,
+        const ReferenceConverterBase& caster)
+{
+#if DEBUG_REFS
+    const size_t itemSize = caster.getReferenceTypeSize();
+    for (size_t i=0 ; i<n ; i++) {
+        void*       d = reinterpret_cast<void      *>(intptr_t(dst) + i*itemSize);
+        void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
+        RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
+        ref->mRefs->renameStrongRefId(s, d);
+        ref->mRefs->renameWeakRefId(s, d);
+    }
+#endif
+}
+
+// ---------------------------------------------------------------------------
+
+TextOutput& printStrongPointer(TextOutput& to, const void* val)
+{
+    to << "sp<>(" << val << ")";
+    return to;
+}
+
+TextOutput& printWeakPointer(TextOutput& to, const void* val)
+{
+    to << "wp<>(" << val << ")";
+    return to;
+}
+
+
 }; // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 73ff230..7197ad7 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4141,6 +4141,38 @@
     }
 }
 
+// Normalize a string for output
+String8 ResTable::normalizeForOutput( const char *input )
+{
+    String8 ret;
+    char buff[2];
+    buff[1] = '\0';
+
+    while (*input != '\0') {
+        switch (*input) {
+            // All interesting characters are in the ASCII zone, so we are making our own lives
+            // easier by scanning the string one byte at a time.
+        case '\\':
+            ret += "\\\\";
+            break;
+        case '\n':
+            ret += "\\n";
+            break;
+        case '"':
+            ret += "\\\"";
+            break;
+        default:
+            buff[0] = *input;
+            ret += buff;
+            break;
+        }
+
+        input++;
+    }
+
+    return ret;
+}
+
 void ResTable::print_value(const Package* pkg, const Res_value& value) const
 {
     if (value.dataType == Res_value::TYPE_NULL) {
@@ -4154,13 +4186,13 @@
         const char* str8 = pkg->header->values.string8At(
                 value.data, &len);
         if (str8 != NULL) {
-            printf("(string8) \"%s\"\n", str8);
+            printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
         } else {
             const char16_t* str16 = pkg->header->values.stringAt(
                     value.data, &len);
             if (str16 != NULL) {
                 printf("(string16) \"%s\"\n",
-                    String8(str16, len).string());
+                    normalizeForOutput(String8(str16, len).string()).string());
             } else {
                 printf("(string) null\n");
             }
diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp
index 2bdc0ce..062e6d7 100644
--- a/libs/utils/SystemClock.cpp
+++ b/libs/utils/SystemClock.cpp
@@ -19,7 +19,7 @@
  * System clock functions.
  */
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
 #include <linux/ioctl.h>
 #include <linux/rtc.h>
 #include <utils/Atomic.h>
@@ -50,7 +50,7 @@
     return -1;
 #else
     struct timeval tv;
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     struct timespec ts;
     int fd;
     int res;
@@ -66,7 +66,7 @@
 
     LOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     fd = open("/dev/alarm", O_RDWR);
     if(fd < 0) {
         LOGW("Unable to open alarm driver: %s\n", strerror(errno));
@@ -106,7 +106,7 @@
  */
 int64_t elapsedRealtime()
 {
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     static int s_fd = -1;
 
     if (s_fd == -1) {
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index ad9a94f..8b5da0e 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -675,6 +675,9 @@
         mLock("Thread::mLock"),
         mStatus(NO_ERROR),
         mExitPending(false), mRunning(false)
+#ifdef HAVE_ANDROID_OS
+        , mTid(-1)
+#endif
 {
 }
 
@@ -715,6 +718,7 @@
         res = androidCreateRawThreadEtc(_threadLoop,
                 this, name, priority, stack, &mThread);
     }
+    // The new thread wakes up at _threadLoop, but immediately blocks on mLock
     
     if (res == false) {
         mStatus = UNKNOWN_ERROR;   // something happened!
@@ -730,16 +734,24 @@
     // here merely indicates successfully starting the thread and does not
     // imply successful termination/execution.
     return NO_ERROR;
+
+    // Exiting scope of mLock is a memory barrier and allows new thread to run
 }
 
 int Thread::_threadLoop(void* user)
 {
     Thread* const self = static_cast<Thread*>(user);
+
+    // force a memory barrier before reading any fields, in particular mHoldSelf
+    {
+    Mutex::Autolock _l(self->mLock);
+    }
+
     sp<Thread> strong(self->mHoldSelf);
     wp<Thread> weak(strong);
     self->mHoldSelf.clear();
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
     // this is very useful for debugging with gdb
     self->mTid = gettid();
 #endif
@@ -753,7 +765,7 @@
             self->mStatus = self->readyToRun();
             result = (self->mStatus == NO_ERROR);
 
-            if (result && !self->mExitPending) {
+            if (result && !self->exitPending()) {
                 // Binder threads (and maybe others) rely on threadLoop
                 // running at least once after a successful ::readyToRun()
                 // (unless, of course, the thread has already been asked to exit
@@ -770,17 +782,21 @@
             result = self->threadLoop();
         }
 
+        // establish a scope for mLock
+        {
+        Mutex::Autolock _l(self->mLock);
         if (result == false || self->mExitPending) {
             self->mExitPending = true;
-            self->mLock.lock();
             self->mRunning = false;
             // clear thread ID so that requestExitAndWait() does not exit if
             // called by a new thread using the same thread ID as this one.
             self->mThread = thread_id_t(-1);
+            // note that interested observers blocked in requestExitAndWait are
+            // awoken by broadcast, but blocked on mLock until break exits scope
             self->mThreadExitedCondition.broadcast();
-            self->mLock.unlock();
             break;
         }
+        }
         
         // Release our strong reference, to let a chance to the thread
         // to die a peaceful death.
@@ -794,6 +810,7 @@
 
 void Thread::requestExit()
 {
+    Mutex::Autolock _l(mLock);
     mExitPending = true;
 }
 
@@ -814,6 +831,8 @@
     while (mRunning == true) {
         mThreadExitedCondition.wait(mLock);
     }
+    // This next line is probably not needed any more, but is being left for
+    // historical reference. Note that each interested party will clear flag.
     mExitPending = false;
 
     return mStatus;
@@ -821,6 +840,7 @@
 
 bool Thread::exitPending() const
 {
+    Mutex::Autolock _l(mLock);
     return mExitPending;
 }
 
diff --git a/libs/utils/tests/Looper_test.cpp b/libs/utils/tests/Looper_test.cpp
index cea1313..8bf2ba2 100644
--- a/libs/utils/tests/Looper_test.cpp
+++ b/libs/utils/tests/Looper_test.cpp
@@ -16,6 +16,13 @@
 
 namespace android {
 
+enum {
+    MSG_TEST1 = 1,
+    MSG_TEST2 = 2,
+    MSG_TEST3 = 3,
+    MSG_TEST4 = 4,
+};
+
 class DelayedWake : public DelayedTask {
     sp<Looper> mLooper;
 
@@ -82,6 +89,15 @@
     }
 };
 
+class StubMessageHandler : public MessageHandler {
+public:
+    Vector<Message> messages;
+
+    virtual void handleMessage(const Message& message) {
+        messages.push(message);
+    }
+};
+
 class LooperTest : public testing::Test {
 protected:
     sp<Looper> mLooper;
@@ -421,5 +437,257 @@
             << "replacement handler callback should be invoked";
 }
 
+TEST_F(LooperTest, SendMessage_WhenOneMessageIsEnqueue_ShouldInvokeHandlerDuringNextPoll) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessage(handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessage_WhenMultipleMessagesAreEnqueued_ShouldInvokeHandlersInOrderDuringNextPoll) {
+    sp<StubMessageHandler> handler1 = new StubMessageHandler();
+    sp<StubMessageHandler> handler2 = new StubMessageHandler();
+    mLooper->sendMessage(handler1, Message(MSG_TEST1));
+    mLooper->sendMessage(handler2, Message(MSG_TEST2));
+    mLooper->sendMessage(handler1, Message(MSG_TEST3));
+    mLooper->sendMessage(handler1, Message(MSG_TEST4));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(3), handler1->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler1->messages[0].what)
+            << "handled message";
+    EXPECT_EQ(MSG_TEST3, handler1->messages[1].what)
+            << "handled message";
+    EXPECT_EQ(MSG_TEST4, handler1->messages[2].what)
+            << "handled message";
+    EXPECT_EQ(size_t(1), handler2->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST2, handler2->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageDelayed_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageDelayed(ms2ns(100), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "first poll should end quickly because next message timeout was computed";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no message handled yet";
+
+    result = mLooper->pollOnce(1000);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "second poll should end around the time of the delayed message dispatch";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+
+    result = mLooper->pollOnce(100);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "third poll should timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left";
+}
+
+TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageDelayed(ms2ns(-1000), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageDelayed_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageDelayed(0, handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageAtTime_WhenSentToTheFuture_ShouldInvokeHandlerAfterDelayTime) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageAtTime(now + ms2ns(100), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(1000);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "first poll should end quickly because next message timeout was computed";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_WAKE due to wakeup";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no message handled yet";
+
+    result = mLooper->pollOnce(1000);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+    EXPECT_NEAR(100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "second poll should end around the time of the delayed message dispatch";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+
+    result = mLooper->pollOnce(100);
+    elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(100 + 100, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "third poll should timeout";
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there were no messages left";
+}
+
+TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePast_ShouldInvokeHandlerDuringNextPoll) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageAtTime(now - ms2ns(1000), handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, SendMessageAtTime_WhenSentToThePresent_ShouldInvokeHandlerDuringNextPoll) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessageAtTime(now, handler, Message(MSG_TEST1));
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(100);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was already sent";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because message was sent";
+    EXPECT_EQ(size_t(1), handler->messages.size())
+            << "handled message";
+    EXPECT_EQ(MSG_TEST1, handler->messages[0].what)
+            << "handled message";
+}
+
+TEST_F(LooperTest, RemoveMessage_WhenRemovingAllMessagesForHandler_ShouldRemoveThoseMessage) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessage(handler, Message(MSG_TEST1));
+    mLooper->sendMessage(handler, Message(MSG_TEST2));
+    mLooper->sendMessage(handler, Message(MSG_TEST3));
+    mLooper->removeMessages(handler);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was sent so looper was awoken";
+    EXPECT_EQ(ALOOPER_POLL_WAKE, result)
+            << "pollOnce result should be ALOOPER_POLL_WAKE because looper was awoken";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no messages to handle";
+
+    result = mLooper->pollOnce(0);
+
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do";
+    EXPECT_EQ(size_t(0), handler->messages.size())
+            << "no messages to handle";
+}
+
+TEST_F(LooperTest, RemoveMessage_WhenRemovingSomeMessagesForHandler_ShouldRemoveThoseMessage) {
+    sp<StubMessageHandler> handler = new StubMessageHandler();
+    mLooper->sendMessage(handler, Message(MSG_TEST1));
+    mLooper->sendMessage(handler, Message(MSG_TEST2));
+    mLooper->sendMessage(handler, Message(MSG_TEST3));
+    mLooper->sendMessage(handler, Message(MSG_TEST4));
+    mLooper->removeMessages(handler, MSG_TEST3);
+    mLooper->removeMessages(handler, MSG_TEST1);
+
+    StopWatch stopWatch("pollOnce");
+    int result = mLooper->pollOnce(0);
+    int32_t elapsedMillis = ns2ms(stopWatch.elapsedTime());
+
+    EXPECT_NEAR(0, elapsedMillis, TIMING_TOLERANCE_MS)
+            << "elapsed time should approx. zero because message was sent so looper was awoken";
+    EXPECT_EQ(ALOOPER_POLL_CALLBACK, result)
+            << "pollOnce result should be ALOOPER_POLL_CALLBACK because two messages were sent";
+    EXPECT_EQ(size_t(2), handler->messages.size())
+            << "no messages to handle";
+    EXPECT_EQ(MSG_TEST2, handler->messages[0].what)
+            << "handled message";
+    EXPECT_EQ(MSG_TEST4, handler->messages[1].what)
+            << "handled message";
+
+    result = mLooper->pollOnce(0);
+
+    EXPECT_EQ(ALOOPER_POLL_TIMEOUT, result)
+            << "pollOnce result should be ALOOPER_POLL_TIMEOUT because there was nothing to do";
+    EXPECT_EQ(size_t(2), handler->messages.size())
+            << "no more messages to handle";
+}
 
 } // namespace android
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 8977fbf..3d5a4d1 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -22,7 +22,7 @@
 
 #include <sys/ioctl.h>
 
-#if HAVE_ANDROID_OS
+#ifdef HAVE_ANDROID_OS
 #include <linux/android_pmem.h>
 #endif
 
@@ -389,10 +389,9 @@
 }
 
 static inline void clearError() {
-    if (gEGLThreadLocalStorageKey != -1) {
-        tls_t* tls = getTLS();
-        tls->error = EGL_SUCCESS;
-    }
+    // This must clear the error from all the underlying EGL implementations as
+    // well as the EGL wrapper layer.
+    eglGetError();
 }
 
 template<typename T>
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f64fd7b..1297363 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -56,6 +56,7 @@
         mNeedsBlending(true),
         mNeedsDithering(false),
         mSecure(false),
+        mProtectedByApp(false),
         mTextureManager(),
         mBufferManager(mTextureManager),
         mWidth(0), mHeight(0), mNeedsScaling(false), mFixedSize(false)
@@ -140,7 +141,8 @@
 
 sp<LayerBaseClient::Surface> Layer::createSurface() const
 {
-    return mSurface;
+    sp<Surface> sur(new SurfaceLayer(mFlinger, const_cast<Layer *>(this)));
+    return sur;
 }
 
 status_t Layer::ditch()
@@ -150,9 +152,6 @@
     // the layer is not on screen anymore. free as much resources as possible
     mFreezeLock.clear();
 
-    // Free our own reference to ISurface
-    mSurface.clear();
-
     Mutex::Autolock _l(mLock);
     mWidth = mHeight = 0;
     return NO_ERROR;
@@ -190,6 +189,7 @@
     mReqHeight = h;
 
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
+    mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
     mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
             (flags & ISurfaceComposer::eOpaque) == 0;
 
@@ -198,7 +198,6 @@
     int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED);
     mNeedsDithering = layerRedsize > displayRedSize;
 
-    mSurface = new SurfaceLayer(mFlinger, this);
     return NO_ERROR;
 }
 
@@ -340,6 +339,45 @@
     drawWithOpenGL(clip, tex);
 }
 
+// As documented in libhardware header, formats in the range
+// 0x100 - 0x1FF are specific to the HAL implementation, and
+// are known to have no alpha channel
+// TODO: move definition for device-specific range into
+// hardware.h, instead of using hard-coded values here.
+#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
+
+bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const
+{
+    // If buffers where set with eOpaque flag, all buffers are known to
+    // be opaque without having to check their actual format
+    if (mNeedsBlending && buffer != NULL) {
+        PixelFormat format = buffer->getPixelFormat();
+
+        if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+            return false;
+        }
+
+        PixelFormatInfo info;
+        status_t err = getPixelFormatInfo(format, &info);
+        if (!err && info.h_alpha <= info.l_alpha) {
+            return false;
+        }
+    }
+
+    // Return opacity as determined from flags and format options
+    // passed to setBuffers()
+    return mNeedsBlending;
+}
+
+bool Layer::needsBlending() const
+{
+    if (mBufferManager.hasActiveBuffer()) {
+        return needsBlending(mBufferManager.getActiveBuffer());
+    }
+
+    return mNeedsBlending;
+}
+
 bool Layer::needsFiltering() const
 {
     if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
@@ -352,6 +390,12 @@
     return LayerBase::needsFiltering();
 }
 
+bool Layer::isProtected() const
+{
+    sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
+    return (activeBuffer != 0) &&
+            (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
 
 status_t Layer::setBufferCount(int bufferCount)
 {
@@ -475,6 +519,10 @@
         // request EGLImage for all buffers
         usage |= GraphicBuffer::USAGE_HW_TEXTURE;
     }
+    if (mProtectedByApp) {
+        // need a hardware-protected path to external video sink
+        usage |= GraphicBuffer::USAGE_PROTECTED;
+    }
     return usage;
 }
 
@@ -583,6 +631,9 @@
     // we retired a buffer, which becomes the new front buffer
 
     const bool noActiveBuffer = !mBufferManager.hasActiveBuffer();
+    const bool activeBlending =
+            noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer());
+
     if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
         LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
         mPostedDirtyRegion.clear();
@@ -597,6 +648,12 @@
 
     sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
     if (newFrontBuffer != NULL) {
+        if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) {
+            // new buffer has different opacity than previous active buffer, need
+            // to recompute visible regions accordingly
+            recomputeVisibleRegions = true;
+        }
+
         // get the dirty region
         // compute the posted region
         const Region dirty(lcblk->getDirtyRegion(buf));
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2908119..128f93d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -75,10 +75,12 @@
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-    virtual bool needsBlending() const      { return mNeedsBlending; }
+    virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const;
+    virtual bool needsBlending() const;
     virtual bool needsDithering() const     { return mNeedsDithering; }
     virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
+    virtual bool isProtected() const;
     virtual sp<Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onRemoved();
@@ -211,14 +213,14 @@
     ClientRef mUserClientRef;
 
     // constants
-    sp<Surface> mSurface;
     PixelFormat mFormat;
     const GLExtensions& mGLExtensions;
     bool mNeedsBlending;
     bool mNeedsDithering;
 
     // page-flip thread (currently main thread)
-    bool mSecure;
+    bool mSecure;         // no screenshots
+    bool mProtectedByApp; // application requires protected path to external sink
     Region mPostedDirtyRegion;
 
     // page-flip thread and transaction thread (currently main thread)
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 86057f8..6025ed4 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -540,7 +540,9 @@
 
 LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client)
-    : LayerBase(flinger, display), mClientRef(client),
+    : LayerBase(flinger, display),
+      mHasSurface(false),
+      mClientRef(client),
       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
 {
 }
@@ -557,12 +559,13 @@
 {
     sp<Surface> s;
     Mutex::Autolock _l(mLock);
-    s = mClientSurface.promote();
-    if (s == 0) {
-        s = createSurface();
-        mClientSurface = s;
-        mClientSurfaceBinder = s->asBinder();
-    }
+
+    LOG_ALWAYS_FATAL_IF(mHasSurface,
+            "LayerBaseClient::getSurface() has already been called");
+
+    mHasSurface = true;
+    s = createSurface();
+    mClientSurfaceBinder = s->asBinder();
     return s;
 }
 
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 8ed4749..7162e47 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -196,6 +196,12 @@
      */
     virtual bool isSecure() const       { return false; }
 
+    /**
+     * isProtected - true if the layer may contain protected content in the
+     * GRALLOC_USAGE_PROTECTED sense.
+     */
+    virtual bool isProtected() const   { return false; }
+
     /** Called from the main thread, when the surface is removed from the
      * draw list */
     virtual status_t ditch() { return NO_ERROR; }
@@ -325,7 +331,7 @@
 
 private:
     mutable Mutex mLock;
-    mutable wp<Surface> mClientSurface;
+    mutable bool mHasSurface;
     wp<IBinder> mClientSurfaceBinder;
     const wp<Client> mClientRef;
     // only read
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index 5631c0a..75f9a89 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -37,8 +37,10 @@
         virtual ~LayerDim();
 
     virtual void onDraw(const Region& clip) const;
-    virtual bool needsBlending() const  { return true; }
-    virtual bool isSecure() const       { return false; }
+    virtual bool needsBlending() const    { return true; }
+    virtual bool isSecure() const         { return false; }
+    virtual bool isProtectedByApp() const { return false; }
+    virtual bool isProtectedByDRM() const { return false; }
     virtual const char* getTypeId() const { return "LayerDim"; }
 };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fd3f0c2..a9fa1ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -327,6 +327,40 @@
     const_cast<SurfaceFlinger*>(this)->signalEvent();
 }
 
+bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
+    Mutex::Autolock _l(mStateLock);
+    sp<IBinder> surfBinder(surface->asBinder());
+
+    // Check the visible layer list for the ISurface
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+        if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+            return true;
+        }
+    }
+
+    // Check the layers in the purgatory.  This check is here so that if a
+    // Surface gets destroyed before all the clients are done using it, the
+    // error will not be reported as "surface XYZ is not authenticated", but
+    // will instead fail later on when the client tries to use the surface,
+    // which should be reported as "surface XYZ returned an -ENODEV".  The
+    // purgatorized layers are no less authentic than the visible ones, so this
+    // should not cause any harm.
+    size_t purgatorySize =  mLayerPurgatory.size();
+    for (size_t i=0 ; i<purgatorySize ; i++) {
+        const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+        sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+        if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t flags)
 {
@@ -2135,6 +2169,19 @@
     if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
         return BAD_VALUE;
 
+    // make sure none of the layers are protected
+    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+    const size_t count = layers.size();
+    for (size_t i=0 ; i<count ; ++i) {
+        const sp<LayerBase>& layer(layers[i]);
+        const uint32_t z = layer->drawingState().z;
+        if (z >= minLayerZ && z <= maxLayerZ) {
+            if (layer->isProtected()) {
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
     if (!GLExtensions::getInstance().haveFramebufferObject())
         return INVALID_OPERATION;
 
@@ -2150,8 +2197,8 @@
     sh = (!sh) ? hw_h : sh;
     const size_t size = sw * sh * 4;
 
-    LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
-            sw, sh, minLayerZ, maxLayerZ);
+    //LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
+    //        sw, sh, minLayerZ, maxLayerZ);
 
     // make sure to clear all GL error flags
     while ( glGetError() != GL_NO_ERROR ) ;
@@ -2183,8 +2230,6 @@
         glClearColor(0,0,0,1);
         glClear(GL_COLOR_BUFFER_BIT);
 
-        const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
-        const size_t count = layers.size();
         for (size_t i=0 ; i<count ; ++i) {
             const sp<LayerBase>& layer(layers[i]);
             const uint32_t z = layer->drawingState().z;
@@ -2236,7 +2281,7 @@
 
     hw.compositionComplete();
 
-    LOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
+    // LOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
 
     return result;
 }
@@ -2470,7 +2515,7 @@
             }
             break;
         }
-        if (++name > 31)
+        if (++name >= SharedBufferStack::NUM_LAYERS_MAX)
             name = NO_MEMORY;
     } while(name >= 0);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6dd91ac..9566819 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -209,6 +209,7 @@
     virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
     virtual void                        signal() const;
+    virtual bool                        authenticateSurface(const sp<ISurface>& surface) const;
 
     virtual status_t captureScreen(DisplayID dpy,
             sp<IMemoryHeap>* heap,