Merge "Part of fix for bug 4997380: Some error types unknown to SslError"
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index e705c6f..1eda646 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -51,7 +51,7 @@
     // the given slot index, and the client is expected to mirror the
     // slot->buffer mapping so that it's not necessary to transfer a
     // GraphicBuffer for every dequeue operation.
-    virtual sp<GraphicBuffer> requestBuffer(int slot) = 0;
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
 
     // setBufferCount sets the number of buffer slots available. Calling this
     // will also cause all buffer slots to be emptied. The caller should empty
@@ -78,7 +78,12 @@
     // client for this buffer. The timestamp is measured in nanoseconds, and
     // must be monotonically increasing. Its other properties (zero point, etc)
     // are client-dependent, and should be documented by the client.
-    virtual status_t queueBuffer(int slot, int64_t timestamp) = 0;
+    //
+    // outWidth, outHeight and outTransform are filled with the default width
+    // and height of the window and current transform applied to buffers,
+    // respectively.
+    virtual status_t queueBuffer(int slot, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
 
     // cancelBuffer indicates that the client does not wish to fill in the
     // buffer associated with slot and transfers ownership of the slot back to
@@ -87,12 +92,7 @@
 
     virtual status_t setCrop(const Rect& reg) = 0;
     virtual status_t setTransform(uint32_t transform) = 0;
-
-    // getAllocator retrieves the binder object that must be referenced as long
-    // as the GraphicBuffers dequeued from this ISurfaceTexture are referenced.
-    // Holding this binder reference prevents SurfaceFlinger from freeing the
-    // buffers before the client is done with them.
-    virtual sp<IBinder> getAllocator() = 0;
+    virtual status_t setScalingMode(int mode) = 0;
 
     // query retrieves some information for this surface
     // 'what' tokens allowed are that of android_natives.h
@@ -104,6 +104,24 @@
     // queued buffers will be retired in order.
     // The default mode is asynchronous.
     virtual status_t setSynchronousMode(bool enabled) = 0;
+
+    // connect attempts to connect a client API to the SurfaceTexture.  This
+    // must be called before any other ISurfaceTexture methods are called except
+    // for getAllocator.
+    //
+    // This method will fail if the connect was previously called on the
+    // SurfaceTexture and no corresponding disconnect call was made.
+    virtual status_t connect(int api) = 0;
+
+    // disconnect attempts to disconnect a client API from the SurfaceTexture.
+    // Calling this method will cause any subsequent calls to other
+    // ISurfaceTexture methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the SurfaceTexture is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index e36360c..2a8e725 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -44,6 +44,7 @@
         MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
     };
     enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
 
     struct FrameAvailableListener : public virtual RefBase {
         // onFrameAvailable() is called from queueBuffer() each time an
@@ -68,7 +69,7 @@
     // SurfaceTexture object (i.e. they are not owned by the client).
     virtual status_t setBufferCount(int bufferCount);
 
-    virtual sp<GraphicBuffer> requestBuffer(int buf);
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
 
     // dequeueBuffer gets the next buffer slot index for the client to use. If a
     // buffer slot is available then that slot index is written to the location
@@ -83,10 +84,12 @@
     // nanoseconds, and must be monotonically increasing. Its other semantics
     // (zero point, etc) are client-dependent and should be documented by the
     // client.
-    virtual status_t queueBuffer(int buf, int64_t timestamp);
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
     virtual void cancelBuffer(int buf);
     virtual status_t setCrop(const Rect& reg);
     virtual status_t setTransform(uint32_t transform);
+    virtual status_t setScalingMode(int mode);
 
     virtual int query(int what, int* value);
 
@@ -97,6 +100,24 @@
     // The default mode is asynchronous.
     virtual status_t setSynchronousMode(bool enabled);
 
+    // connect attempts to connect a client API to the SurfaceTexture.  This
+    // must be called before any other ISurfaceTexture methods are called except
+    // for getAllocator.
+    //
+    // This method will fail if the connect was previously called on the
+    // SurfaceTexture and no corresponding disconnect call was made.
+    virtual status_t connect(int api);
+
+    // disconnect attempts to disconnect a client API from the SurfaceTexture.
+    // Calling this method will cause any subsequent calls to other
+    // ISurfaceTexture methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the SurfaceTexture is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api);
+
     // updateTexImage sets the image contents of the target texture to that of
     // the most recently queued buffer.
     //
@@ -166,6 +187,20 @@
     // getCurrentTransform returns the transform of the current buffer
     uint32_t getCurrentTransform() const;
 
+    // getCurrentScalingMode returns the scaling mode of the current buffer
+    uint32_t getCurrentScalingMode() const;
+
+    // abandon frees all the buffers and puts the SurfaceTexture into the
+    // 'abandoned' state.  Once put in this state the SurfaceTexture can never
+    // leave it.  When in the 'abandoned' state, all methods of the
+    // ISurfaceTexture interface will fail with the NO_INIT error.
+    //
+    // Note that while calling this method causes all the buffers to be freed
+    // from the perspective of the the SurfaceTexture, if there are additional
+    // references on the buffers (e.g. if a buffer is referenced by a client or
+    // by OpenGL ES as a texture) then those buffer will remain allocated.
+    void abandon();
+
     // dump our state in a String
     void dump(String8& result) const;
     void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
@@ -176,7 +211,6 @@
     // all slots.
     void freeAllBuffers();
     static bool isExternalFormat(uint32_t format);
-    static GLenum getTextureTarget(uint32_t format);
 
 private:
 
@@ -201,6 +235,7 @@
               mBufferState(BufferSlot::FREE),
               mRequestBufferCalled(false),
               mTransform(0),
+              mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
               mTimestamp(0) {
             mCrop.makeInvalid();
         }
@@ -262,6 +297,11 @@
         // slot.
         uint32_t mTransform;
 
+        // mScalingMode is the current scaling mode for this buffer slot. This
+        // gets set to mNextScalingMode each time queueBuffer gets called for
+        // this slot.
+        uint32_t mScalingMode;
+
         // mTimestamp is the current timestamp for this buffer slot. This gets
         // to set by queueBuffer each time this slot is queued.
         int64_t mTimestamp;
@@ -307,31 +347,30 @@
     // reset mCurrentTexture to INVALID_BUFFER_SLOT.
     int mCurrentTexture;
 
-    // mCurrentTextureTarget is the GLES texture target to be used with the
-    // current texture.
-    GLenum mCurrentTextureTarget;
-
     // mCurrentTextureBuf is the graphic buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
-    // must track it separately in order to properly use
-    // IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
+    // must track it separately in order to support the getCurrentBuffer method.
     sp<GraphicBuffer> mCurrentTextureBuf;
 
     // mCurrentCrop is the crop rectangle that applies to the current texture.
-    // It gets set to mLastQueuedCrop each time updateTexImage is called.
+    // It gets set each time updateTexImage is called.
     Rect mCurrentCrop;
 
     // mCurrentTransform is the transform identifier for the current texture. It
-    // gets set to mLastQueuedTransform each time updateTexImage is called.
+    // gets set each time updateTexImage is called.
     uint32_t mCurrentTransform;
 
+    // mCurrentScalingMode is the scaling mode for the current texture. It gets
+    // set to each time updateTexImage is called.
+    uint32_t mCurrentScalingMode;
+
     // mCurrentTransformMatrix is the transform matrix for the current texture.
     // It gets computed by computeTransformMatrix each time updateTexImage is
     // called.
     float mCurrentTransformMatrix[16];
 
     // mCurrentTimestamp is the timestamp for the current texture. It
-    // gets set to mLastQueuedTimestamp each time updateTexImage is called.
+    // gets set each time updateTexImage is called.
     int64_t mCurrentTimestamp;
 
     // mNextCrop is the crop rectangle that will be used for the next buffer
@@ -342,6 +381,10 @@
     // buffer that gets queued. It is set by calling setTransform.
     uint32_t mNextTransform;
 
+    // mNextScalingMode is the scaling mode that will be used for the next
+    // buffers that get queued. It is set by calling setScalingMode.
+    int mNextScalingMode;
+
     // mTexName is the name of the OpenGL texture to which streamed images will
     // be bound when updateTexImage is called. It is set at construction time
     // changed with a call to setTexName.
@@ -362,6 +405,11 @@
     // mAllowSynchronousMode whether we allow synchronous mode or not
     const bool mAllowSynchronousMode;
 
+    // mConnectedApi indicates the API that is currently connected to this
+    // SurfaceTexture.  It defaults to NO_CONNECTED_API (= 0), and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
     // mDequeueCondition condition used for dequeueBuffer in synchronous mode
     mutable Condition mDequeueCondition;
 
@@ -369,6 +417,13 @@
     typedef Vector<int> Fifo;
     Fifo mQueue;
 
+    // mAbandoned indicates that the SurfaceTexture will no longer be used to
+    // consume images buffers pushed to it using the ISurfaceTexture interface.
+    // It is initialized to false, and set to true in the abandon method.  A
+    // SurfaceTexture that has been abandoned will return the NO_INIT error from
+    // all ISurfaceTexture methods capable of returning an error.
+    bool mAbandoned;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 9db7364..57f9e15 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -21,6 +21,7 @@
 #include <gui/SurfaceTexture.h>
 
 #include <ui/egl/android_natives.h>
+#include <ui/Region.h>
 
 #include <utils/RefBase.h>
 #include <utils/threads.h>
@@ -37,29 +38,24 @@
 
     sp<ISurfaceTexture> getISurfaceTexture() const;
 
-private:
-    friend class Surface;
+protected:
+    SurfaceTextureClient();
+    void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
 
+private:
     // can't be copied
     SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
     SurfaceTextureClient(const SurfaceTextureClient& rhs);
+    void init();
 
     // ANativeWindow hooks
-    static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
-    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int perform(ANativeWindow* window, int operation, ...);
-    static int query(const ANativeWindow* window, int what, int* value);
-    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int setSwapInterval(ANativeWindow* window, int interval);
-
-    int cancelBuffer(ANativeWindowBuffer* buffer);
-    int dequeueBuffer(ANativeWindowBuffer** buffer);
-    int lockBuffer(ANativeWindowBuffer* buffer);
-    int perform(int operation, va_list args);
-    int query(int what, int* value) const;
-    int queueBuffer(ANativeWindowBuffer* buffer);
-    int setSwapInterval(int interval);
+    static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+    static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_perform(ANativeWindow* window, int operation, ...);
+    static int hook_query(const ANativeWindow* window, int what, int* value);
+    static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_setSwapInterval(ANativeWindow* window, int interval);
 
     int dispatchConnect(va_list args);
     int dispatchDisconnect(va_list args);
@@ -67,39 +63,49 @@
     int dispatchSetBuffersGeometry(va_list args);
     int dispatchSetBuffersDimensions(va_list args);
     int dispatchSetBuffersFormat(va_list args);
+    int dispatchSetScalingMode(va_list args);
     int dispatchSetBuffersTransform(va_list args);
     int dispatchSetBuffersTimestamp(va_list args);
     int dispatchSetCrop(va_list args);
     int dispatchSetUsage(va_list args);
+    int dispatchLock(va_list args);
+    int dispatchUnlockAndPost(va_list args);
 
-    int connect(int api);
-    int disconnect(int api);
-    int setBufferCount(int bufferCount);
-    int setBuffersDimensions(int w, int h);
-    int setBuffersFormat(int format);
-    int setBuffersTransform(int transform);
-    int setBuffersTimestamp(int64_t timestamp);
-    int setCrop(Rect const* rect);
-    int setUsage(uint32_t reqUsage);
+protected:
+    virtual int cancelBuffer(ANativeWindowBuffer* buffer);
+    virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
+    virtual int lockBuffer(ANativeWindowBuffer* buffer);
+    virtual int perform(int operation, va_list args);
+    virtual int query(int what, int* value) const;
+    virtual int queueBuffer(ANativeWindowBuffer* buffer);
+    virtual int setSwapInterval(int interval);
 
-    void freeAllBuffers();
-    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
-
-    int getConnectedApi() const;
+    virtual int connect(int api);
+    virtual int disconnect(int api);
+    virtual int setBufferCount(int bufferCount);
+    virtual int setBuffersDimensions(int w, int h);
+    virtual int setBuffersFormat(int format);
+    virtual int setScalingMode(int mode);
+    virtual int setBuffersTransform(int transform);
+    virtual int setBuffersTimestamp(int64_t timestamp);
+    virtual int setCrop(Rect const* rect);
+    virtual int setUsage(uint32_t reqUsage);
+    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+    virtual int unlockAndPost();
 
     enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
     enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
     enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
 
+private:
+    void freeAllBuffers();
+    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
     // mSurfaceTexture is the interface to the surface texture server. All
     // operations on the surface texture client ultimately translate into
     // interactions with the server using this interface.
     sp<ISurfaceTexture> mSurfaceTexture;
 
-    // mAllocator is the binder object that is referenced to prevent the
-    // dequeued buffers from being freed prematurely.
-    sp<IBinder> mAllocator;
-
     // mSlots stores the buffers that have been allocated for each buffer slot.
     // It is initialized to null pointers, and gets filled in with the result of
     // ISurfaceTexture::requestBuffer when the client dequeues a buffer from a
@@ -129,25 +135,28 @@
     // a timestamp is auto-generated when queueBuffer is called.
     int64_t mTimestamp;
 
-    // mConnectedApi holds the currently connected API to this surface
-    int mConnectedApi;
+    // mDefaultWidth is default width of the window, regardless of the
+    // native_window_set_buffers_dimensions call
+    uint32_t mDefaultWidth;
 
-    // mQueryWidth is the width returned by query(). It is set to width
-    // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
-    uint32_t mQueryWidth;
+    // mDefaultHeight is default width of the window, regardless of the
+    // native_window_set_buffers_dimensions call
+    uint32_t mDefaultHeight;
 
-    // mQueryHeight is the height returned by query(). It is set to height
-    // of the last dequeued buffer or to mReqHeight if no buffer was dequeued.
-    uint32_t mQueryHeight;
-
-    // mQueryFormat is the format returned by query(). It is set to the last
-    // dequeued format or to mReqFormat if no buffer was dequeued.
-    uint32_t mQueryFormat;
+    // mTransformHint is the transform probably applied to buffers of this
+    // window. this is only a hint, actual transform may differ.
+    uint32_t mTransformHint;
 
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
     mutable Mutex mMutex;
+
+    // must be used from the lock/unlock thread
+    sp<GraphicBuffer>           mLockedBuffer;
+    sp<GraphicBuffer>           mPostedBuffer;
+    mutable Region              mOldDirtyRegion;
+    bool                        mConnectedToCpu;
 };
 
 }; // namespace android
