Merge "AudioRecord JAVA: expose audio session Id"
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 5b5b731..bc630ae 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -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,6 +92,7 @@
 
     virtual status_t setCrop(const Rect& reg) = 0;
     virtual status_t setTransform(uint32_t transform) = 0;
+    virtual status_t setScalingMode(int mode) = 0;
 
     // getAllocator retrieves the binder object that must be referenced as long
     // as the GraphicBuffers dequeued from this ISurfaceTexture are referenced.
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 4080f27..945f4bc 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -84,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);
 
@@ -185,6 +187,9 @@
     // 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;
+
     // dump our state in a String
     void dump(String8& result) const;
     void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
@@ -220,6 +225,7 @@
               mBufferState(BufferSlot::FREE),
               mRequestBufferCalled(false),
               mTransform(0),
+              mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
               mTimestamp(0) {
             mCrop.makeInvalid();
         }
@@ -281,6 +287,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;
@@ -337,20 +348,24 @@
     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
@@ -361,6 +376,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.
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 5ec469e..829d8ab 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,30 +63,44 @@
     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.
@@ -141,10 +151,28 @@
     // dequeued format or to mReqFormat if no buffer was dequeued.
     uint32_t mQueryFormat;
 
+    // mDefaultWidth is default width of the window, regardless of the
+    // set_dimension call
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight is default width of the window, regardless of the
+    // set_dimension call
+    uint32_t mDefaultHeight;
+
+    // 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/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..9c352ad 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,47 +122,25 @@
         uint32_t    reserved[2];
     };
 
-    static status_t writeToParcel(
-            const sp<Surface>& control, Parcel* parcel);
-
+    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
@@ -194,61 +151,18 @@
     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;
 
-    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/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/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 41434a4..be90e2e 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -43,6 +43,7 @@
     SET_SYNCHRONOUS_MODE,
     CONNECT,
     DISCONNECT,
+    SET_SCALING_MODE,
 };
 
 
@@ -92,12 +93,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;
     }
@@ -130,6 +135,15 @@
         return result;
     }
 
+    virtual status_t setScalingMode(int mode) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(SET_SCALING_MODE, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
+
     virtual sp<IBinder> getAllocator() {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
@@ -216,7 +230,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;
@@ -244,6 +263,13 @@
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
+        case SET_SCALING_MODE: {
+            CHECK_INTERFACE(ISurfaceTexture, data, reply);
+            int mode = data.readInt32();
+            status_t result = setScalingMode(mode);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        } break;
         case GET_ALLOCATOR: {
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             sp<IBinder> result = getAllocator();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9185e1e..c4f9e53 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,12 @@
 {
     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->writeInt32(identity);
-    parcel->writeInt32(width);
-    parcel->writeInt32(height);
-    parcel->writeInt32(format);
-    parcel->writeInt32(flags);
     return NO_ERROR;
 }
 
@@ -277,24 +204,18 @@
 // ---------------------------------------------------------------------------
 
 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();
 }
 
 Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
-    : mInitCheck(NO_INIT)
+    : SurfaceTextureClient()
 {
     mSurface    = interface_cast<ISurface>(ref);
     mIdentity   = parcel.readInt32();
-    mWidth      = parcel.readInt32();
-    mHeight     = parcel.readInt32();
-    mFormat     = parcel.readInt32();
-    mFlags      = parcel.readInt32();
     init();
 }
 
@@ -303,31 +224,16 @@
 {
     sp<ISurface> sur;
     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;
         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);
+             "mSurface = %p, mIdentity = %d",
+             surface->mSurface.get(), surface->mIdentity);
     }
     parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
     parcel->writeInt32(identity);
-    parcel->writeInt32(width);
-    parcel->writeInt32(height);
-    parcel->writeInt32(format);
-    parcel->writeInt32(flags);
     return NO_ERROR;
 
 }
@@ -363,38 +269,19 @@
 
 void Surface::init()
 {
-    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());
         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 +289,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 +307,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 1410481..0f08570 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -90,6 +90,7 @@
     mCurrentTransform(0),
     mCurrentTimestamp(0),
     mNextTransform(0),
+    mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mTexName(tex),
     mSynchronousMode(false),
     mAllowSynchronousMode(allowSynchronousMode),
@@ -401,7 +402,8 @@
     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;
@@ -453,6 +455,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
@@ -461,6 +464,11 @@
     if (listener != 0) {
         listener->onFrameAvailable();
     }
+
+    *outWidth = mDefaultWidth;
+    *outHeight = mDefaultHeight;
+    *outTransform = 0;
+
     return OK;
 }
 