diff --git a/include/private/binder/binder_module.h b/include/private/binder/binder_module.h
index fdf327e..a8dd64f 100644
--- a/include/private/binder/binder_module.h
+++ b/include/private/binder/binder_module.h
@@ -21,126 +21,11 @@
 namespace android {
 #endif
 
-#if defined(HAVE_ANDROID_OS)
-
 /* obtain structures and constants from the kernel header */
 
 #include <sys/ioctl.h>
 #include <linux/binder.h>
 
-#else
-
-/* Some parts of the simulator need fake versions of this 
- * stuff in order to compile.  Really this should go away
- * entirely...
- */
-
-#define BINDER_CURRENT_PROTOCOL_VERSION 7
-
-#define BINDER_TYPE_BINDER 1
-#define BINDER_TYPE_WEAK_BINDER 2
-#define BINDER_TYPE_HANDLE 3
-#define BINDER_TYPE_WEAK_HANDLE 4
-#define BINDER_TYPE_FD 5
-
-struct flat_binder_object {
-    unsigned long type;
-    unsigned long flags;
-    union {
-        void *binder;
-        signed long handle;
-    };
-    void *cookie;
-};
-
-struct binder_write_read {
-    signed long write_size;
-    signed long write_consumed;
-    unsigned long write_buffer;
-    signed long read_size;
-    signed long read_consumed;
-    unsigned long read_buffer;
-};
-
-struct binder_transaction_data {
-    union {
-        size_t handle;
-        void *ptr;
-    } target;
-    void *cookie;
-    unsigned int code;
-    
-    unsigned int flags;
-    pid_t sender_pid;
-    uid_t sender_euid;
-    size_t data_size;
-    size_t offsets_size;
-    
-    union {
-        struct {
-            const void *buffer;
-            const void *offsets;
-        } ptr;
-        uint8_t buf[8];
-    } data;
-};
-
-enum transaction_flags {
-    TF_ONE_WAY = 0x01,
-    TF_ROOT_OBJECT = 0x04,
-    TF_STATUS_CODE = 0x08,
-    TF_ACCEPT_FDS = 0x10,
-};
-
-
-enum {
-    FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
-    FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
-};
-
-enum BinderDriverReturnProtocol {
-    BR_ERROR,
-    BR_OK,
-    BR_TRANSACTION,
-    BR_REPLY,
-    BR_ACQUIRE_RESULT,
-    BR_DEAD_REPLY,
-    BR_TRANSACTION_COMPLETE,
-    BR_INCREFS,
-    BR_ACQUIRE,
-    BR_RELEASE,
-    BR_DECREFS,
-    BR_ATTEMPT_ACQUIRE,
-    BR_NOOP,
-    BR_SPAWN_LOOPER,
-    BR_FINISHED,
-    BR_DEAD_BINDER,
-    BR_CLEAR_DEATH_NOTIFICATION_DONE,
-    BR_FAILED_REPLY,
-};
-
-enum BinderDriverCommandProtocol {
-    BC_TRANSACTION,
-    BC_REPLY,
-    BC_ACQUIRE_RESULT,
-    BC_FREE_BUFFER,
-    BC_INCREFS,
-    BC_ACQUIRE,
-    BC_RELEASE,
-    BC_DECREFS,
-    BC_INCREFS_DONE,
-    BC_ACQUIRE_DONE,
-    BC_ATTEMPT_ACQUIRE,
-    BC_REGISTER_LOOPER,
-    BC_ENTER_LOOPER,
-    BC_EXIT_LOOPER,
-    BC_REQUEST_DEATH_NOTIFICATION,
-    BC_CLEAR_DEATH_NOTIFICATION,
-    BC_DEAD_BINDER_DONE,
-};
-
-#endif
-
 #ifdef __cplusplus
 }   // namespace android
 #endif
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 6e9a654..02cabc1 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -45,9 +45,6 @@
     struct surface_data_t {
         int32_t             token;
         int32_t             identity;
-        uint32_t            width;
-        uint32_t            height;
-        uint32_t            format;
         status_t readFromParcel(const Parcel& parcel);
         status_t writeToParcel(Parcel* parcel) const;
     };
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index dc2a845..0460bbd 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -28,6 +28,8 @@
 #include <ui/Region.h>
 #include <ui/egl/android_natives.h>
 
+#include <gui/SurfaceTextureClient.h>
+
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceComposerClient.h>
 
@@ -37,14 +39,9 @@
 
 // ---------------------------------------------------------------------------
 
-class GraphicBuffer;
-class GraphicBufferMapper;
-class IOMX;
 class ISurfaceTexture;
-class Rect;
 class Surface;
 class SurfaceComposerClient;
-class SurfaceTextureClient;
 
 // ---------------------------------------------------------------------------
 
@@ -60,7 +57,6 @@
     static bool isSameSurface(
             const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
         
-    uint32_t    getFlags() const { return mFlags; }
     uint32_t    getIdentity() const { return mIdentity; }
 
     // release surface data from java
@@ -89,25 +85,13 @@
     SurfaceControl& operator = (SurfaceControl& rhs);
     SurfaceControl(const SurfaceControl& rhs);
 
-    
     friend class SurfaceComposerClient;
-
-    // camera and camcorder need access to the ISurface binder interface for preview
-    friend class CameraService;
-    friend class MediaRecorder;
-    // mediaplayer needs access to ISurface for display
-    friend class MediaPlayer;
-    // for testing
-    friend class Test;
-    // videoEditor preview classes
-    friend class VideoEditorPreviewController;
     friend class Surface;
 
     SurfaceControl(
             const sp<SurfaceComposerClient>& client,
             const sp<ISurface>& surface,
-            const ISurfaceComposerClient::surface_data_t& data,
-            uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
+            const ISurfaceComposerClient::surface_data_t& data);
 
     ~SurfaceControl();
 
@@ -118,10 +102,6 @@
     sp<ISurface>                mSurface;
     SurfaceID                   mToken;
     uint32_t                    mIdentity;
-    uint32_t                    mWidth;
-    uint32_t                    mHeight;
-    PixelFormat                 mFormat;
-    uint32_t                    mFlags;
     mutable Mutex               mLock;
     
     mutable sp<Surface>         mSurfaceData;
@@ -129,8 +109,7 @@
     
 // ---------------------------------------------------------------------------
 
-class Surface 
-    : public EGLNativeBase<ANativeWindow, Surface, RefBase>
+class Surface : public SurfaceTextureClient
 {
 public:
     struct SurfaceInfo {
@@ -143,112 +122,50 @@
         uint32_t    reserved[2];
     };
 
-    static status_t writeToParcel(
-            const sp<Surface>& control, Parcel* parcel);
+    explicit Surface(const sp<ISurfaceTexture>& st);
+
+    static status_t writeToParcel(const sp<Surface>& control, Parcel* parcel);
 
     static sp<Surface> readFromParcel(const Parcel& data);
-
     static bool isValid(const sp<Surface>& surface) {
         return (surface != 0) && surface->isValid();
     }
 
     bool        isValid();
-    uint32_t    getFlags() const    { return mFlags; }
     uint32_t    getIdentity() const { return mIdentity; }
     sp<ISurfaceTexture> getSurfaceTexture();
 
     // the lock/unlock APIs must be used from the same thread
-    status_t    lock(SurfaceInfo* info, bool blocking = true);
-    status_t    lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+    status_t    lock(SurfaceInfo* info, Region* dirty = NULL);
     status_t    unlockAndPost();
 
     sp<IBinder> asBinder() const;
 
 private:
-    /*
-     * Android frameworks friends
-     * (eventually this should go away and be replaced by proper APIs)
-     */
-    // camera and camcorder need access to the ISurface binder interface for preview
-    friend class CameraService;
-    friend class MediaRecorder;
-    // MediaPlayer needs access to ISurface for display
-    friend class MediaPlayer;
-    friend class IOMX;
-    friend class SoftwareRenderer;
     // this is just to be able to write some unit tests
     friend class Test;
-    // videoEditor preview classes
-    friend class VideoEditorPreviewController;
-    friend class PreviewRenderer;
-
-private:
-    friend class SurfaceComposerClient;
     friend class SurfaceControl;
 
     // can't be copied
     Surface& operator = (Surface& rhs);
     Surface(const Surface& rhs);
 
-    Surface(const sp<SurfaceControl>& control);
+    explicit Surface(const sp<SurfaceControl>& control);
     Surface(const Parcel& data, const sp<IBinder>& ref);
     ~Surface();
 
-
-    /*
-     *  ANativeWindow hooks
-     */
-    static int setSwapInterval(ANativeWindow* window, int interval);
-    static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
-    static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int query(const ANativeWindow* window, int what, int* value);
-    static int perform(ANativeWindow* window, int operation, ...);
-
-    int setSwapInterval(int interval);
-    int dequeueBuffer(ANativeWindowBuffer** buffer);
-    int lockBuffer(ANativeWindowBuffer* buffer);
-    int queueBuffer(ANativeWindowBuffer* buffer);
-    int cancelBuffer(ANativeWindowBuffer* buffer);
-    int query(int what, int* value) const;
-    int perform(int operation, va_list args);
-
     /*
      *  private stuff...
      */
-    void init();
-    status_t validate(bool inCancelBuffer = false) const;
+    void init(const sp<ISurfaceTexture>& surfaceTexture);
 
-    int getConnectedApi() const;
-    
     static void cleanCachedSurfacesLocked();
 
+    virtual int query(int what, int* value) const;
+
     // constants
-    status_t                    mInitCheck;
     sp<ISurface>                mSurface;
-    sp<SurfaceTextureClient>    mSurfaceTextureClient;
     uint32_t                    mIdentity;
-    PixelFormat                 mFormat;
-    uint32_t                    mFlags;
-    
-    // protected by mSurfaceLock. These are also used from lock/unlock
-    // but in that case, they must be called form the same thread.
-    mutable Region              mDirtyRegion;
-
-    // must be used from the lock/unlock thread
-    sp<GraphicBuffer>           mLockedBuffer;
-    sp<GraphicBuffer>           mPostedBuffer;
-    mutable Region              mOldDirtyRegion;
-    bool                        mReserved;
-
-    // query() must be called from dequeueBuffer() thread
-    uint32_t                    mWidth;
-    uint32_t                    mHeight;
-
-    // Inherently thread-safe
-    mutable Mutex               mSurfaceLock;
-    mutable Mutex               mApiLock;
 
     // A cache of Surface objects that have been deserialized into this process.
     static Mutex sCachedSurfacesLock;
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index f46f25c..848c5a1 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -55,7 +55,7 @@
 
     PIXEL_FORMAT_OPAQUE         = -1,
         // System chooses an opaque format (no alpha bits required)
-    
+
     // real pixel formats supported for rendering -----------------------------
 
     PIXEL_FORMAT_RGBA_8888   = HAL_PIXEL_FORMAT_RGBA_8888,  // 4x8-bit RGBA
@@ -84,7 +84,7 @@
         INDEX_GREEN   = 2,
         INDEX_BLUE    = 3
     };
-    
+
     enum { // components
         ALPHA               = 1,
         RGB                 = 2,
@@ -98,10 +98,10 @@
         uint8_t h;
         uint8_t l;
     };
-    
+
     inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
     size_t getScanlineSize(unsigned int width) const;
-    size_t getSize(size_t ci) const { 
+    size_t getSize(size_t ci) const {
         return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
     }
     size_t      version;
@@ -112,7 +112,7 @@
         szinfo      cinfo[4];
         struct {
             uint8_t     h_alpha;
-            uint8_t     l_alpha;    
+            uint8_t     l_alpha;
             uint8_t     h_red;
             uint8_t     l_red;
             uint8_t     h_green;
diff --git a/include/utils/Pool.h b/include/utils/Pool.h
deleted file mode 100644
index 2ee768e..0000000
--- a/include/utils/Pool.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef UTILS_POOL_H
-#define UTILS_POOL_H
-
-#include <utils/TypeHelpers.h>
-
-namespace android {
-
-class PoolImpl {
-public:
-    PoolImpl(size_t objSize);
-    ~PoolImpl();
-
-    void* allocImpl();
-    void freeImpl(void* obj);
-
-private:
-    size_t mObjSize;
-};
-
-/*
- * A homogeneous typed memory pool for fixed size objects.
- * Not intended to be thread-safe.
- */
-template<typename T>
-class Pool : private PoolImpl {
-public:
-    /* Creates an initially empty pool. */
-    Pool() : PoolImpl(sizeof(T)) { }
-
-    /* Destroys the pool.
-     * Assumes that the pool is empty. */
-    ~Pool() { }
-
-    /* Allocates an object from the pool, growing the pool if needed. */
-    inline T* alloc() {
-        void* mem = allocImpl();
-        if (! traits<T>::has_trivial_ctor) {
-            return new (mem) T();
-        } else {
-            return static_cast<T*>(mem);
-        }
-    }
-
-    /* Frees an object from the pool. */
-    inline void free(T* obj) {
-        if (! traits<T>::has_trivial_dtor) {
-            obj->~T();
-        }
-        freeImpl(obj);
-    }
-};
-
-} // namespace android
-
-#endif // UTILS_POOL_H
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 3a99979..547e36a 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -38,6 +38,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <time.h>
 
 namespace android {
 
@@ -174,6 +175,20 @@
         size_t uncompLen, size_t compLen);
 
     /*
+     * Utility function to convert ZIP's time format to a timespec struct.
+     */
+    static inline void zipTimeToTimespec(long when, struct tm* timespec) {
+        const long date = when >> 16;
+        timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
+        timespec->tm_mon = (date >> 5) & 0x0F;
+        timespec->tm_mday = date & 0x1F;
+
+        timespec->tm_hour = (when >> 11) & 0x1F;
+        timespec->tm_min = (when >> 5) & 0x3F;
+        timespec->tm_sec = (when & 0x1F) << 1;
+    }
+
+    /*
      * Some basic functions for raw data manipulation.  "LE" means
      * Little Endian.
      */
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 7264ac4..f5288c8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -154,11 +154,7 @@
         mBinderContextUserData = userData;
 
         int dummy = 0;
-#if defined(HAVE_ANDROID_OS)
         status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
-#else
-        status_t result = INVALID_OPERATION;
-#endif
         if (result == 0) {
             mManagesContexts = true;
         } else if (result == -1) {
@@ -304,12 +300,7 @@
     if (fd >= 0) {
         fcntl(fd, F_SETFD, FD_CLOEXEC);
         int vers;
-#if defined(HAVE_ANDROID_OS)
         status_t result = ioctl(fd, BINDER_VERSION, &vers);
-#else
-        status_t result = -1;
-        errno = EPERM;
-#endif
         if (result == -1) {
             LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
             close(fd);
@@ -320,14 +311,11 @@
             close(fd);
             fd = -1;
         }
-#if defined(HAVE_ANDROID_OS)
         size_t maxThreads = 15;
         result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
         if (result == -1) {
             LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
         }
-#endif
-        
     } else {
         LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
     }
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index bc97cac..ace16aa 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -132,9 +132,6 @@
 {
     token    = parcel.readInt32();
     identity = parcel.readInt32();
-    width    = parcel.readInt32();
-    height   = parcel.readInt32();
-    format   = parcel.readInt32();
     return NO_ERROR;
 }
 
@@ -142,9 +139,6 @@
 {
     parcel->writeInt32(token);
     parcel->writeInt32(identity);
-    parcel->writeInt32(width);
-    parcel->writeInt32(height);
-    parcel->writeInt32(format);
     return NO_ERROR;
 }
 
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 16e3780..55246dc 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -38,9 +38,11 @@
     CANCEL_BUFFER,
     SET_CROP,
     SET_TRANSFORM,
-    GET_ALLOCATOR,
     QUERY,
     SET_SYNCHRONOUS_MODE,
+    CONNECT,
+    DISCONNECT,
+    SET_SCALING_MODE,
 };
 
 
@@ -52,18 +54,18 @@
     {
     }
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx) {
+    virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(bufferIdx);
         remote()->transact(REQUEST_BUFFER, data, &reply);
-        sp<GraphicBuffer> buffer;
         bool nonNull = reply.readInt32();
         if (nonNull) {
-            buffer = new GraphicBuffer();
-            reply.read(*buffer);
+            *buf = new GraphicBuffer();
+            reply.read(**buf);
         }
-        return buffer;
+        status_t result = reply.readInt32();
+        return result;
     }
 
     virtual status_t setBufferCount(int bufferCount)
@@ -90,12 +92,16 @@
         return result;
     }
 
-    virtual status_t queueBuffer(int buf, int64_t timestamp) {
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(buf);
         data.writeInt64(timestamp);
         remote()->transact(QUEUE_BUFFER, data, &reply);
+        *outWidth = reply.readInt32();
+        *outHeight = reply.readInt32();
+        *outTransform = reply.readInt32();
         status_t result = reply.readInt32();
         return result;
     }
@@ -128,11 +134,13 @@
         return result;
     }
 
-    virtual sp<IBinder> getAllocator() {
+    virtual status_t setScalingMode(int mode) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
-        remote()->transact(GET_ALLOCATOR, data, &reply);
-        return reply.readStrongBinder();
+        data.writeInt32(mode);
+        remote()->transact(SET_SCALING_MODE, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
     }
 
     virtual int query(int what, int* value) {
@@ -154,7 +162,23 @@
         return result;
     }
 
+    virtual status_t connect(int api) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(api);
+        remote()->transact(CONNECT, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
 
+    virtual status_t disconnect(int api) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(api);
+        remote()->transact(DISCONNECT, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture");
@@ -168,11 +192,13 @@
         case REQUEST_BUFFER: {
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             int bufferIdx   = data.readInt32();
-            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx));
+            sp<GraphicBuffer> buffer;
+            int result = requestBuffer(bufferIdx, &buffer);
             reply->writeInt32(buffer != 0);
             if (buffer != 0) {
                 reply->write(*buffer);
             }
+            reply->writeInt32(result);
             return NO_ERROR;
         } break;
         case SET_BUFFER_COUNT: {
@@ -198,7 +224,12 @@
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             int buf = data.readInt32();
             int64_t timestamp = data.readInt64();
-            status_t result = queueBuffer(buf, timestamp);
+            uint32_t outWidth, outHeight, outTransform;
+            status_t result = queueBuffer(buf, timestamp,
+                    &outWidth, &outHeight, &outTransform);
+            reply->writeInt32(outWidth);
+            reply->writeInt32(outHeight);
+            reply->writeInt32(outTransform);
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
@@ -226,10 +257,11 @@
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
-        case GET_ALLOCATOR: {
+        case SET_SCALING_MODE: {
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
-            sp<IBinder> result = getAllocator();
-            reply->writeStrongBinder(result);
+            int mode = data.readInt32();
+            status_t result = setScalingMode(mode);
+            reply->writeInt32(result);
             return NO_ERROR;
         } break;
         case QUERY: {
@@ -248,6 +280,20 @@
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
+        case CONNECT: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int api = data.readInt32();
+            status_t res = connect(api);
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
+        case DISCONNECT: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int api = data.readInt32();
+            status_t res = disconnect(api);
+            reply->writeInt32(res);
+            return NO_ERROR;
+        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9185e1e..ccf98e5 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -26,15 +26,12 @@
 #include <utils/Log.h>
 #include <utils/threads.h>
 
-#include <binder/IMemory.h>
 #include <binder/IPCThreadState.h>
 
 #include <gui/SurfaceTextureClient.h>
 
 #include <ui/DisplayInfo.h>
 #include <ui/GraphicBuffer.h>
-#include <ui/GraphicBufferMapper.h>
-#include <ui/GraphicLog.h>
 #include <ui/Rect.h>
 
 #include <surfaceflinger/ISurface.h>
@@ -42,63 +39,8 @@
 #include <surfaceflinger/Surface.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 
-#include <private/surfaceflinger/LayerState.h>
-
 namespace android {
 
-// ----------------------------------------------------------------------
-
-static status_t copyBlt(
-        const sp<GraphicBuffer>& dst, 
-        const sp<GraphicBuffer>& src, 
-        const Region& reg)
-{
-    // src and dst with, height and format must be identical. no verification
-    // is done here.
-    status_t err;
-    uint8_t const * src_bits = NULL;
-    err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
-    LOGE_IF(err, "error locking src buffer %s", strerror(-err));
-
-    uint8_t* dst_bits = NULL;
-    err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
-    LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
-
-    Region::const_iterator head(reg.begin());
-    Region::const_iterator tail(reg.end());
-    if (head != tail && src_bits && dst_bits) {
-        const size_t bpp = bytesPerPixel(src->format);
-        const size_t dbpr = dst->stride * bpp;
-        const size_t sbpr = src->stride * bpp;
-
-        while (head != tail) {
-            const Rect& r(*head++);
-            ssize_t h = r.height();
-            if (h <= 0) continue;
-            size_t size = r.width() * bpp;
-            uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
-            uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
-            if (dbpr==sbpr && size==sbpr) {
-                size *= h;
-                h = 1;
-            }
-            do {
-                memcpy(d, s, size);
-                d += dbpr;
-                s += sbpr;
-            } while (--h > 0);
-        }
-    }
-    
-    if (src_bits)
-        src->unlock();
-    
-    if (dst_bits)
-        dst->unlock();
-    
-    return err;
-}
-
 // ============================================================================
 //  SurfaceControl
 // ============================================================================
@@ -106,12 +48,9 @@
 SurfaceControl::SurfaceControl(
         const sp<SurfaceComposerClient>& client, 
         const sp<ISurface>& surface,
-        const ISurfaceComposerClient::surface_data_t& data,
-        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+        const ISurfaceComposerClient::surface_data_t& data)
     : mClient(client), mSurface(surface),
-      mToken(data.token), mIdentity(data.identity),
-      mWidth(data.width), mHeight(data.height), mFormat(data.format),
-      mFlags(flags)
+      mToken(data.token), mIdentity(data.identity)
 {
 }
         
@@ -240,24 +179,13 @@
 {
     sp<ISurface> sur;
     uint32_t identity = 0;
-    uint32_t width = 0;
-    uint32_t height = 0;
-    uint32_t format = 0;
-    uint32_t flags = 0;
     if (SurfaceControl::isValid(control)) {
         sur      = control->mSurface;
         identity = control->mIdentity;
-        width    = control->mWidth;
-        height   = control->mHeight;
-        format   = control->mFormat;
-        flags    = control->mFlags;
     }
     parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+    parcel->writeStrongBinder(NULL);  // NULL ISurfaceTexture in this case.
     parcel->writeInt32(identity);
-    parcel->writeInt32(width);
-    parcel->writeInt32(height);
-    parcel->writeInt32(format);
-    parcel->writeInt32(flags);
     return NO_ERROR;
 }
 
@@ -265,7 +193,8 @@
 {
     Mutex::Autolock _l(mLock);
     if (mSurfaceData == 0) {
-        mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+        sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
+        mSurfaceData = new Surface(surface_control);
     }
     return mSurfaceData;
 }
@@ -277,57 +206,63 @@
 // ---------------------------------------------------------------------------
 
 Surface::Surface(const sp<SurfaceControl>& surface)
-    : mInitCheck(NO_INIT),
+    : SurfaceTextureClient(),
       mSurface(surface->mSurface),
-      mIdentity(surface->mIdentity),
-      mFormat(surface->mFormat), mFlags(surface->mFlags),
-      mWidth(surface->mWidth), mHeight(surface->mHeight)
+      mIdentity(surface->mIdentity)
 {
-    init();
+    sp<ISurfaceTexture> st;
+    if (mSurface != NULL) {
+        st = mSurface->getSurfaceTexture();
+    }
+    init(st);
 }
 
 Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
-    : mInitCheck(NO_INIT)
+    : SurfaceTextureClient()
 {
-    mSurface    = interface_cast<ISurface>(ref);
+    mSurface = interface_cast<ISurface>(ref);
+    sp<IBinder> st_binder(parcel.readStrongBinder());
+    sp<ISurfaceTexture> st;
+    if (st_binder != NULL) {
+        st = interface_cast<ISurfaceTexture>(st_binder);
+    } else if (mSurface != NULL) {
+        st = mSurface->getSurfaceTexture();
+    }
+
     mIdentity   = parcel.readInt32();
-    mWidth      = parcel.readInt32();
-    mHeight     = parcel.readInt32();
-    mFormat     = parcel.readInt32();
-    mFlags      = parcel.readInt32();
-    init();
+    init(st);
+}
+
+Surface::Surface(const sp<ISurfaceTexture>& st)
+    : SurfaceTextureClient(),
+      mSurface(NULL),
+      mIdentity(0)
+{
+    init(st);
 }
 
 status_t Surface::writeToParcel(
         const sp<Surface>& surface, Parcel* parcel)
 {
     sp<ISurface> sur;
+    sp<ISurfaceTexture> st;
     uint32_t identity = 0;
-    uint32_t width = 0;
-    uint32_t height = 0;
-    uint32_t format = 0;
-    uint32_t flags = 0;
     if (Surface::isValid(surface)) {
         sur      = surface->mSurface;
+        st       = surface->getISurfaceTexture();
         identity = surface->mIdentity;
-        width    = surface->mWidth;
-        height   = surface->mHeight;
-        format   = surface->mFormat;
-        flags    = surface->mFlags;
-    } else if (surface != 0 && surface->mSurface != 0) {
-        LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
-             "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
-             "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
-             surface->mSurface.get(), surface->mIdentity, surface->mWidth,
-             surface->mHeight, surface->mFormat, surface->mFlags,
-             surface->mInitCheck);
+    } else if (surface != 0 &&
+            (surface->mSurface != NULL ||
+             surface->getISurfaceTexture() != NULL)) {
+        LOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: "
+             "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ",
+             surface->mSurface.get(), surface->getISurfaceTexture().get(),
+             surface->mIdentity);
     }
-    parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+
+    parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
+    parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
     parcel->writeInt32(identity);
-    parcel->writeInt32(width);
-    parcel->writeInt32(height);
-    parcel->writeInt32(format);
-    parcel->writeInt32(flags);
     return NO_ERROR;
 
 }
@@ -343,8 +278,8 @@
        surface = new Surface(data, binder);
        sCachedSurfaces.add(binder, surface);
     }
-    if (surface->mSurface == 0) {
-      surface = 0;
+    if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
+        surface = 0;
     }
     cleanCachedSurfacesLocked();
     return surface;
@@ -361,40 +296,20 @@
     }
 }
 