@@ -495,7 +503,7 @@
 }
 
 status_t SurfaceTexture::connect(int api) {
-    LOGV("SurfaceTexture::connect");
+    LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
     Mutex::Autolock lock(mMutex);
     int err = NO_ERROR;
     switch (api) {
@@ -504,6 +512,8 @@
         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;
@@ -517,7 +527,7 @@
 }
 
 status_t SurfaceTexture::disconnect(int api) {
-    LOGV("SurfaceTexture::disconnect");
+    LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
     Mutex::Autolock lock(mMutex);
     int err = NO_ERROR;
     switch (api) {
@@ -528,6 +538,8 @@
             if (mConnectedApi == api) {
                 mConnectedApi = NO_CONNECTED_API;
             } else {
+                LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                        mConnectedApi, api);
                 err = -EINVAL;
             }
             break;
@@ -538,6 +550,22 @@
     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);
@@ -598,6 +626,7 @@
         mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
         mCurrentCrop = mSlots[buf].mCrop;
         mCurrentTransform = mSlots[buf].mTransform;
+        mCurrentScalingMode = mSlots[buf].mScalingMode;
         mCurrentTimestamp = mSlots[buf].mTimestamp;
         computeCurrentTransformMatrix();
 
@@ -805,6 +834,11 @@
     return mCurrentTransform;
 }
 
+uint32_t SurfaceTexture::getCurrentScalingMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentScalingMode;
+}
+
 int SurfaceTexture::query(int what, int* outValue)
 {
     Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f39cabf..1dc6cd2 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -24,24 +24,45 @@
 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),
-        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;
 
+    mReqWidth = 0;
+    mReqHeight = 0;
+    mReqFormat = 0;
+    mReqUsage = 0;
+    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    mQueryWidth = 0;
+    mQueryHeight = 0;
+    mQueryFormat = 0;
+    mConnectedToCpu = false;
+}
+
+void SurfaceTextureClient::setISurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture)
+{
+    mSurfaceTexture = surfaceTexture;
+
     // Get a reference to the allocator.
     mAllocator = mSurfaceTexture->getAllocator();
 }
@@ -50,42 +71,42 @@
     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);
@@ -201,27 +222,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 +292,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 +355,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,28 +370,37 @@
     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);
-    return mSurfaceTexture->connect(api);
+    int err = mSurfaceTexture->connect(api);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = true;
+    }
+    return err;
 }
 
 int SurfaceTextureClient::disconnect(int api) {
     LOGV("SurfaceTextureClient::disconnect");
     Mutex::Autolock lock(mMutex);
-    return mSurfaceTexture->disconnect(api);
+    int err = mSurfaceTexture->disconnect(api);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = false;
+    }
+    return err;
 }
 
-int SurfaceTextureClient::getConnectedApi() const
-{
-    // XXX: This method will be going away shortly, and is currently bogus.  It
-    // always returns "nothing is connected".  It will go away once Surface gets
-    // updated to actually connect as the 'CPU' API when locking a buffer.
-    Mutex::Autolock lock(mMutex);
-    return 0;
-}
-
-
 int SurfaceTextureClient::setUsage(uint32_t reqUsage)
 {
     LOGV("SurfaceTextureClient::setUsage");
@@ -421,6 +476,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");
@@ -443,4 +510,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/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 9c10c75..412552e 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;
@@ -299,14 +311,38 @@
 {
     switch (operation) {
         case NATIVE_WINDOW_SET_USAGE:
-        case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+            // TODO: we should implement this
+            return NO_ERROR;
         case NATIVE_WINDOW_CONNECT:
+            // TODO: we should implement this
+            return NO_ERROR;
         case NATIVE_WINDOW_DISCONNECT:
-            break;
-        default:
-            return NAME_NOT_FOUND;
+            // TODO: we should implement this
+            return NO_ERROR;
+        case NATIVE_WINDOW_LOCK:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_UNLOCK_AND_POST:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_CROP:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_BUFFER_COUNT:
+            // TODO: we should implement this
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+            return INVALID_OPERATION;
+        case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+            // TODO: we should implement this
+            return NO_ERROR;
+        case NATIVE_WINDOW_SET_SCALING_MODE:
+            return INVALID_OPERATION;
     }
-    return NO_ERROR;
+    return NAME_NOT_FOUND;
 }
 
 // ----------------------------------------------------------------------------
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/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/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..e0268fa 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);
@@ -400,14 +396,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 +426,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 +453,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 +488,10 @@
 
                 // 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();
+            }
         }
     }
 }
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 680814c..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);
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 60fa965..11f61cc 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -52,6 +52,20 @@
     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) {
+        *outTransform = layer->getOrientation();
+    }
+
+    return res;
+}
+
 status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
         uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
 
@@ -64,9 +78,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..24d5f9a 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();
 }
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 */