-void Surface::init()
+void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
 {
-    ANativeWindow::setSwapInterval  = setSwapInterval;
-    ANativeWindow::dequeueBuffer    = dequeueBuffer;
-    ANativeWindow::cancelBuffer     = cancelBuffer;
-    ANativeWindow::lockBuffer       = lockBuffer;
-    ANativeWindow::queueBuffer      = queueBuffer;
-    ANativeWindow::query            = query;
-    ANativeWindow::perform          = perform;
-
-    if (mSurface != NULL) {
-        sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+    if (mSurface != NULL || surfaceTexture != NULL) {
         LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
         if (surfaceTexture != NULL) {
-            mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
-            mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+            setISurfaceTexture(surfaceTexture);
+            setUsage(GraphicBuffer::USAGE_HW_RENDER);
         }
 
         DisplayInfo dinfo;
         SurfaceComposerClient::getDisplayInfo(0, &dinfo);
         const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
         const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-
-        const_cast<int&>(ANativeWindow::minSwapInterval) =
-                mSurfaceTextureClient->minSwapInterval;
-
-        const_cast<int&>(ANativeWindow::maxSwapInterval) =
-                mSurfaceTextureClient->maxSwapInterval;
-
         const_cast<uint32_t&>(ANativeWindow::flags) = 0;
-
-        if (mSurfaceTextureClient != 0) {
-            mInitCheck = NO_ERROR;
-        }
     }
 }
 
@@ -402,27 +317,16 @@
 {
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
-    mSurfaceTextureClient.clear();
     mSurface.clear();
     IPCThreadState::self()->flushCommands();
 }
 
 bool Surface::isValid() {
-    return mInitCheck == NO_ERROR;
-}
-
-status_t Surface::validate(bool inCancelBuffer) const
-{
-    // check that we initialized ourself properly
-    if (mInitCheck != NO_ERROR) {
-        LOGE("invalid token (identity=%u)", mIdentity);
-        return mInitCheck;
-    }
-    return NO_ERROR;
+    return getISurfaceTexture() != NULL;
 }
 
 sp<ISurfaceTexture> Surface::getSurfaceTexture() {
-    return mSurface != NULL ? mSurface->getSurfaceTexture() : NULL;
+    return getISurfaceTexture();
 }
 
 sp<IBinder> Surface::asBinder() const {
@@ -431,219 +335,45 @@
 
 // ----------------------------------------------------------------------------
 
-int Surface::setSwapInterval(ANativeWindow* window, int interval) {
-    Surface* self = getSelf(window);
-    return self->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindow* window, 
-        ANativeWindowBuffer** buffer) {
-    Surface* self = getSelf(window);
-    return self->dequeueBuffer(buffer);
-}
-
-int Surface::cancelBuffer(ANativeWindow* window,
-        ANativeWindowBuffer* buffer) {
-    Surface* self = getSelf(window);
-    return self->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindow* window, 
-        ANativeWindowBuffer* buffer) {
-    Surface* self = getSelf(window);
-    return self->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindow* window, 
-        ANativeWindowBuffer* buffer) {
-    Surface* self = getSelf(window);
-    return self->queueBuffer(buffer);
-}
-
-int Surface::query(const ANativeWindow* window,
-        int what, int* value) {
-    const Surface* self = getSelf(window);
-    return self->query(what, value);
-}
-
-int Surface::perform(ANativeWindow* window, 
-        int operation, ...) {
-    va_list args;
-    va_start(args, operation);
-    Surface* self = getSelf(window);
-    int res = self->perform(operation, args);
-    va_end(args);
-    return res;
-}
-
-// ----------------------------------------------------------------------------
-
-int Surface::setSwapInterval(int interval) {
-    return mSurfaceTextureClient->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
-    status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
-    if (err == NO_ERROR) {
-        mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
-    }
-    return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
-    return mSurfaceTextureClient->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
-    return mSurfaceTextureClient->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
-    return mSurfaceTextureClient->queueBuffer(buffer);
-}
-
 int Surface::query(int what, int* value) const {
     switch (what) {
     case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
-        // TODO: this is not needed anymore
         *value = 1;
         return NO_ERROR;
     case NATIVE_WINDOW_CONCRETE_TYPE:
-        // TODO: this is not needed anymore
         *value = NATIVE_WINDOW_SURFACE;
         return NO_ERROR;
     }
-    return mSurfaceTextureClient->query(what, value);
-}
-
-int Surface::perform(int operation, va_list args) {
-    return mSurfaceTextureClient->perform(operation, args);
+    return SurfaceTextureClient::query(what, value);
 }
 
 // ----------------------------------------------------------------------------
 
-int Surface::getConnectedApi() const {
-    return mSurfaceTextureClient->getConnectedApi();
-}
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
+    ANativeWindow_Buffer outBuffer;
 
-// ----------------------------------------------------------------------------
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
-    return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) 
-{
-    if (getConnectedApi()) {
-        LOGE("Surface::lock(%p) failed. Already connected to another API",
-                (ANativeWindow*)this);
-        CallStack stack;
-        stack.update();
-        stack.dump("");
-        return INVALID_OPERATION;
+    ARect temp;
+    ARect* inOutDirtyBounds = NULL;
+    if (dirtyIn) {
+        temp = dirtyIn->getBounds();
+        inOutDirtyBounds = &temp;
     }
 
-    if (mApiLock.tryLock() != NO_ERROR) {
-        LOGE("calling Surface::lock from different threads!");
-        CallStack stack;
-        stack.update();
-        stack.dump("");
-        return WOULD_BLOCK;
-    }
+    status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
 
-    /* Here we're holding mApiLock */
-    
-    if (mLockedBuffer != 0) {
-        LOGE("Surface::lock failed, already locked");
-        mApiLock.unlock();
-        return INVALID_OPERATION;
-    }
-
-    // we're intending to do software rendering from this point
-    mSurfaceTextureClient->setUsage(
-            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
-    ANativeWindowBuffer* out;
-    status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
-    LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
     if (err == NO_ERROR) {
-        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
-        err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
-        LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
-                backBuffer->handle, strerror(-err));
-        if (err == NO_ERROR) {
-            const Rect bounds(backBuffer->width, backBuffer->height);
-            const Region boundsRegion(bounds);
-            Region scratch(boundsRegion);
-            Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
-            newDirtyRegion &= boundsRegion;
-
-            // figure out if we can copy the frontbuffer back
-            const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
-            const bool canCopyBack = (frontBuffer != 0 &&
-                    backBuffer->width  == frontBuffer->width &&
-                    backBuffer->height == frontBuffer->height &&
-                    backBuffer->format == frontBuffer->format &&
-                    !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
-
-            // the dirty region we report to surfaceflinger is the one
-            // given by the user (as opposed to the one *we* return to the
-            // user).
-            mDirtyRegion = newDirtyRegion;
-
-            if (canCopyBack) {
-                // copy the area that is invalid and not repainted this round
-                const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
-                if (!copyback.isEmpty())
-                    copyBlt(backBuffer, frontBuffer, copyback);
-            } else {
-                // if we can't copy-back anything, modify the user's dirty
-                // region to make sure they redraw the whole buffer
-                newDirtyRegion = boundsRegion;
-            }
-
-            // keep track of the are of the buffer that is "clean"
-            // (ie: that will be redrawn)
-            mOldDirtyRegion = newDirtyRegion;
-
-            void* vaddr;
-            status_t res = backBuffer->lock(
-                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-                    newDirtyRegion.bounds(), &vaddr);
-            
-            LOGW_IF(res, "failed locking buffer (handle = %p)", 
-                    backBuffer->handle);
-
-            mLockedBuffer = backBuffer;
-            other->w      = backBuffer->width;
-            other->h      = backBuffer->height;
-            other->s      = backBuffer->stride;
-            other->usage  = backBuffer->usage;
-            other->format = backBuffer->format;
-            other->bits   = vaddr;
-        }
+        other->w = uint32_t(outBuffer.width);
+        other->h = uint32_t(outBuffer.height);
+        other->s = uint32_t(outBuffer.stride);
+        other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+        other->format = uint32_t(outBuffer.format);
+        other->bits = outBuffer.bits;
     }
-    mApiLock.unlock();
     return err;
 }
-    
-status_t Surface::unlockAndPost() 
-{
-    if (mLockedBuffer == 0) {
-        LOGE("Surface::unlockAndPost failed, no locked buffer");
-        return INVALID_OPERATION;
-    }
 
-    status_t err = mLockedBuffer->unlock();
-    LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
-    
-    err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
-    LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
-            mLockedBuffer->handle, strerror(-err));
-
-    mPostedBuffer = mLockedBuffer;
-    mLockedBuffer = 0;
-    return err;
+status_t Surface::unlockAndPost() {
+    return SurfaceTextureClient::unlockAndPost();
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8cead80..3b0ffea 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -339,7 +339,7 @@
         sp<ISurface> surface = mClient->createSurface(&data, name,
                 display, w, h, format, flags);
         if (surface != 0) {
-            result = new SurfaceControl(this, surface, data, w, h, format, flags);
+            result = new SurfaceControl(this, surface, data);
         }
     }
     return result;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 886a3fb..16755ad 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -86,13 +86,15 @@
     mClientBufferCount(0),
     mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
     mCurrentTexture(INVALID_BUFFER_SLOT),
-    mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
     mCurrentTransform(0),
     mCurrentTimestamp(0),
     mNextTransform(0),
+    mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mTexName(tex),
     mSynchronousMode(false),
-    mAllowSynchronousMode(allowSynchronousMode) {
+    mAllowSynchronousMode(allowSynchronousMode),
+    mConnectedApi(NO_CONNECTED_API),
+    mAbandoned(false) {
     LOGV("SurfaceTexture::SurfaceTexture");
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -148,6 +150,11 @@
     LOGV("SurfaceTexture::setBufferCount");
     Mutex::Autolock lock(mMutex);
 
+    if (mAbandoned) {
+        LOGE("setBufferCount: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
     if (bufferCount > NUM_BUFFER_SLOTS) {
         LOGE("setBufferCount: bufferCount larger than slots available");
         return BAD_VALUE;
@@ -189,30 +196,43 @@
 
 status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
-    Mutex::Autolock lock(mMutex);
-    if ((w != mDefaultWidth) || (h != mDefaultHeight)) {
-        mDefaultWidth = w;
-        mDefaultHeight = h;
+    if (!w || !h) {
+        LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", w, h);
+        return BAD_VALUE;
     }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
     return OK;
 }
 
-sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf) {
+status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
     LOGV("SurfaceTexture::requestBuffer");
     Mutex::Autolock lock(mMutex);
-    if (buf < 0 || mBufferCount <= buf) {
-        LOGE("requestBuffer: slot index out of range [0, %d]: %d",
-                mBufferCount, buf);
-        return 0;
+    if (mAbandoned) {
+        LOGE("requestBuffer: SurfaceTexture has been abandoned!");
+        return NO_INIT;
     }
-    mSlots[buf].mRequestBufferCalled = true;
-    return mSlots[buf].mGraphicBuffer;
+    if (slot < 0 || mBufferCount <= slot) {
+        LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, slot);
+        return BAD_VALUE;
+    }
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
 }
 
 status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
         uint32_t format, uint32_t usage) {
     LOGV("SurfaceTexture::dequeueBuffer");
 
+    if (mAbandoned) {
+        LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
     if ((w && !h) || (!w && h)) {
         LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
         return BAD_VALUE;
@@ -250,6 +270,11 @@
             // wait for the FIFO to drain
             while (!mQueue.isEmpty()) {
                 mDequeueCondition.wait(mMutex);
+                if (mAbandoned) {
+                    LOGE("dequeueBuffer: SurfaceTexture was abandoned while "
+                            "blocked!");
+                    return NO_INIT;
+                }
             }
             minBufferCountNeeded = mSynchronousMode ?
                     MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
@@ -378,6 +403,11 @@
 status_t SurfaceTexture::setSynchronousMode(bool enabled) {
     Mutex::Autolock lock(mMutex);
 
+    if (mAbandoned) {
+        LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
     status_t err = OK;
     if (!mAllowSynchronousMode && enabled)
         return err;
@@ -400,13 +430,18 @@
     return err;
 }
 
-status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
+status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
     LOGV("SurfaceTexture::queueBuffer");
 
     sp<FrameAvailableListener> listener;
 
     { // scope for the lock
         Mutex::Autolock lock(mMutex);
+        if (mAbandoned) {
+            LOGE("queueBuffer: SurfaceTexture has been abandoned!");
+            return NO_INIT;
+        }
         if (buf < 0 || buf >= mBufferCount) {
             LOGE("queueBuffer: slot index out of range [0, %d]: %d",
                     mBufferCount, buf);
@@ -452,6 +487,7 @@
         mSlots[buf].mBufferState = BufferSlot::QUEUED;
         mSlots[buf].mCrop = mNextCrop;
         mSlots[buf].mTransform = mNextTransform;
+        mSlots[buf].mScalingMode = mNextScalingMode;
         mSlots[buf].mTimestamp = timestamp;
         mDequeueCondition.signal();
     } // scope for the lock
@@ -460,12 +496,23 @@
     if (listener != 0) {
         listener->onFrameAvailable();
     }
+
+    *outWidth = mDefaultWidth;
+    *outHeight = mDefaultHeight;
+    *outTransform = 0;
+
     return OK;
 }
 
 void SurfaceTexture::cancelBuffer(int buf) {
     LOGV("SurfaceTexture::cancelBuffer");
     Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
+        return;
+    }
+
     if (buf < 0 || buf >= mBufferCount) {
         LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
                 mBufferCount, buf);
@@ -482,6 +529,10 @@
 status_t SurfaceTexture::setCrop(const Rect& crop) {
     LOGV("SurfaceTexture::setCrop");
     Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        LOGE("setCrop: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
     mNextCrop = crop;
     return OK;
 }
@@ -489,10 +540,90 @@
 status_t SurfaceTexture::setTransform(uint32_t transform) {
     LOGV("SurfaceTexture::setTransform");
     Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        LOGE("setTransform: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
     mNextTransform = transform;
     return OK;
 }
 
+status_t SurfaceTexture::connect(int api) {
+    LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        LOGE("connect: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi != NO_CONNECTED_API) {
+                LOGE("connect: already connected (cur=%d, req=%d)",
+                        mConnectedApi, api);
+                err = -EINVAL;
+            } else {
+                mConnectedApi = api;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+status_t SurfaceTexture::disconnect(int api) {
+    LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        LOGE("connect: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi == api) {
+                mConnectedApi = NO_CONNECTED_API;
+            } else {
+                LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                        mConnectedApi, api);
+                err = -EINVAL;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+status_t SurfaceTexture::setScalingMode(int mode) {
+    LOGV("SurfaceTexture::setScalingMode(%d)", mode);
+
+    switch (mode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+            break;
+        default:
+            return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mNextScalingMode = mode;
+    return OK;
+}
+
 status_t SurfaceTexture::updateTexImage() {
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
@@ -522,12 +653,8 @@
             LOGW("updateTexImage: clearing GL error: %#04x", error);
         }
 
-        GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format);
-        if (target != mCurrentTextureTarget) {
-            glDeleteTextures(1, &mTexName);
-        }
-        glBindTexture(target, mTexName);
-        glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+        glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
 
         bool failed = false;
         while ((error = glGetError()) != GL_NO_ERROR) {
@@ -549,10 +676,10 @@
 
         // Update the SurfaceTexture state.
         mCurrentTexture = buf;
-        mCurrentTextureTarget = target;
         mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
         mCurrentCrop = mSlots[buf].mCrop;
         mCurrentTransform = mSlots[buf].mTransform;
+        mCurrentScalingMode = mSlots[buf].mScalingMode;
         mCurrentTimestamp = mSlots[buf].mTimestamp;
         computeCurrentTransformMatrix();
 
@@ -562,7 +689,7 @@
         mDequeueCondition.signal();
     } else {
         // We always bind the texture even if we don't update its contents.
-        glBindTexture(mCurrentTextureTarget, mTexName);
+        glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
     }
 
     return OK;
@@ -587,20 +714,8 @@
     return false;
 }
 
-GLenum SurfaceTexture::getTextureTarget(uint32_t format)
-{
-    GLenum target = GL_TEXTURE_2D;
-#if defined(GL_OES_EGL_image_external)
-    if (isExternalFormat(format)) {
-        target = GL_TEXTURE_EXTERNAL_OES;
-    }
-#endif
-    return target;
-}
-
 GLenum SurfaceTexture::getCurrentTextureTarget() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTextureTarget;
+    return GL_TEXTURE_EXTERNAL_OES;
 }
 
 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
@@ -712,11 +827,6 @@
     mFrameAvailableListener = listener;
 }
 
-sp<IBinder> SurfaceTexture::getAllocator() {
-    LOGV("SurfaceTexture::getAllocator");
-    return mGraphicBufferAlloc->asBinder();
-}
-
 void SurfaceTexture::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         mSlots[i].mGraphicBuffer = 0;
@@ -760,20 +870,27 @@
     return mCurrentTransform;
 }
 
+uint32_t SurfaceTexture::getCurrentScalingMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentScalingMode;
+}
+
 int SurfaceTexture::query(int what, int* outValue)
 {
     Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        LOGE("query: SurfaceTexture has been abandoned!");
+        return NO_INIT;
+    }
+
     int value;
     switch (what) {
     case NATIVE_WINDOW_WIDTH:
         value = mDefaultWidth;
-        if (!mDefaultWidth && !mDefaultHeight && mCurrentTextureBuf!=0)
-            value = mCurrentTextureBuf->width;
         break;
     case NATIVE_WINDOW_HEIGHT:
         value = mDefaultHeight;
-        if (!mDefaultWidth && !mDefaultHeight && mCurrentTextureBuf!=0)
-            value = mCurrentTextureBuf->height;
         break;
     case NATIVE_WINDOW_FORMAT:
         value = mPixelFormat;
@@ -789,6 +906,13 @@
     return NO_ERROR;
 }
 
+void SurfaceTexture::abandon() {
+    Mutex::Autolock lock(mMutex);
+    freeAllBuffers();
+    mAbandoned = true;
+    mDequeueCondition.signal();
+}
+
 void SurfaceTexture::dump(String8& result) const
 {
     char buffer[1024];
@@ -816,12 +940,12 @@
     }
 
     snprintf(buffer, SIZE,
-            "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d, target=0x%04x}\n"
+            "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
             "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
             ,
             prefix, mCurrentCrop.left,
             mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
-            mCurrentTransform, mCurrentTexture, mCurrentTextureTarget,
+            mCurrentTransform, mCurrentTexture,
             prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom,
             mCurrentTransform, fifoSize, fifo.string()
     );
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index e203035..e6837ea 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -24,68 +24,86 @@
 namespace android {
 
 SurfaceTextureClient::SurfaceTextureClient(
-        const sp<ISurfaceTexture>& surfaceTexture):
-        mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
-        mReqHeight(0), mReqFormat(0), mReqUsage(0),
-        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
-        mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
-        mMutex() {
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    SurfaceTextureClient::init();
+    SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
+}
+
+SurfaceTextureClient::SurfaceTextureClient() {
+    SurfaceTextureClient::init();
+}
+
+void SurfaceTextureClient::init() {
     // Initialize the ANativeWindow function pointers.
-    ANativeWindow::setSwapInterval  = setSwapInterval;
-    ANativeWindow::dequeueBuffer    = dequeueBuffer;
-    ANativeWindow::cancelBuffer     = cancelBuffer;
-    ANativeWindow::lockBuffer       = lockBuffer;
-    ANativeWindow::queueBuffer      = queueBuffer;
-    ANativeWindow::query            = query;
-    ANativeWindow::perform          = perform;
+    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
+    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
+    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
+    ANativeWindow::lockBuffer       = hook_lockBuffer;
+    ANativeWindow::queueBuffer      = hook_queueBuffer;
+    ANativeWindow::query            = hook_query;
+    ANativeWindow::perform          = hook_perform;
 
     const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
     const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
 
-    // Get a reference to the allocator.
-    mAllocator = mSurfaceTexture->getAllocator();
+    mReqWidth = 0;
+    mReqHeight = 0;
+    mReqFormat = 0;
+    mReqUsage = 0;
+    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    mDefaultWidth = 0;
+    mDefaultHeight = 0;
+    mTransformHint = 0;
+    mConnectedToCpu = false;
+}
+
+void SurfaceTextureClient::setISurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    mSurfaceTexture = surfaceTexture;
 }
 
 sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
     return mSurfaceTexture;
 }
 
-int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
     SurfaceTextureClient* c = getSelf(window);
     return c->setSwapInterval(interval);
 }
 
-int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
         ANativeWindowBuffer** buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->dequeueBuffer(buffer);
 }
 
-int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
         ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->cancelBuffer(buffer);
 }
 
-int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
         ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->lockBuffer(buffer);
 }
 
-int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
         ANativeWindowBuffer* buffer) {
     SurfaceTextureClient* c = getSelf(window);
     return c->queueBuffer(buffer);
 }
 
-int SurfaceTextureClient::query(const ANativeWindow* window,
+int SurfaceTextureClient::hook_query(const ANativeWindow* window,
                                 int what, int* value) {
     const SurfaceTextureClient* c = getSelf(window);
     return c->query(what, value);
 }
 
-int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
     va_list args;
     va_start(args, operation);
     SurfaceTextureClient* c = getSelf(window);
@@ -127,14 +145,12 @@
     }
 
     if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
-        gbuf = mSurfaceTexture->requestBuffer(buf);
-        if (gbuf == 0) {
-            LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
-            return NO_MEMORY;
+        result = mSurfaceTexture->requestBuffer(buf, &gbuf);
+        if (result != NO_ERROR) {
+            LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
+                    result);
+            return result;
         }
-        mQueryWidth  = gbuf->width;
-        mQueryHeight = gbuf->height;
-        mQueryFormat = gbuf->format;
     }
     *buffer = gbuf.get();
     return OK;
@@ -201,27 +217,38 @@
     if (i < 0) {
         return i;
     }
-    mSurfaceTexture->queueBuffer(i, timestamp);
+    mSurfaceTexture->queueBuffer(i, timestamp,
+            &mDefaultWidth, &mDefaultHeight, &mTransformHint);
     return OK;
 }
 
 int SurfaceTextureClient::query(int what, int* value) const {
     LOGV("SurfaceTextureClient::query");
-    switch (what) {
-    case NATIVE_WINDOW_FORMAT:
-        if (mReqFormat) {
-            *value = mReqFormat;
-            return NO_ERROR;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        switch (what) {
+            case NATIVE_WINDOW_FORMAT:
+                if (mReqFormat) {
+                    *value = mReqFormat;
+                    return NO_ERROR;
+                }
+                break;
+            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+                *value = 0;
+                return NO_ERROR;
+            case NATIVE_WINDOW_CONCRETE_TYPE:
+                *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_WIDTH:
+                *value = mDefaultWidth;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_HEIGHT:
+                *value = mDefaultHeight;
+                return NO_ERROR;
+            case NATIVE_WINDOW_TRANSFORM_HINT:
+                *value = mTransformHint;
+                return NO_ERROR;
         }
-        break;
-    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
-        // TODO: this is not needed anymore
-        *value = 0;
-        return NO_ERROR;
-    case NATIVE_WINDOW_CONCRETE_TYPE:
-        // TODO: this is not needed anymore
-        *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
-        return NO_ERROR;
     }
     return mSurfaceTexture->query(what, value);
 }
@@ -260,6 +287,15 @@
     case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
         res = dispatchSetBuffersFormat(args);
         break;
+    case NATIVE_WINDOW_LOCK:
+        res = dispatchLock(args);
+        break;
+    case NATIVE_WINDOW_UNLOCK_AND_POST:
+        res = dispatchUnlockAndPost(args);
+        break;
+    case NATIVE_WINDOW_SET_SCALING_MODE:
+        res = dispatchSetScalingMode(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -314,6 +350,11 @@
     return setBuffersFormat(f);
 }
 
+int SurfaceTextureClient::dispatchSetScalingMode(va_list args) {
+    int m = va_arg(args, int);
+    return setScalingMode(m);
+}
+
 int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
     int transform = va_arg(args, int);
     return setBuffersTransform(transform);
@@ -324,21 +365,23 @@
     return setBuffersTimestamp(timestamp);
 }
 
+int SurfaceTextureClient::dispatchLock(va_list args) {
+    ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+    ARect* inOutDirtyBounds = va_arg(args, ARect*);
+    return lock(outBuffer, inOutDirtyBounds);
+}
+
+int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
+    return unlockAndPost();
+}
+
+
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
     Mutex::Autolock lock(mMutex);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnectedApi) {
-                err = -EINVAL;
-            } else {
-                mConnectedApi = api;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
+    int err = mSurfaceTexture->connect(api);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = true;
     }
     return err;
 }
@@ -346,29 +389,13 @@
 int SurfaceTextureClient::disconnect(int api) {
     LOGV("SurfaceTextureClient::disconnect");
     Mutex::Autolock lock(mMutex);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnectedApi == api) {
-                mConnectedApi = 0;
-            } else {
-                err = -EINVAL;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
+    int err = mSurfaceTexture->disconnect(api);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = false;
     }
     return err;
 }
 
-int SurfaceTextureClient::getConnectedApi() const
-{
-    Mutex::Autolock lock(mMutex);
-    return mConnectedApi;
-}
-
-
 int SurfaceTextureClient::setUsage(uint32_t reqUsage)
 {
     LOGV("SurfaceTextureClient::setUsage");
@@ -444,6 +471,18 @@
     return NO_ERROR;
 }
 
+int SurfaceTextureClient::setScalingMode(int mode)
+{
+    LOGV("SurfaceTextureClient::setScalingMode(%d)", mode);
+    Mutex::Autolock lock(mMutex);
+    // mode is validated on the server
+    status_t err = mSurfaceTexture->setScalingMode(mode);
+    LOGE_IF(err, "ISurfaceTexture::setScalingMode(%d) returned %s",
+            mode, strerror(-err));
+
+    return err;
+}
+
 int SurfaceTextureClient::setBuffersTransform(int transform)
 {
     LOGV("SurfaceTextureClient::setBuffersTransform");
@@ -466,4 +505,160 @@
     }
 }
 
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+        const sp<GraphicBuffer>& dst,
+        const sp<GraphicBuffer>& src,
+        const Region& reg)
+{
+    // src and dst with, height and format must be identical. no verification
+    // is done here.
+    status_t err;
+    uint8_t const * src_bits = NULL;
+    err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+    LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+    uint8_t* dst_bits = NULL;
+    err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+    LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+    Region::const_iterator head(reg.begin());
+    Region::const_iterator tail(reg.end());
+    if (head != tail && src_bits && dst_bits) {
+        const size_t bpp = bytesPerPixel(src->format);
+        const size_t dbpr = dst->stride * bpp;
+        const size_t sbpr = src->stride * bpp;
+
+        while (head != tail) {
+            const Rect& r(*head++);
+            ssize_t h = r.height();
+            if (h <= 0) continue;
+            size_t size = r.width() * bpp;
+            uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+            uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+            if (dbpr==sbpr && size==sbpr) {
+                size *= h;
+                h = 1;
+            }
+            do {
+                memcpy(d, s, size);
+                d += dbpr;
+                s += sbpr;
+            } while (--h > 0);
+        }
+    }
+
+    if (src_bits)
+        src->unlock();
+
+    if (dst_bits)
+        dst->unlock();
+
+    return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceTextureClient::lock(
+        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+    if (mLockedBuffer != 0) {
+        LOGE("Surface::lock failed, already locked");
+        return INVALID_OPERATION;
+    }
+
+    if (!mConnectedToCpu) {
+        int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
+        if (err) {
+            return err;
+        }
+        // we're intending to do software rendering from this point
+        setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+    }
+
+    ANativeWindowBuffer* out;
+    status_t err = dequeueBuffer(&out);
+    LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+    if (err == NO_ERROR) {
+        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+        err = lockBuffer(backBuffer.get());
+        LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+                backBuffer->handle, strerror(-err));
+        if (err == NO_ERROR) {
+            const Rect bounds(backBuffer->width, backBuffer->height);
+
+            Region newDirtyRegion;
+            if (inOutDirtyBounds) {
+                newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+                newDirtyRegion.andSelf(bounds);
+            } else {
+                newDirtyRegion.set(bounds);
+            }
+
+            // figure out if we can copy the frontbuffer back
+            const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+            const bool canCopyBack = (frontBuffer != 0 &&
+                    backBuffer->width  == frontBuffer->width &&
+                    backBuffer->height == frontBuffer->height &&
+                    backBuffer->format == frontBuffer->format);
+
+            if (canCopyBack) {
+                // copy the area that is invalid and not repainted this round
+                const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+                if (!copyback.isEmpty())
+                    copyBlt(backBuffer, frontBuffer, copyback);
+            } else {
+                // if we can't copy-back anything, modify the user's dirty
+                // region to make sure they redraw the whole buffer
+                newDirtyRegion.set(bounds);
+            }
+
+            // keep track of the are of the buffer that is "clean"
+            // (ie: that will be redrawn)
+            mOldDirtyRegion = newDirtyRegion;
+
+            if (inOutDirtyBounds) {
+                *inOutDirtyBounds = newDirtyRegion.getBounds();
+            }
+
+            void* vaddr;
+            status_t res = backBuffer->lock(
+                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                    newDirtyRegion.bounds(), &vaddr);
+
+            LOGW_IF(res, "failed locking buffer (handle = %p)",
+                    backBuffer->handle);
+
+            mLockedBuffer = backBuffer;
+            outBuffer->width  = backBuffer->width;
+            outBuffer->height = backBuffer->height;
+            outBuffer->stride = backBuffer->stride;
+            outBuffer->format = backBuffer->format;
+            outBuffer->bits   = vaddr;
+        }
+    }
+    return err;
+}
+
+status_t SurfaceTextureClient::unlockAndPost()
+{
+    if (mLockedBuffer == 0) {
+        LOGE("Surface::unlockAndPost failed, no locked buffer");
+        return INVALID_OPERATION;
+    }
+
+    status_t err = mLockedBuffer->unlock();
+    LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+    err = queueBuffer(mLockedBuffer.get());
+    LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+            mLockedBuffer->handle, strerror(-err));
+
+    mPostedBuffer = mLockedBuffer;
+    mLockedBuffer = 0;
+    return err;
+}
+
 }; // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 519b40e..c1a3c98 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -116,11 +116,6 @@
     EXPECT_EQ(NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, result);
 }
 
-TEST_F(SurfaceTextureClientTest, ANativeWindowLockFails) {
-    ANativeWindow_Buffer buf;
-    ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(mANW.get(), &buf, NULL));
-}
-
 TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) {
     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
@@ -613,4 +608,90 @@
     }
 }
 
+class MultiSurfaceTextureClientTest : public ::testing::Test {
+
+public:
+    MultiSurfaceTextureClientTest() :
+            mEglDisplay(EGL_NO_DISPLAY),
+            mEglContext(EGL_NO_CONTEXT) {
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            mEglSurfaces[i] = EGL_NO_CONTEXT;
+        }
+    }
+
+protected:
+
+    enum { NUM_SURFACE_TEXTURES = 32 };
+
+    virtual void SetUp() {
+        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+
+        EGLint majorVersion, minorVersion;
+        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        EGLConfig myConfig;
+        EGLint numConfigs = 0;
+        EGLint configAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+            EGL_NONE
+        };
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &myConfig, 1,
+                &numConfigs));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+                0);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
+
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            sp<SurfaceTexture> st(new SurfaceTexture(i));
+            sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+            mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
+                    static_cast<ANativeWindow*>(stc.get()), NULL);
+            ASSERT_EQ(EGL_SUCCESS, eglGetError());
+            ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
+        }
+    }
+
+    virtual void TearDown() {
+        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                EGL_NO_CONTEXT);
+
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            if (mEglSurfaces[i] != EGL_NO_SURFACE) {
+                eglDestroySurface(mEglDisplay, mEglSurfaces[i]);
+            }
+        }
+
+        if (mEglContext != EGL_NO_CONTEXT) {
+            eglDestroyContext(mEglDisplay, mEglContext);
+        }
+
+        if (mEglDisplay != EGL_NO_DISPLAY) {
+            eglTerminate(mEglDisplay);
+        }
+    }
+
+    EGLDisplay mEglDisplay;
+    EGLSurface mEglSurfaces[NUM_SURFACE_TEXTURES];
+    EGLContext mEglContext;
+};
+
+// XXX: This test is disabled because it causes a hang on some devices.  See bug
+// 5015672.
+TEST_F(MultiSurfaceTextureClientTest, DISABLED_MakeCurrentBetweenSurfacesWorks) {
+    for (int iter = 0; iter < 8; iter++) {
+        for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+            eglMakeCurrent(mEglDisplay, mEglSurfaces[i], mEglSurfaces[i],
+                    mEglContext);
+            glClear(GL_COLOR_BUFFER_BIT);
+            eglSwapBuffers(mEglDisplay, mEglSurfaces[i]);
+        }
+    }
+}
+
 } // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 88433fb..44babcf 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "SurfaceTexture_test"
 //#define LOG_NDEBUG 0
 
 #include <gtest/gtest.h>
@@ -379,6 +380,13 @@
         ASSERT_NE(-1, mTexMatrixHandle);
     }
 
+    virtual void TearDown() {
+        mANW.clear();
+        mSTC.clear();
+        mST.clear();
+        GLTest::TearDown();
+    }
+
     // drawTexture draws the SurfaceTexture over the entire GL viewport.
     void drawTexture() {
         const GLfloat triangleVertices[] = {
@@ -824,9 +832,7 @@
     pt->requestExitAndWait();
 }
 
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
     const int texWidth = 64;
     const int texHeight = 66;
 
@@ -863,26 +869,24 @@
     EXPECT_TRUE(checkPixel( 0, 65,  35,  35,  35,  35));
 
     EXPECT_TRUE(checkPixel(15, 10,  35, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(23, 65, 231,  35, 231,  35));
     EXPECT_TRUE(checkPixel(19, 40,  35, 231,  35,  35));
     EXPECT_TRUE(checkPixel(38, 30, 231,  35,  35,  35));
     EXPECT_TRUE(checkPixel(42, 54,  35,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(37, 33, 228,  38,  38,  38));
+    EXPECT_TRUE(checkPixel(37, 34,  35, 231, 231, 231));
     EXPECT_TRUE(checkPixel(31,  8, 231,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(36, 47, 228,  35, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
-    EXPECT_TRUE(checkPixel(48,  3, 228, 228,  38,  35));
+    EXPECT_TRUE(checkPixel(37, 47, 231,  35, 231, 231));
+    EXPECT_TRUE(checkPixel(25, 38,  35,  35,  35,  35));
+    EXPECT_TRUE(checkPixel(49,  6,  35, 231,  35,  35));
     EXPECT_TRUE(checkPixel(54, 50,  35, 231, 231, 231));
-    EXPECT_TRUE(checkPixel(24, 25,  41,  41, 231, 231));
-    EXPECT_TRUE(checkPixel(10,  9,  38,  38, 231, 231));
+    EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(10,  6,  35,  35, 231, 231));
     EXPECT_TRUE(checkPixel(29,  4,  35,  35,  35, 231));
-    EXPECT_TRUE(checkPixel(56, 31,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(55, 28,  35,  35, 231,  35));
     EXPECT_TRUE(checkPixel(58, 55,  35,  35, 231, 231));
 }
 
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
     const int texWidth = 64;
     const int texHeight = 64;
 
@@ -936,9 +940,7 @@
     EXPECT_TRUE(checkPixel( 3, 52,  35, 231,  35,  35));
 }
 
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) {
     const int texWidth = 64;
     const int texHeight = 64;
 
@@ -948,7 +950,7 @@
     EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
             mANW.get(), NULL);
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
+    ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
 
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
             mEglContext));
@@ -972,6 +974,8 @@
 
     eglSwapBuffers(mEglDisplay, stcEglSurface);
 
+    eglDestroySurface(mEglDisplay, stcEglSurface);
+
     // Do the consumer side of things
     EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
             mEglContext));
@@ -1010,6 +1014,83 @@
     EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
 }
 
+TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
+    class ProducerThread : public Thread {
+    public:
+        ProducerThread(const sp<ANativeWindow>& anw):
+                mANW(anw),
+                mDequeueError(NO_ERROR) {
+        }
+
+        virtual ~ProducerThread() {
+        }
+
+        virtual bool threadLoop() {
+            Mutex::Autolock lock(mMutex);
+            ANativeWindowBuffer* anb;
+
+            // Frame 1
+            if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+                return false;
+            }
+            if (anb == NULL) {
+                return false;
+            }
+            if (mANW->queueBuffer(mANW.get(), anb)
+                    != NO_ERROR) {
+                return false;
+            }
+
+            // Frame 2
+            if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+                return false;
+            }
+            if (anb == NULL) {
+                return false;
+            }
+            if (mANW->queueBuffer(mANW.get(), anb)
+                    != NO_ERROR) {
+                return false;
+            }
+
+            // Frame 3 - error expected
+            mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
+            return false;
+        }
+
+        status_t getDequeueError() {
+            Mutex::Autolock lock(mMutex);
+            return mDequeueError;
+        }
+
+    private:
+        sp<ANativeWindow> mANW;
+        status_t mDequeueError;
+        Mutex mMutex;
+    };
+
+    sp<FrameWaiter> fw(new FrameWaiter);
+    mST->setFrameAvailableListener(fw);
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, mST->setBufferCountServer(2));
+
+    sp<Thread> pt(new ProducerThread(mANW));
+    pt->run();
+
+    fw->waitForFrame();
+    fw->waitForFrame();
+
+    // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
+    // block waiting for a buffer to become available.
+    usleep(100000);
+
+    mST->abandon();
+
+    pt->requestExitAndWait();
+    ASSERT_EQ(NO_INIT,
+            reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
+}
+
 /*
  * This test is for testing GL -> GL texture streaming via SurfaceTexture.  It
  * contains functionality to create a producer thread that will perform GL
@@ -1089,13 +1170,21 @@
     // synchronously from SurfaceTexture::queueBuffer.
     class FrameCondition : public SurfaceTexture::FrameAvailableListener {
     public:
+        FrameCondition():
+                mFrameAvailable(false),
+                mFrameFinished(false) {
+        }
+
         // waitForFrame waits for the next frame to arrive.  This should be
         // called from the consumer thread once for every frame expected by the
         // test.
         void waitForFrame() {
-            LOGV("+waitForFrame");
             Mutex::Autolock lock(mMutex);
-            status_t result = mFrameAvailableCondition.wait(mMutex);
+            LOGV("+waitForFrame");
+            while (!mFrameAvailable) {
+                mFrameAvailableCondition.wait(mMutex);
+            }
+            mFrameAvailable = false;
             LOGV("-waitForFrame");
         }
 
@@ -1103,22 +1192,30 @@
         // on to produce the next frame.  This should be called by the consumer
         // thread once for every frame expected by the test.
         void finishFrame() {
-            LOGV("+finishFrame");
             Mutex::Autolock lock(mMutex);
+            LOGV("+finishFrame");
+            mFrameFinished = true;
             mFrameFinishCondition.signal();
             LOGV("-finishFrame");
         }
 
         // This should be called by SurfaceTexture on the producer thread.
         virtual void onFrameAvailable() {
-            LOGV("+onFrameAvailable");
             Mutex::Autolock lock(mMutex);
+            LOGV("+onFrameAvailable");
+            mFrameAvailable = true;
             mFrameAvailableCondition.signal();
-            mFrameFinishCondition.wait(mMutex);
+            while (!mFrameFinished) {
+                mFrameFinishCondition.wait(mMutex);
+            }
+            mFrameFinished = false;
             LOGV("-onFrameAvailable");
         }
 
     protected:
+        bool mFrameAvailable;
+        bool mFrameFinished;
+
         Mutex mMutex;
         Condition mFrameAvailableCondition;
         Condition mFrameFinishCondition;
@@ -1164,6 +1261,7 @@
         }
         mProducerThread.clear();
         mFC.clear();
+        SurfaceTextureGLTest::TearDown();
     }
 
     void runProducerThread(const sp<ProducerThread> producerThread) {
@@ -1180,7 +1278,7 @@
     sp<FrameCondition> mFC;
 };
 
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) {
     class PT : public ProducerThread {
         virtual void render() {
             glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1198,7 +1296,7 @@
     // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
 }
 
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) {
     class PT : public ProducerThread {
         virtual void render() {
             glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1216,7 +1314,7 @@
     // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
 }
 
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
     enum { NUM_ITERATIONS = 1024 };
 
     class PT : public ProducerThread {
@@ -1244,7 +1342,7 @@
     }
 }
 
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
     enum { NUM_ITERATIONS = 1024 };
 
     class PT : public ProducerThread {
@@ -1272,4 +1370,70 @@
     }
 }
 
+// XXX: This test is disabled because it is currently hanging on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
+    enum { NUM_ITERATIONS = 64 };
+
+    class PT : public ProducerThread {
+        virtual void render() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) {
+                glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                glClear(GL_COLOR_BUFFER_BIT);
+                LOGV("+swapBuffers");
+                swapBuffers();
+                LOGV("-swapBuffers");
+            }
+        }
+    };
+
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, mST->setBufferCountServer(2));
+
+    runProducerThread(new PT());
+
+    // Allow three frames to be rendered and queued before starting the
+    // rendering in this thread.  For the latter two frames we don't call
+    // updateTexImage so the next dequeue from the producer thread will block
+    // waiting for a frame to become available.
+    mFC->waitForFrame();
+    mFC->finishFrame();
+
+    // We must call updateTexImage to consume the first frame so that the
+    // SurfaceTexture is able to reduce the buffer count to 2.  This is because
+    // the GL driver may dequeue a buffer when the EGLSurface is created, and
+    // that happens before we call setBufferCountServer.  It's possible that the
+    // driver does not dequeue a buffer at EGLSurface creation time, so we
+    // cannot rely on this to cause the second dequeueBuffer call to block.
+    mST->updateTexImage();
+
+    mFC->waitForFrame();
+    mFC->finishFrame();
+    mFC->waitForFrame();
+    mFC->finishFrame();
+
+    // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
+    // block waiting for a buffer to become available.
+    usleep(100000);
+
+    // Render and present a number of images.  This thread should not be blocked
+    // by the fact that the producer thread is blocking in dequeue.
+    for (int i = 0; i < NUM_ITERATIONS; i++) {
+        glClear(GL_COLOR_BUFFER_BIT);
+        eglSwapBuffers(mEglDisplay, mEglSurface);
+    }
+
+    // Consume the two pending buffers to unblock the producer thread.
+    mST->updateTexImage();
+    mST->updateTexImage();
+
+    // Consume the remaining buffers from the producer thread.
+    for (int i = 0; i < NUM_ITERATIONS-3; i++) {
+        mFC->waitForFrame();
+        mFC->finishFrame();
+        LOGV("+updateTexImage");
+        mST->updateTexImage();
+        LOGV("-updateTexImage");
+    }
+}
+
 } // namespace android
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 9c10c75..0e8ae61 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -289,6 +289,18 @@
         case NATIVE_WINDOW_CONCRETE_TYPE:
             *value = NATIVE_WINDOW_FRAMEBUFFER;
             return NO_ERROR;
+        case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+            *value = 0;
+            return NO_ERROR;
+        case NATIVE_WINDOW_DEFAULT_WIDTH:
+            *value = fb->width;
+            return NO_ERROR;
+        case NATIVE_WINDOW_DEFAULT_HEIGHT:
+            *value = fb->height;
+            return NO_ERROR;
+        case NATIVE_WINDOW_TRANSFORM_HINT:
+            *value = 0;
+            return NO_ERROR;
     }
     *value = 0;
     return BAD_VALUE;
@@ -298,15 +310,25 @@
         int operation, ...)
 {
     switch (operation) {
-        case NATIVE_WINDOW_SET_USAGE:
-        case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
         case NATIVE_WINDOW_CONNECT:
         case NATIVE_WINDOW_DISCONNECT:
-            break;
-        default:
-            return NAME_NOT_FOUND;
+        case NATIVE_WINDOW_SET_USAGE:
+        case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+        case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+        case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+            // TODO: we should implement these
+            return NO_ERROR;
+
+        case NATIVE_WINDOW_LOCK:
+        case NATIVE_WINDOW_UNLOCK_AND_POST:
+        case NATIVE_WINDOW_SET_CROP:
+        case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+        case NATIVE_WINDOW_SET_SCALING_MODE:
+            return INVALID_OPERATION;
     }
-    return NO_ERROR;
+    return NAME_NOT_FOUND;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index c46d6f4..1e602e9 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -83,7 +83,9 @@
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
     status_t result;
 
-    int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
+    String8 ashmemName("InputChannel ");
+    ashmemName.append(name);
+    int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
     if (serverAshmemFd < 0) {
         result = -errno;
         LOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 693a32a..700b604 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -45,4 +45,4 @@
 )
 
 # Build the manual test programs.
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index f633357..e4eadbd 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -29,7 +29,6 @@
 	Flattenable.cpp \
 	LinearTransform.cpp \
 	ObbFile.cpp \
-	Pool.cpp \
 	PropertyMap.cpp \
 	RefBase.cpp \
 	ResourceTypes.cpp \
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 87549fe..7ef30f9 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -481,6 +481,14 @@
     return sprintf(buf, "%d %s=%s\n", len, key, value);
 }
 
+// Wire format to the backup manager service is chunked:  each chunk is prefixed by
+// a 4-byte count of its size.  A chunk size of zero (four zero bytes) indicates EOD.
+void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
+    uint32_t chunk_size_no = htonl(size);
+    writer->WriteEntityData(&chunk_size_no, 4);
+    if (size != 0) writer->WriteEntityData(buffer, size);
+}
+
 int write_tarfile(const String8& packageName, const String8& domain,
         const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
 {
@@ -660,16 +668,16 @@
 
         // Checksum and write the pax block header
         calc_tar_checksum(paxHeader);
-        writer->WriteEntityData(paxHeader, 512);
+        send_tarfile_chunk(writer, paxHeader, 512);
 
         // Now write the pax data itself
         int paxblocks = (paxLen + 511) / 512;
-        writer->WriteEntityData(paxData, 512 * paxblocks);
+        send_tarfile_chunk(writer, paxData, 512 * paxblocks);
     }
 
     // Checksum and write the 512-byte ustar file header block to the output
     calc_tar_checksum(buf);
-    writer->WriteEntityData(buf, 512);
+    send_tarfile_chunk(writer, buf, 512);
 
     // Now write the file data itself, for real files.  We honor tar's convention that
     // only full 512-byte blocks are sent to write().
@@ -699,7 +707,7 @@
                 memset(buf + nRead, 0, remainder);
                 nRead += remainder;
             }
-            writer->WriteEntityData(buf, nRead);
+            send_tarfile_chunk(writer, buf, nRead);
             toWrite -= nRead;
         }
     }
diff --git a/libs/utils/Pool.cpp b/libs/utils/Pool.cpp
deleted file mode 100644
index 8f18cb9..0000000
--- a/libs/utils/Pool.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Copyright 2010 The Android Open Source Project
-//
-// A simple memory pool.
-//
-#define LOG_TAG "Pool"
-
-//#define LOG_NDEBUG 0
-
-#include <cutils/log.h>
-#include <utils/Pool.h>
-
-#include <stdlib.h>
-
-namespace android {
-
-// TODO Provide a real implementation of a pool.  This is just a stub for initial development.
-
-PoolImpl::PoolImpl(size_t objSize) :
-    mObjSize(objSize) {
-}
-
-PoolImpl::~PoolImpl() {
-}
-
-void* PoolImpl::allocImpl() {
-    void* ptr = malloc(mObjSize);
-    LOG_ALWAYS_FATAL_IF(ptr == NULL, "Cannot allocate new pool object.");
-    return ptr;
-}
-
-void PoolImpl::freeImpl(void* obj) {
-    LOG_ALWAYS_FATAL_IF(obj == NULL, "Caller attempted to free NULL pool object.");
-    return free(obj);
-}
-
-} // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index cb6c246..6cf01c8 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4346,7 +4346,8 @@
                 | (0x0000ffff & (entryIndex));
             resource_name resName;
             if (!this->getResourceName(resID, &resName)) {
-                return UNKNOWN_ERROR;
+                LOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
+                continue;
             }
 
             const String16 overlayType(resName.type, resName.typeLen);
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 50312e7..d18c0a2 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -161,6 +161,7 @@
     pthread_t thread;
     int result = pthread_create(&thread, &attr,
                     (android_pthread_entry)entryFunction, userData);
+    pthread_attr_destroy(&attr);
     if (result != 0) {
         LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
              "(android threadPriority=%d)",
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 87ae3d5..bfb37a6 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -252,13 +252,15 @@
         "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
 
     void* item = editItemLocation(index);
-    if (item == 0)
-        return NO_MEMORY;
-    _do_destroy(item, 1);
-    if (prototype == 0) {
-        _do_construct(item, 1);
-    } else {
-        _do_copy(item, prototype, 1);
+    if (item != prototype) {
+        if (item == 0)
+            return NO_MEMORY;
+        _do_destroy(item, 1);
+        if (prototype == 0) {
+            _do_construct(item, 1);
+        } else {
+            _do_copy(item, prototype, 1);
+        }
     }
     return ssize_t(index);
 }
@@ -347,9 +349,10 @@
 //    LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
 //        this, (int)where, (int)amount, (int)mCount, (int)capacity());
 
-    if (where > mCount)
-        where = mCount;
-      
+    LOG_ASSERT(where <= mCount,
+            "[%p] _grow: where=%d, amount=%d, count=%d",
+            this, (int)where, (int)amount, (int)mCount); // caller already checked
+
     const size_t new_size = mCount + amount;
     if (capacity() < new_size) {
         const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
@@ -366,10 +369,10 @@
             SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
             if (sb) {
                 void* array = sb->data();
-                if (where>0) {
+                if (where != 0) {
                     _do_copy(array, mStorage, where);
                 }
-                if (mCount>where) {
+                if (where != mCount) {
                     const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
                     void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
                     _do_copy(dest, from, mCount-where);
@@ -379,15 +382,14 @@
             }
         }
     } else {
-        ssize_t s = mCount-where;
-        if (s>0) {
-            void* array = editArrayImpl();    
-            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+        if (where != mCount) {
+            void* array = editArrayImpl();
             const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
-            _do_move_forward(to, from, s);
+            void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+            _do_move_forward(to, from, mCount - where);
         }
     }
-    mCount += amount;
+    mCount = new_size;
     void* free_space = const_cast<void*>(itemLocation(where));
     return free_space;
 }
@@ -400,14 +402,15 @@
 //    LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
 //        this, (int)where, (int)amount, (int)mCount, (int)capacity());
 
-    if (where >= mCount)
-        where = mCount - amount;
+    LOG_ASSERT(where + amount <= mCount,
+            "[%p] _shrink: where=%d, amount=%d, count=%d",
+            this, (int)where, (int)amount, (int)mCount); // caller already checked
 
     const size_t new_size = mCount - amount;
     if (new_size*3 < capacity()) {
         const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
 //        LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
-        if ((where == mCount-amount) &&
+        if ((where == new_size) &&
             (mFlags & HAS_TRIVIAL_COPY) &&
             (mFlags & HAS_TRIVIAL_DTOR))
         {
@@ -418,31 +421,28 @@
             SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
             if (sb) {
                 void* array = sb->data();
-                if (where>0) {
+                if (where != 0) {
                     _do_copy(array, mStorage, where);
                 }
-                if (mCount > where+amount) {
+                if (where != new_size) {
                     const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
                     void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
-                    _do_copy(dest, from, mCount-(where+amount));
+                    _do_copy(dest, from, new_size - where);
                 }
                 release_storage();
                 mStorage = const_cast<void*>(array);
             }
         }
     } else {
-        void* array = editArrayImpl();    
+        void* array = editArrayImpl();
         void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
         _do_destroy(to, amount);
-        ssize_t s = mCount-(where+amount);
-        if (s>0) {
+        if (where != new_size) {
             const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
-            _do_move_backward(to, from, s);
+            _do_move_backward(to, from, new_size - where);
         }
     }
-
-    // adjust the number of items...
-    mCount -= amount;
+    mCount = new_size;
 }
 
 size_t VectorImpl::itemSize() const {
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 8726a53..b97f52f 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -8,7 +8,8 @@
 	ObbFile_test.cpp \
 	Looper_test.cpp \
 	String8_test.cpp \
-	Unicode_test.cpp
+	Unicode_test.cpp \
+	ZipFileRO_test.cpp \
 
 shared_libraries := \
 	libz \
diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp
new file mode 100644
index 0000000..7a1d0bd
--- /dev/null
+++ b/libs/utils/tests/ZipFileRO_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ZipFileRO_test"
+#include <utils/Log.h>
+#include <utils/ZipFileRO.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+class ZipFileROTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+    struct tm t;
+
+    // 2011-06-29 14:40:40
+    long when = 0x3EDD7514;
+
+    ZipFileRO::zipTimeToTimespec(when, &t);
+
+    EXPECT_EQ(2011, t.tm_year + 1900)
+            << "Year was improperly converted.";
+
+    EXPECT_EQ(6, t.tm_mon)
+            << "Month was improperly converted.";
+
+    EXPECT_EQ(29, t.tm_mday)
+            << "Day was improperly converted.";
+
+    EXPECT_EQ(14, t.tm_hour)
+            << "Hour was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_min)
+            << "Minute was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_sec)
+            << "Second was improperly converted.";
+}
+
+}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1123e16..6a199db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -226,7 +226,7 @@
 #ifndef EGL_ANDROID_image_native_buffer
 #define EGL_ANDROID_image_native_buffer 1
 struct ANativeWindowBuffer;
-#define EGL_NATIVE_BUFFER_ANDROID       0x3140  /* eglCreateImageKHR target */
+#define EGL_NATIVE_BUFFER_ANDROID               0x3140  /* eglCreateImageKHR target */
 #endif
 
 #ifndef EGL_ANDROID_swap_rectangle
@@ -237,6 +237,11 @@
 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
 #endif
 
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID                  0x3142  /* EGLConfig attribute */
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/specs/EGL_ANDROID_recordable.txt b/opengl/specs/EGL_ANDROID_recordable.txt
index cf44465..8dbd26f 100644
--- a/opengl/specs/EGL_ANDROID_recordable.txt
+++ b/opengl/specs/EGL_ANDROID_recordable.txt
@@ -55,7 +55,7 @@
     Accepted by the <attribute> parameter of eglGetConfigAttrib and
     the <attrib_list> parameter of eglChooseConfig:
 
-        EGL_RECORDABLE_ANDROID                      0xXXXX
+        EGL_RECORDABLE_ANDROID                      0x3142
 
 Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
 
@@ -103,11 +103,38 @@
 
     RESOLVED: It should not affect sorting.  Some implementations may not have
     any drawback associated with using a recordable EGLConfig.  Such
-    implementations should not have to double-up some of their configs to  one sort earlier than .
-    Implementations that do have drawbacks can use the existing caveat
-    mechanism to report this drawback to the client.
+    implementations should not have to double-up some of their configs to  one
+    sort earlier than .  Implementations that do have drawbacks can use the
+    existing caveat mechanism to report this drawback to the client.
+
+    3. How is this extension expected to be implemented?
+
+    RESPONSE: There are two basic approaches to implementing this extension
+    that were considered during its design.  In both cases it is assumed that a
+    color space conversion must be performed at some point because most video
+    encoding formats use a YUV color space.  The two approaches are
+    distinguished by the point at which this color space conversion is
+    performed.
+
+    One approach involves performing the color space conversion as part of the
+    eglSwapBuffers call before queuing the rendered image to the ANativeWindow.
+    In this case, the VisualID of the EGLConfig would correspond to a YUV
+    Android HAL pixel format from which the video encoder can read.  The
+    EGLConfig would likely have the EGL_SLOW_CONFIG caveat because using that
+    config to render normal window contents would result in an RGB -> YUV color
+    space conversion when rendering the frame as well as a YUV -> RGB
+    conversion when compositing the window.
+
+    The other approach involves performing the color space conversion in the
+    video encoder.  In this case, the VisualID of the EGLConfig would
+    correspond to an RGB HAL pixel format from which the video encoder can
+    read.  The EGLConfig would likely not need to have any caveat set, as using
+    this config for normal window rendering would not have any added cost.
 
 Revision History
 
+#2 (Jamie Gennis, July 15, 2011)
+    - Added issue 3.
+
 #1 (Jamie Gennis, July 8, 2011)
     - Initial draft.
diff --git a/opengl/tests/gl2_copyTexImage/Android.mk b/opengl/tests/gl2_copyTexImage/Android.mk
new file mode 100644
index 0000000..bef1f90
--- /dev/null
+++ b/opengl/tests/gl2_copyTexImage/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	gl2_copyTexImage.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv2 \
+    libui
+
+LOCAL_MODULE:= test-opengl-gl2_copyTexImage
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
new file mode 100644
index 0000000..c2bfdec
--- /dev/null
+++ b/opengl/tests/gl2_copyTexImage/gl2_copyTexImage.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Timers.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+static void printGLString(const char *name, GLenum s) {
+    // fprintf(stderr, "printGLString %s, %d\n", name, s);
+    const char *v = (const char *) glGetString(s);
+    // int error = glGetError();
+    // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+    //        (unsigned int) v);
+    // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+    //    fprintf(stderr, "GL %s = %s\n", name, v);
+    // else
+    //    fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+    fprintf(stderr, "GL %s = %s\n", name, v);
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+    if (returnVal != EGL_TRUE) {
+        fprintf(stderr, "%s() returned %d\n", op, returnVal);
+    }
+
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
+        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+                error);
+    }
+}
+
+static void checkGlError(const char* op) {
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+    }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+    "void main() {\n"
+    "  gl_Position = vPosition;\n"
+    "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+    "void main() {\n"
+    "  gl_FragColor = vec4(0.0, 1.0, 0.0, 0.5);\n"
+    "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+    GLuint shader = glCreateShader(shaderType);
+    if (shader) {
+        glShaderSource(shader, 1, &pSource, NULL);
+        glCompileShader(shader);
+        GLint compiled = 0;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    fprintf(stderr, "Could not compile shader %d:\n%s\n",
+                            shaderType, buf);
+                    free(buf);
+                }
+                glDeleteShader(shader);
+                shader = 0;
+            }
+        }
+    }
+    return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+    if (!vertexShader) {
+        return 0;
+    }
+
+    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+    if (!pixelShader) {
+        return 0;
+    }
+
+    GLuint program = glCreateProgram();
+    if (program) {
+        glAttachShader(program, vertexShader);
+        checkGlError("glAttachShader");
+        glAttachShader(program, pixelShader);
+        checkGlError("glAttachShader");
+        glLinkProgram(program);
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    fprintf(stderr, "Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(program);
+            program = 0;
+        }
+    }
+    return program;
+}
+
+GLuint gProgram;
+GLuint gTextureProgram;
+GLuint gvPositionHandle;
+GLuint gvTexturePositionHandle;
+GLuint gvTextureTexCoordsHandle;
+GLuint gvTextureSamplerHandle;
+GLuint gFbo;
+GLuint gTexture;
+GLuint gBufferTexture;
+
+static const char gSimpleVS[] =
+    "attribute vec4 position;\n"
+    "attribute vec2 texCoords;\n"
+    "varying vec2 outTexCoords;\n"
+    "\nvoid main(void) {\n"
+    "    outTexCoords = texCoords;\n"
+    "    gl_Position = position;\n"
+    "}\n\n";
+static const char gSimpleFS[] =
+    "precision mediump float;\n\n"
+    "varying vec2 outTexCoords;\n"
+    "uniform sampler2D texture;\n"
+    "\nvoid main(void) {\n"
+    "    gl_FragColor = texture2D(texture, outTexCoords);\n"
+    "}\n\n";
+
+bool setupGraphics(int w, int h) {
+    gProgram = createProgram(gVertexShader, gFragmentShader);
+    if (!gProgram) {
+        return false;
+    }
+    gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+    checkGlError("glGetAttribLocation");
+    fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n", gvPositionHandle);
+
+    gTextureProgram = createProgram(gSimpleVS, gSimpleFS);
+    if (!gTextureProgram) {
+        return false;
+    }
+    gvTexturePositionHandle = glGetAttribLocation(gTextureProgram, "position");
+    checkGlError("glGetAttribLocation");
+    gvTextureTexCoordsHandle = glGetAttribLocation(gTextureProgram, "texCoords");
+    checkGlError("glGetAttribLocation");
+    gvTextureSamplerHandle = glGetUniformLocation(gTextureProgram, "texture");
+    checkGlError("glGetAttribLocation");
+
+    glActiveTexture(GL_TEXTURE0);
+
+    glGenTextures(1, &gTexture);
+    glBindTexture(GL_TEXTURE_2D, gTexture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glGenTextures(1, &gBufferTexture);
+    glBindTexture(GL_TEXTURE_2D, gBufferTexture);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glGenFramebuffers(1, &gFbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, gFbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gTexture, 0);
+
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    glViewport(0, 0, w, h);
+    checkGlError("glViewport");
+    return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+        0.5f, -0.5f };
+
+const GLint FLOAT_SIZE_BYTES = 4;
+const GLint TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+const GLfloat gTriangleVerticesData[] = {
+    // X, Y, Z, U, V
+    -1.0f, -1.0f, 0, 0.f, 0.f,
+    1.0f, -1.0f, 0, 1.f, 0.f,
+    -1.0f,  1.0f, 0, 0.f, 1.f,
+    1.0f,   1.0f, 0, 1.f, 1.f,
+};
+
+void renderFrame(GLint w, GLint h) {
+    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+    checkGlError("glClearColor");
+    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    checkGlError("glClear");
+
+    // Bind FBO and draw into it
+    glBindFramebuffer(GL_FRAMEBUFFER, gFbo);
+    checkGlError("glBindFramebuffer");
+
+    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+    checkGlError("glClearColor");
+    glClear(GL_COLOR_BUFFER_BIT);
+    checkGlError("glClear");
+
+    glUseProgram(gProgram);
+    checkGlError("glUseProgram");
+
+    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+    checkGlError("glVertexAttribPointer");
+    glEnableVertexAttribArray(gvPositionHandle);
+    checkGlError("glEnableVertexAttribArray");
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+    checkGlError("glDrawArrays");
+
+    // Copy content of FBO into a texture
+    glBindTexture(GL_TEXTURE_2D, gBufferTexture);
+    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w / 2, h / 2);
+    checkGlError("glCopyTexSubImage2D");
+
+    // Back to the display
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    checkGlError("glBindFramebuffer");
+
+    // Draw copied content on the screen
+    glUseProgram(gTextureProgram);
+    checkGlError("glUseProgram");
+
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+    glVertexAttribPointer(gvTexturePositionHandle, 3, GL_FLOAT, GL_FALSE,
+            TRIANGLE_VERTICES_DATA_STRIDE_BYTES, gTriangleVerticesData);
+    checkGlError("glVertexAttribPointer");
+    glVertexAttribPointer(gvTextureTexCoordsHandle, 2, GL_FLOAT, GL_FALSE,
+            TRIANGLE_VERTICES_DATA_STRIDE_BYTES, &gTriangleVerticesData[3]);
+    checkGlError("glVertexAttribPointer");
+    glEnableVertexAttribArray(gvTexturePositionHandle);
+    glEnableVertexAttribArray(gvTextureTexCoordsHandle);
+    checkGlError("glEnableVertexAttribArray");
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    checkGlError("glDrawArrays");
+}
+
+void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+    struct {EGLint attribute; const char* name;} names[] = {
+    X(EGL_BUFFER_SIZE),
+    X(EGL_ALPHA_SIZE),
+    X(EGL_BLUE_SIZE),
+    X(EGL_GREEN_SIZE),
+    X(EGL_RED_SIZE),
+    X(EGL_DEPTH_SIZE),
+    X(EGL_STENCIL_SIZE),
+    X(EGL_CONFIG_CAVEAT),
+    X(EGL_CONFIG_ID),
+    X(EGL_LEVEL),
+    X(EGL_MAX_PBUFFER_HEIGHT),
+    X(EGL_MAX_PBUFFER_PIXELS),
+    X(EGL_MAX_PBUFFER_WIDTH),
+    X(EGL_NATIVE_RENDERABLE),
+    X(EGL_NATIVE_VISUAL_ID),
+    X(EGL_NATIVE_VISUAL_TYPE),
+    X(EGL_SAMPLES),
+    X(EGL_SAMPLE_BUFFERS),
+    X(EGL_SURFACE_TYPE),
+    X(EGL_TRANSPARENT_TYPE),
+    X(EGL_TRANSPARENT_RED_VALUE),
+    X(EGL_TRANSPARENT_GREEN_VALUE),
+    X(EGL_TRANSPARENT_BLUE_VALUE),
+    X(EGL_BIND_TO_TEXTURE_RGB),
+    X(EGL_BIND_TO_TEXTURE_RGBA),
+    X(EGL_MIN_SWAP_INTERVAL),
+    X(EGL_MAX_SWAP_INTERVAL),
+    X(EGL_LUMINANCE_SIZE),
+    X(EGL_ALPHA_MASK_SIZE),
+    X(EGL_COLOR_BUFFER_TYPE),
+    X(EGL_RENDERABLE_TYPE),
+    X(EGL_CONFORMANT),
+   };
+#undef X
+
+    for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+        EGLint value = -1;
+        EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+        EGLint error = eglGetError();
+        if (returnVal && error == EGL_SUCCESS) {
+            printf(" %s: ", names[j].name);
+            printf("%d (0x%x)", value, value);
+        }
+    }
+    printf("\n");
+}
+
+int printEGLConfigurations(EGLDisplay dpy) {
+    EGLint numConfig = 0;
+    EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+    checkEglError("eglGetConfigs", returnVal);
+    if (!returnVal) {
+        return false;
+    }
+
+    printf("Number of EGL configuration: %d\n", numConfig);
+
+    EGLConfig* configs = (EGLConfig*) malloc(sizeof(EGLConfig) * numConfig);
+    if (! configs) {
+        printf("Could not allocate configs.\n");
+        return false;
+    }
+
+    returnVal = eglGetConfigs(dpy, configs, numConfig, &numConfig);
+    checkEglError("eglGetConfigs", returnVal);
+    if (!returnVal) {
+        free(configs);
+        return false;
+    }
+
+    for(int i = 0; i < numConfig; i++) {
+        printf("Configuration %d\n", i);
+        printEGLConfiguration(dpy, configs[i]);
+    }
+
+    free(configs);
+    return true;
+}
+
+int main(int argc, char** argv) {
+    EGLBoolean returnValue;
+    EGLConfig myConfig = {0};
+
+    EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+    EGLint s_configAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            EGL_ALPHA_SIZE, 8,
+            EGL_NONE };
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLSurface surface;
+    EGLint w, h;
+
+    EGLDisplay dpy;
+
+    checkEglError("<init>");
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+    if (dpy == EGL_NO_DISPLAY) {
+        printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+        return 0;
+    }
+
+    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+    checkEglError("eglInitialize", returnValue);
+    fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+    if (returnValue != EGL_TRUE) {
+        printf("eglInitialize failed\n");
+        return 0;
+    }
+
+    if (!printEGLConfigurations(dpy)) {
+        printf("printEGLConfigurations failed\n");
+        return 0;
+    }
+
+    checkEglError("printEGLConfigurations");
+
+    EGLNativeWindowType window = android_createDisplaySurface();
+    EGLint numConfigs = -1, n = 0;
+    eglChooseConfig(dpy, s_configAttribs, 0, 0, &numConfigs);
+    if (numConfigs) {
+        EGLConfig* const configs = new EGLConfig[numConfigs];
+        eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n);
+        myConfig = configs[0];
+        delete[] configs;
+    }
+
+    checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+    printf("Chose this configuration:\n");
+    printEGLConfiguration(dpy, myConfig);
+
+    surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+    checkEglError("eglCreateWindowSurface");
+    if (surface == EGL_NO_SURFACE) {
+        printf("gelCreateWindowSurface failed.\n");
+        return 0;
+    }
+
+    context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, context_attribs);
+    checkEglError("eglCreateContext");
+    if (context == EGL_NO_CONTEXT) {
+        printf("eglCreateContext failed\n");
+        return 0;
+    }
+    returnValue = eglMakeCurrent(dpy, surface, surface, context);
+    checkEglError("eglMakeCurrent", returnValue);
+    if (returnValue != EGL_TRUE) {
+        return 0;
+    }
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+    checkEglError("eglQuerySurface");
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+    checkEglError("eglQuerySurface");
+    GLint dim = w < h ? w : h;
+
+    fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+
+    printGLString("Version", GL_VERSION);
+    printGLString("Vendor", GL_VENDOR);
+    printGLString("Renderer", GL_RENDERER);
+    printGLString("Extensions", GL_EXTENSIONS);
+
+    if(!setupGraphics(w, h)) {
+        fprintf(stderr, "Could not set up graphics.\n");
+        return 0;
+    }
+
+    for (;;) {
+        renderFrame(w, h);
+        eglSwapBuffers(dpy, surface);
+        checkEglError("eglSwapBuffers");
+    }
+
+    return 0;
+}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f3b6c4d..7d6a14d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -44,10 +44,6 @@
 
 namespace android {
 
-template <typename T> inline T min(T a, T b) {
-    return a<b ? a : b;
-}
-
 // ---------------------------------------------------------------------------
 
 Layer::Layer(SurfaceFlinger* flinger,
@@ -56,14 +52,14 @@
         mTextureName(-1U),
         mQueuedFrames(0),
         mCurrentTransform(0),
+        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
         mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
         mOpaqueLayer(true),
         mNeedsDithering(false),
         mSecure(false),
-        mProtectedByApp(false),
-        mFixedSize(false)
+        mProtectedByApp(false)
 {
     mCurrentCrop.makeInvalid();
     glGenTextures(1, &mTextureName);
@@ -356,12 +352,13 @@
     if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
+                "doTransaction: "
                 "resize (layer=%p), requested (%dx%d), drawing (%d,%d), "
-                "fixedSize=%d",
+                "scalingMode=%d",
                 this,
                 int(temp.requested_w), int(temp.requested_h),
                 int(front.requested_w), int(front.requested_h),
-                isFixedSize());
+                mCurrentScalingMode);
 
         if (!isFixedSize()) {
             // we're being resized and there is a freeze display request,
@@ -400,14 +397,7 @@
 }
 
 bool Layer::isFixedSize() const {
-    Mutex::Autolock _l(mLock);
-    return mFixedSize;
-}
-
-void Layer::setFixedSize(bool fixedSize)
-{
-    Mutex::Autolock _l(mLock);
-    mFixedSize = fixedSize;
+    return mCurrentScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
 }
 
 bool Layer::isCropped() const {
@@ -437,9 +427,14 @@
 
         const Rect crop(mSurfaceTexture->getCurrentCrop());
         const uint32_t transform(mSurfaceTexture->getCurrentTransform());
-        if ((crop != mCurrentCrop) || (transform != mCurrentTransform)) {
+        const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
+        if ((crop != mCurrentCrop) ||
+            (transform != mCurrentTransform) ||
+            (scalingMode != mCurrentScalingMode))
+        {
             mCurrentCrop = crop;
             mCurrentTransform = transform;
+            mCurrentScalingMode = scalingMode;
             mFlinger->invalidateHwcGeometry();
         }
 
@@ -459,13 +454,22 @@
         // FIXME: mPostedDirtyRegion = dirty & bounds
         mPostedDirtyRegion.set(front.w, front.h);
 
-        sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
-        if ((newFrontBuffer->getWidth()  == front.requested_w &&
-            newFrontBuffer->getHeight() == front.requested_h) ||
-            isFixedSize())
+
+        if ((front.w != front.requested_w) ||
+            (front.h != front.requested_h))
         {
-            if ((front.w != front.requested_w) ||
-                (front.h != front.requested_h))
+            // check that we received a buffer of the right size
+            // (Take the buffer's orientation into account)
+            sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
+            uint32_t bufWidth  = newFrontBuffer->getWidth();
+            uint32_t bufHeight = newFrontBuffer->getHeight();
+            if (mCurrentTransform & Transform::ROT_90) {
+                swap(bufWidth, bufHeight);
+            }
+
+            if (isFixedSize() ||
+                    (bufWidth == front.requested_w &&
+                    bufHeight == front.requested_h))
             {
                 // Here we pretend the transaction happened by updating the
                 // current and drawing states. Drawing state is only accessed
@@ -485,10 +489,18 @@
 
                 // recompute visible region
                 recomputeVisibleRegions = true;
+
+                // we now have the correct size, unfreeze the screen
+                mFreezeLock.clear();
             }
 
-            // we now have the correct size, unfreeze the screen
-            mFreezeLock.clear();
+            LOGD_IF(DEBUG_RESIZE,
+                    "lockPageFlip : "
+                    "       (layer=%p), buffer (%ux%u, tr=%02x), "
+                    "requested (%dx%d)",
+                    this,
+                    bufWidth, bufHeight, mCurrentTransform,
+                    front.requested_w, front.requested_h);
         }
     }
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e3fc13d..ddfc666 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -59,7 +59,6 @@
     status_t setBuffers(uint32_t w, uint32_t h, 
             PixelFormat format, uint32_t flags=0);
 
-    // Set this Layer's buffers size
     bool isFixedSize() const;
 
     // LayerBase interface
@@ -88,7 +87,6 @@
     void onFrameQueued();
     virtual sp<ISurface> createSurface();
     uint32_t getEffectiveUsage(uint32_t usage) const;
-    void setFixedSize(bool fixedSize);
     bool isCropped() const;
     static bool getOpacityForFormat(uint32_t format);
 
@@ -106,6 +104,7 @@
     GLfloat mTextureMatrix[16];
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
+    uint32_t mCurrentScalingMode;
     bool mCurrentOpacity;
 
     // constants
@@ -124,7 +123,6 @@
 
     // binder thread, transaction thread
     mutable Mutex mLock;
-    bool mFixedSize;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b0881a4..4a27701 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1318,9 +1318,6 @@
         if (surfaceHandle != 0) {
             params->token = token;
             params->identity = layer->getIdentity();
-            params->width = w;
-            params->height = h;
-            params->format = format;
             if (normalLayer != 0) {
                 Mutex::Autolock _l(mStateLock);
                 mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
@@ -1551,8 +1548,18 @@
          * Dump SurfaceFlinger global state
          */
 
-        snprintf(buffer, SIZE, "SurfaceFlinger global state\n");
+        snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
         result.append(buffer);
+
+        const GLExtensions& extensions(GLExtensions::getInstance());
+        snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
+                extensions.getVendor(),
+                extensions.getRenderer(),
+                extensions.getVersion());
+        result.append(buffer);
+        snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
+        result.append(buffer);
+
         mWormholeRegion.dump(result, "WormholeRegion");
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         snprintf(buffer, SIZE,
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 60fa965..91e010f 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -52,6 +52,24 @@
     return res;
 }
 
+status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+
+    status_t res = SurfaceTexture::queueBuffer(buf, timestamp,
+            outWidth, outHeight, outTransform);
+
+    sp<Layer> layer(mLayer.promote());
+    if (layer != NULL) {
+        uint32_t orientation = layer->getOrientation();
+        if (orientation & Transform::ROT_INVALID) {
+            orientation = 0;
+        }
+        *outTransform = orientation;
+    }
+
+    return res;
+}
+
 status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
 
@@ -64,9 +82,6 @@
         //LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x",
         //        __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage);
         res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage);
-        if (res == NO_ERROR) {
-            layer->setFixedSize(w && h);
-        }
     }
     return res;
 }
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 7faff54..29a9cbe 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -45,6 +45,9 @@
     virtual status_t setBufferCount(int bufferCount);
 
 protected:
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+
     virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
             uint32_t format, uint32_t usage);
 };
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 4cedcbf..05b7527 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -20,6 +20,7 @@
 #include <utils/String8.h>
 #include <ui/Region.h>
 
+#include "clz.h"
 #include "Transform.h"
 
 // ---------------------------------------------------------------------------
@@ -28,42 +29,6 @@
 
 // ---------------------------------------------------------------------------
 
-template <typename T>
-static inline T min(T a, T b) {
-    return a<b ? a : b;
-}
-template <typename T>
-static inline T min(T a, T b, T c) {
-    return min(a, min(b, c));
-}
-template <typename T>
-static inline T min(T a, T b, T c, T d) {
-    return min(a, b, min(c, d));
-}
-
-template <typename T>
-static inline T max(T a, T b) {
-    return a>b ? a : b;
-}
-template <typename T>
-static inline T max(T a, T b, T c) {
-    return max(a, max(b, c));
-}
-template <typename T>
-static inline T max(T a, T b, T c, T d) {
-    return max(a, b, max(c, d));
-}
-
-template <typename T>
-static inline
-void swap(T& a, T& b) {
-    T t(a);
-    a = b;
-    b = t;
-}
-
-// ---------------------------------------------------------------------------
-
 Transform::Transform() {
     reset();
 }
@@ -343,7 +308,7 @@
 
 bool Transform::preserveRects() const
 {
-    return (type() & ROT_INVALID) ? false : true;
+    return (getOrientation() & ROT_INVALID) ? false : true;
 }
 
 void Transform::dump(const char* name) const
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
index ca44555..a4c5262 100644
--- a/services/surfaceflinger/clz.h
+++ b/services/surfaceflinger/clz.h
@@ -24,6 +24,41 @@
     return __builtin_clz(x);
 }
 
+template <typename T>
+static inline T min(T a, T b) {
+    return a<b ? a : b;
+}
+template <typename T>
+static inline T min(T a, T b, T c) {
+    return min(a, min(b, c));
+}
+template <typename T>
+static inline T min(T a, T b, T c, T d) {
+    return min(a, b, min(c, d));
+}
+
+template <typename T>
+static inline T max(T a, T b) {
+    return a>b ? a : b;
+}
+template <typename T>
+static inline T max(T a, T b, T c) {
+    return max(a, max(b, c));
+}
+template <typename T>
+static inline T max(T a, T b, T c, T d) {
+    return max(a, b, max(c, d));
+}
+
+template <typename T>
+static inline
+void swap(T& a, T& b) {
+    T t(a);
+    a = b;
+    b = t;
+}
+
+
 }; // namespace android
 
 #endif /* ANDROID_SURFACE_FLINGER_CLZ_H */