Merge "b/5080166 Enalbe multi-touch on external touch escreen."
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 1eda646..50626a0 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -111,7 +111,12 @@
     //
     // This method will fail if the connect was previously called on the
     // SurfaceTexture and no corresponding disconnect call was made.
-    virtual status_t connect(int api) = 0;
+    //
+    // 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 connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
 
     // disconnect attempts to disconnect a client API from the SurfaceTexture.
     // Calling this method will cause any subsequent calls to other
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2a8e725..a6fb12e 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -106,7 +106,8 @@
     //
     // This method will fail if the connect was previously called on the
     // SurfaceTexture and no corresponding disconnect call was made.
-    virtual status_t connect(int api);
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
 
     // disconnect attempts to disconnect a client API from the SurfaceTexture.
     // Calling this method will cause any subsequent calls to other
@@ -207,9 +208,28 @@
 
 protected:
 
-    // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
-    // all slots.
-    void freeAllBuffers();
+    // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+    // for the given slot.
+    void freeBufferLocked(int index);
+
+    // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+    // EGLImage) for all slots.
+    void freeAllBuffersLocked();
+
+    // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+    // and EGLImage) for all slots except the head of mQueue
+    void freeAllBuffersExceptHeadLocked();
+
+    // drainQueueLocked drains the buffer queue if we're in synchronous mode
+    // returns immediately otherwise. return NO_INIT if SurfaceTexture
+    // became abandoned or disconnected during this call.
+    status_t drainQueueLocked();
+
+    // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
+    // synchronous mode and free all buffers. In asynchronous mode, all buffers
+    // are freed except the current buffer.
+    status_t drainQueueAndFreeBuffersLocked();
+
     static bool isExternalFormat(uint32_t format);
 
 private:
diff --git a/include/ui/Input.h b/include/ui/Input.h
index c9f694a..f1385a0 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -206,10 +206,17 @@
 
     float getAxisValue(int32_t axis) const;
     status_t setAxisValue(int32_t axis, float value);
-    float* editAxisValue(int32_t axis);
 
     void scale(float scale);
 
+    inline float getX() const {
+        return getAxisValue(AMOTION_EVENT_AXIS_X);
+    }
+
+    inline float getY() const {
+        return getAxisValue(AMOTION_EVENT_AXIS_Y);
+    }
+
 #ifdef HAVE_ANDROID_OS
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index 600017e..9452e86 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -68,6 +68,30 @@
     // Result is undefined if all bits are unmarked.
     inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
 
+    // Finds the first marked bit in the set and clears it.  Returns the bit index.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t clearFirstMarkedBit() {
+        uint32_t n = firstMarkedBit();
+        clearBit(n);
+        return n;
+    }
+
+    // Finds the first unmarked bit in the set and marks it.  Returns the bit index.
+    // Result is undefined if all bits are marked.
+    inline uint32_t markFirstUnmarkedBit() {
+        uint32_t n = firstUnmarkedBit();
+        markBit(n);
+        return n;
+    }
+
+    // Finds the last marked bit in the set and clears it.  Returns the bit index.
+    // Result is undefined if all bits are unmarked.
+    inline uint32_t clearLastMarkedBit() {
+        uint32_t n = lastMarkedBit();
+        clearBit(n);
+        return n;
+    }
+
     // Gets the index of the specified bit in the set, which is the number of
     // marked bits that appear before the specified bit.
     inline uint32_t getIndexOfBit(uint32_t n) const {
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index ca17082..c7a9b78 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -80,9 +80,12 @@
         void                incWeak(const void* id);
         void                decWeak(const void* id);
         
+        // acquires a strong reference if there is already one.
         bool                attemptIncStrong(const void* id);
         
-        //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
+        // acquires a weak reference if there is already one.
+        // This is not always safe. see ProcessState.cpp and BpBinder.cpp
+        // for proper use.
         bool                attemptIncWeak(const void* id);
 
         //! DEBUGGING ONLY: Get current weak ref count.
@@ -116,28 +119,15 @@
 
     typedef RefBase basetype;
 
-    // used to override the RefBase destruction.
-    class Destroyer {
-        friend class RefBase;
-        friend class weakref_type;
-    public:
-        virtual ~Destroyer();
-    private:
-        virtual void destroy(RefBase const* base) = 0;
-    };
-
-    // Make sure to never acquire a strong reference from this function. The
-    // same restrictions than for destructors apply.
-    void setDestroyer(Destroyer* destroyer);
-
 protected:
                             RefBase();
     virtual                 ~RefBase();
 
     //! Flags for extendObjectLifetime()
     enum {
+        OBJECT_LIFETIME_STRONG  = 0x0000,
         OBJECT_LIFETIME_WEAK    = 0x0001,
-        OBJECT_LIFETIME_FOREVER = 0x0003
+        OBJECT_LIFETIME_MASK    = 0x0001
     };
     
             void            extendObjectLifetime(int32_t mode);
@@ -163,7 +153,7 @@
     
                             RefBase(const RefBase& o);
             RefBase&        operator=(const RefBase& o);
-            
+
         weakref_impl* const mRefs;
 };
 
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 3a99979..547e36a 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -38,6 +38,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <time.h>
 
 namespace android {
 
@@ -174,6 +175,20 @@
         size_t uncompLen, size_t compLen);
 
     /*
+     * Utility function to convert ZIP's time format to a timespec struct.
+     */
+    static inline void zipTimeToTimespec(long when, struct tm* timespec) {
+        const long date = when >> 16;
+        timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
+        timespec->tm_mon = (date >> 5) & 0x0F;
+        timespec->tm_mday = date & 0x1F;
+
+        timespec->tm_hour = (when >> 11) & 0x1F;
+        timespec->tm_min = (when >> 5) & 0x3F;
+        timespec->tm_sec = (when & 0x1F) << 1;
+    }
+
+    /*
      * Some basic functions for raw data manipulation.  "LE" means
      * Little Endian.
      */
diff --git a/include/utils/threads.h b/include/utils/threads.h
index c8e9c04..c84a9b4 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <time.h>
+#include <system/graphics.h>
 
 #if defined(HAVE_PTHREADS)
 # include <pthread.h>
@@ -42,8 +43,8 @@
      * ** Keep in sync with android.os.Process.java **
      * ***********************************************
      * 
-     * This maps directly to the "nice" priorites we use in Android.
-     * A thread priority should be chosen inverse-proportinally to
+     * This maps directly to the "nice" priorities we use in Android.
+     * A thread priority should be chosen inverse-proportionally to
      * the amount of work the thread is expected to do. The more work
      * a thread will do, the less favorable priority it should get so that 
      * it doesn't starve the system. Threads not behaving properly might
@@ -66,7 +67,7 @@
     ANDROID_PRIORITY_DISPLAY        =  -4,
     
     /* ui service treads might want to run at a urgent display (uncommon) */
-    ANDROID_PRIORITY_URGENT_DISPLAY =  -8,
+    ANDROID_PRIORITY_URGENT_DISPLAY =  HAL_PRIORITY_URGENT_DISPLAY,
     
     /* all normal audio threads */
     ANDROID_PRIORITY_AUDIO          = -16,
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 55246dc..babd2c0 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -162,11 +162,15 @@
         return result;
     }
 
-    virtual status_t connect(int api) {
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
         data.writeInt32(api);
         remote()->transact(CONNECT, data, &reply);
+        *outWidth = reply.readInt32();
+        *outHeight = reply.readInt32();
+        *outTransform = reply.readInt32();
         status_t result = reply.readInt32();
         return result;
     }
@@ -283,7 +287,12 @@
         case CONNECT: {
             CHECK_INTERFACE(ISurfaceTexture, data, reply);
             int api = data.readInt32();
-            status_t res = connect(api);
+            uint32_t outWidth, outHeight, outTransform;
+            status_t res = connect(api,
+                    &outWidth, &outHeight, &outTransform);
+            reply->writeInt32(outWidth);
+            reply->writeInt32(outHeight);
+            reply->writeInt32(outTransform);
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ccf98e5..2c70251 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -277,6 +277,11 @@
     if (surface == 0) {
        surface = new Surface(data, binder);
        sCachedSurfaces.add(binder, surface);
+    } else {
+        // The Surface was found in the cache, but we still should clear any
+        // remaining data from the parcel.
+        data.readStrongBinder();  // ISurfaceTexture
+        data.readInt32();         // identity
     }
     if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
         surface = 0;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 16755ad..7ac4343 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -104,7 +104,7 @@
 
 SurfaceTexture::~SurfaceTexture() {
     LOGV("SurfaceTexture::~SurfaceTexture");
-    freeAllBuffers();
+    freeAllBuffersLocked();
 }
 
 status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
@@ -154,7 +154,6 @@
         LOGE("setBufferCount: SurfaceTexture has been abandoned!");
         return NO_INIT;
     }
-
     if (bufferCount > NUM_BUFFER_SLOTS) {
         LOGE("setBufferCount: bufferCount larger than slots available");
         return BAD_VALUE;
@@ -168,24 +167,24 @@
         }
     }
 
+    const int minBufferSlots = mSynchronousMode ?
+            MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
     if (bufferCount == 0) {
-        const int minBufferSlots = mSynchronousMode ?
-                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
         mClientBufferCount = 0;
         bufferCount = (mServerBufferCount >= minBufferSlots) ?
                 mServerBufferCount : minBufferSlots;
         return setBufferCountServerLocked(bufferCount);
     }
 
-    // We don't allow the client to set a buffer-count less than
-    // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it.
-    if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) {
+    if (bufferCount < minBufferSlots) {
+        LOGE("setBufferCount: requested buffer count (%d) is less than "
+                "minimum (%d)", bufferCount, minBufferSlots);
         return BAD_VALUE;
     }
 
     // here we're guaranteed that the client doesn't have dequeued buffers
     // and will release all of its buffer references.
-    freeAllBuffers();
+    freeAllBuffersLocked();
     mBufferCount = bufferCount;
     mClientBufferCount = bufferCount;
     mCurrentTexture = INVALID_BUFFER_SLOT;
@@ -228,11 +227,6 @@
         uint32_t format, uint32_t usage) {
     LOGV("SurfaceTexture::dequeueBuffer");
 
-    if (mAbandoned) {
-        LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
-        return NO_INIT;
-    }
-
     if ((w && !h) || (!w && h)) {
         LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
         return BAD_VALUE;
@@ -246,10 +240,15 @@
     int dequeuedCount = 0;
     bool tryAgain = true;
     while (tryAgain) {
+        if (mAbandoned) {
+            LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+            return NO_INIT;
+        }
+
         // We need to wait for the FIFO to drain if the number of buffer
         // needs to change.
         //
-        // The condition "number of buffer needs to change" is true if
+        // The condition "number of buffers needs to change" is true if
         // - the client doesn't care about how many buffers there are
         // - AND the actual number of buffer is different from what was
         //   set in the last setBufferCountServer()
@@ -261,31 +260,24 @@
         // As long as this condition is true AND the FIFO is not empty, we
         // wait on mDequeueCondition.
 
-        int minBufferCountNeeded = mSynchronousMode ?
+        const int minBufferCountNeeded = mSynchronousMode ?
                 MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
 
-        if (!mClientBufferCount &&
+        const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
                 ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded))) {
+                        (mServerBufferCount < minBufferCountNeeded));
+
+        if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
             // wait for the FIFO to drain
-            while (!mQueue.isEmpty()) {
-                mDequeueCondition.wait(mMutex);
-                if (mAbandoned) {
-                    LOGE("dequeueBuffer: SurfaceTexture was abandoned while "
-                            "blocked!");
-                    return NO_INIT;
-                }
-            }
-            minBufferCountNeeded = mSynchronousMode ?
-                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+            mDequeueCondition.wait(mMutex);
+            // NOTE: we continue here because we need to reevaluate our
+            // whole state (eg: we could be abandoned or disconnected)
+            continue;
         }
 
-
-        if (!mClientBufferCount &&
-                ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded))) {
+        if (numberOfBuffersNeedsToChange) {
             // here we're guaranteed that mQueue is empty
-            freeAllBuffers();
+            freeAllBuffersLocked();
             mBufferCount = mServerBufferCount;
             if (mBufferCount < minBufferCountNeeded)
                 mBufferCount = minBufferCountNeeded;
@@ -414,9 +406,9 @@
 
     if (!enabled) {
         // going to asynchronous mode, drain the queue
-        while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
-            mDequeueCondition.wait(mMutex);
-        }
+        err = drainQueueLocked();
+        if (err != NO_ERROR)
+            return err;
     }
 
     if (mSynchronousMode != enabled) {
@@ -548,7 +540,8 @@
     return OK;
 }
 
-status_t SurfaceTexture::connect(int api) {
+status_t SurfaceTexture::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
     LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
     Mutex::Autolock lock(mMutex);
 
@@ -569,6 +562,9 @@
                 err = -EINVAL;
             } else {
                 mConnectedApi = api;
+                *outWidth = mDefaultWidth;
+                *outHeight = mDefaultHeight;
+                *outTransform = 0;
             }
             break;
         default:
@@ -594,7 +590,9 @@
         case NATIVE_WINDOW_API_MEDIA:
         case NATIVE_WINDOW_API_CAMERA:
             if (mConnectedApi == api) {
+                drainQueueAndFreeBuffersLocked();
                 mConnectedApi = NO_CONNECTED_API;
+                mDequeueCondition.signal();
             } else {
                 LOGE("disconnect: connected to another api (cur=%d, req=%d)",
                         mConnectedApi, api);
@@ -628,6 +626,11 @@
     LOGV("SurfaceTexture::updateTexImage");
     Mutex::Autolock lock(mMutex);
 
+    if (mAbandoned) {
+        LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
+        return NO_INIT;
+    }
+
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
     if (!mQueue.empty()) {
@@ -638,6 +641,10 @@
         EGLImageKHR image = mSlots[buf].mEglImage;
         if (image == EGL_NO_IMAGE_KHR) {
             EGLDisplay dpy = eglGetCurrentDisplay();
+            if (mSlots[buf].mGraphicBuffer == 0) {
+                LOGE("buffer at slot %d is null", buf);
+                return BAD_VALUE;
+            }
             image = createImage(dpy, mSlots[buf].mGraphicBuffer);
             mSlots[buf].mEglImage = image;
             mSlots[buf].mEglDisplay = dpy;
@@ -827,18 +834,66 @@
     mFrameAvailableListener = listener;
 }
 
-void SurfaceTexture::freeAllBuffers() {
+void SurfaceTexture::freeBufferLocked(int i) {
+    mSlots[i].mGraphicBuffer = 0;
+    mSlots[i].mBufferState = BufferSlot::FREE;
+    if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void SurfaceTexture::freeAllBuffersLocked() {
+    LOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersLocked called but mQueue is not empty");
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i].mGraphicBuffer = 0;
-        mSlots[i].mBufferState = BufferSlot::FREE;
-        if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
-            mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
-            mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+        freeBufferLocked(i);
+    }
+}
+
+void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
+    LOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+    int head = -1;
+    if (!mQueue.empty()) {
+        Fifo::iterator front(mQueue.begin());
+        head = *front;
+    }
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (i != head) {
+            freeBufferLocked(i);
         }
     }
 }
 
+status_t SurfaceTexture::drainQueueLocked() {
+    while (mSynchronousMode && !mQueue.isEmpty()) {
+        mDequeueCondition.wait(mMutex);
+        if (mAbandoned) {
+            LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
+            return NO_INIT;
+        }
+        if (mConnectedApi == NO_CONNECTED_API) {
+            LOGE("drainQueueLocked: SurfaceTexture is not connected!");
+            return NO_INIT;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
+    status_t err = drainQueueLocked();
+    if (err == NO_ERROR) {
+        if (mSynchronousMode) {
+            freeAllBuffersLocked();
+        } else {
+            freeAllBuffersExceptHeadLocked();
+        }
+    }
+    return err;
+}
+
 EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
         const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -908,8 +963,10 @@
 
 void SurfaceTexture::abandon() {
     Mutex::Autolock lock(mMutex);
-    freeAllBuffers();
+    mQueue.clear();
     mAbandoned = true;
+    mCurrentTextureBuf.clear();
+    freeAllBuffersLocked();
     mDequeueCondition.signal();
 }
 
@@ -965,13 +1022,24 @@
     for (int i=0 ; i<mBufferCount ; i++) {
         const BufferSlot& slot(mSlots[i]);
         snprintf(buffer, SIZE,
-                "%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, "
-                "timestamp=%lld\n",
-                prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState),
+                "%s%s[%02d] "
+                "state=%-8s, crop=[%d,%d,%d,%d], "
+                "transform=0x%02x, timestamp=%lld",
+                prefix, (i==mCurrentTexture)?">":" ", i,
+                stateName(slot.mBufferState),
                 slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom,
                 slot.mTransform, slot.mTimestamp
         );
         result.append(buffer);
+
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        if (buf != NULL) {
+            snprintf(buffer, SIZE,
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride, buf->format);
+            result.append(buffer);
+        }
+        result.append("\n");
     }
 }
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index e6837ea..e91be84 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -258,10 +258,10 @@
     int res = NO_ERROR;
     switch (operation) {
     case NATIVE_WINDOW_CONNECT:
-        res = dispatchConnect(args);
+        // deprecated. must return NO_ERROR.
         break;
     case NATIVE_WINDOW_DISCONNECT:
-        res = dispatchDisconnect(args);
+        // deprecated. must return NO_ERROR.
         break;
     case NATIVE_WINDOW_SET_USAGE:
         res = dispatchSetUsage(args);
@@ -296,6 +296,12 @@
     case NATIVE_WINDOW_SET_SCALING_MODE:
         res = dispatchSetScalingMode(args);
         break;
+    case NATIVE_WINDOW_API_CONNECT:
+        res = dispatchConnect(args);
+        break;
+    case NATIVE_WINDOW_API_DISCONNECT:
+        res = dispatchDisconnect(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -379,7 +385,8 @@
 int SurfaceTextureClient::connect(int api) {
     LOGV("SurfaceTextureClient::connect");
     Mutex::Autolock lock(mMutex);
-    int err = mSurfaceTexture->connect(api);
+    int err = mSurfaceTexture->connect(api,
+            &mDefaultWidth, &mDefaultHeight, &mTransformHint);
     if (!err && api == NATIVE_WINDOW_API_CPU) {
         mConnectedToCpu = true;
     }
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
index 020646b..f24a71d 100644
--- a/libs/ui/EGLUtils.cpp
+++ b/libs/ui/EGLUtils.cpp
@@ -24,8 +24,6 @@
 
 #include <EGL/egl.h>
 
-#include <system/graphics.h>
-
 #include <private/ui/android_natives_priv.h>
 
 // ----------------------------------------------------------------------------
@@ -69,49 +67,31 @@
         return BAD_VALUE;
     
     // Get all the "potential match" configs...
-    if (eglChooseConfig(dpy, attrs, 0, 0, &numConfigs) == EGL_FALSE)
+    if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
         return BAD_VALUE;
 
-    if (numConfigs) {
-        EGLConfig* const configs = new EGLConfig[numConfigs];
-        if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
-            delete [] configs;
-            return BAD_VALUE;
-        }
-
-        bool hasAlpha = false;
-        switch (format) {
-            case HAL_PIXEL_FORMAT_RGBA_8888:
-            case HAL_PIXEL_FORMAT_BGRA_8888:
-            case HAL_PIXEL_FORMAT_RGBA_5551:
-            case HAL_PIXEL_FORMAT_RGBA_4444:
-                hasAlpha = true;
-                break;
-        }
-
-        // The first config is guaranteed to over-satisfy the constraints
-        EGLConfig config = configs[0];
-
-        // go through the list and skip configs that over-satisfy our needs
-        int i;
-        for (i=0 ; i<n ; i++) {
-            if (!hasAlpha) {
-                EGLint alphaSize;
-                eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &alphaSize);
-                if (alphaSize > 0) {
-                    continue;
-                }
-            }
+    EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+    if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+        free(configs);
+        return BAD_VALUE;
+    }
+    
+    int i;
+    EGLConfig config = NULL;
+    for (i=0 ; i<n ; i++) {
+        EGLint nativeVisualId = 0;
+        eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+        if (nativeVisualId>0 && format == nativeVisualId) {
             config = configs[i];
             break;
         }
+    }
 
-        delete [] configs;
-
-        if (i<n) {
-            *outConfig = config;
-            return NO_ERROR;
-        }
+    free(configs);
+    
+    if (i<n) {
+        *outConfig = config;
+        return NO_ERROR;
     }
 
     return NAME_NOT_FOUND;
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 0e8ae61..8949730 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -317,6 +317,8 @@
         case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
         case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
         case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+        case NATIVE_WINDOW_API_CONNECT:
+        case NATIVE_WINDOW_API_DISCONNECT:
             // TODO: we should implement these
             return NO_ERROR;
 
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 33ef1fc..e75415b 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -61,13 +61,19 @@
     const size_t c = list.size();
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
-        snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
-            list.keyAt(i), rec.size/1024.0f, 
-            rec.w, rec.s, rec.h, rec.format, rec.usage);
+        if (rec.size) {
+            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
+                    list.keyAt(i), rec.size/1024.0f,
+                    rec.w, rec.s, rec.h, rec.format, rec.usage);
+        } else {
+            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %8X | 0x%08x\n",
+                    list.keyAt(i),
+                    rec.w, rec.s, rec.h, rec.format, rec.usage);
+        }
         result.append(buffer);
         total += rec.size;
     }
-    snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+    snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
     result.append(buffer);
     if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
         mAllocDev->dump(mAllocDev, buffer, SIZE);
@@ -101,13 +107,19 @@
     if (err == NO_ERROR) {
         Mutex::Autolock _l(sLock);
         KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+        int bpp = bytesPerPixel(format);
+        if (bpp < 0) {
+            // probably a HAL custom format. in any case, we don't know
+            // what its pixel size is.
+            bpp = 0;
+        }
         alloc_rec_t rec;
         rec.w = w;
         rec.h = h;
         rec.s = *stride;
         rec.format = format;
         rec.usage = usage;
-        rec.size = h * stride[0] * bytesPerPixel(format);
+        rec.size = h * stride[0] * bpp;
         list.add(*handle, rec);
     }
 
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0af7f80..688b998 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -280,6 +280,9 @@
     uint64_t axisBit = 1LL << axis;
     uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
     if (!(bits & axisBit)) {
+        if (value == 0) {
+            return OK; // axes with value 0 do not need to be stored
+        }
         uint32_t count = __builtin_popcountll(bits);
         if (count >= MAX_AXES) {
             tooManyAxes(axis);
@@ -294,23 +297,10 @@
     return OK;
 }
 
-float* PointerCoords::editAxisValue(int32_t axis) {
-    if (axis < 0 || axis > 63) {
-        return NULL;
-    }
-
-    uint64_t axisBit = 1LL << axis;
-    if (!(bits & axisBit)) {
-        return NULL;
-    }
-    uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
-    return &values[index];
-}
-
 static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
-    float* value = c.editAxisValue(axis);
-    if (value) {
-        *value *= scaleFactor;
+    float value = c.getAxisValue(axis);
+    if (value != 0) {
+        c.setAxisValue(axis, value * scaleFactor);
     }
 }
 
@@ -574,20 +564,14 @@
     size_t numSamples = mSamplePointerCoords.size();
     for (size_t i = 0; i < numSamples; i++) {
         PointerCoords& c = mSamplePointerCoords.editItemAt(i);
-        float* xPtr = c.editAxisValue(AMOTION_EVENT_AXIS_X);
-        float* yPtr = c.editAxisValue(AMOTION_EVENT_AXIS_Y);
-        if (xPtr && yPtr) {
-            float x = *xPtr + oldXOffset;
-            float y = *yPtr + oldYOffset;
-            matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point);
-            *xPtr = SkScalarToFloat(point.fX) - newXOffset;
-            *yPtr = SkScalarToFloat(point.fY) - newYOffset;
-        }
+        float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
+        float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
+        matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
+        c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
+        c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
 
-        float* orientationPtr = c.editAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
-        if (orientationPtr) {
-            *orientationPtr = transformAngle(matrix, *orientationPtr);
-        }
+        float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+        c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
     }
 }
 
@@ -727,7 +711,7 @@
     }
 
     while (idBits.count() > MAX_POINTERS) {
-        idBits.clearBit(idBits.lastMarkedBit());
+        idBits.clearLastMarkedBit();
     }
 
     Movement& movement = mMovements[mIndex];
@@ -776,7 +760,7 @@
         // We do this on down instead of on up because the client may want to query the
         // final velocity for a pointer that just went up.
         BitSet32 downIdBits;
-        downIdBits.markBit(event->getActionIndex());
+        downIdBits.markBit(event->getPointerId(event->getActionIndex()));
         clearPointers(downIdBits);
         break;
     }
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 693a32a..700b604 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -45,4 +45,4 @@
 )
 
 # Build the manual test programs.
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
index e48d5b7..e21c464 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -52,9 +52,6 @@
     ASSERT_EQ(0, coords.getAxisValue(1))
             << "getAxisValue should return zero because axis is not present";
 
-    ASSERT_EQ(NULL, coords.editAxisValue(0))
-            << "editAxisValue should return null because axis is not present";
-
     // Set first axis.
     ASSERT_EQ(OK, coords.setAxisValue(1, 5));
     ASSERT_EQ(0x00000002ULL, coords.bits);
@@ -96,26 +93,17 @@
     ASSERT_EQ(2, coords.getAxisValue(3))
             << "getAxisValue should return value of axis";
 
-    // Edit an existing axis value in place.
-    valuePtr = coords.editAxisValue(1);
-    ASSERT_EQ(5, *valuePtr)
-            << "editAxisValue should return pointer to axis value";
-
-    *valuePtr = 7;
-    ASSERT_EQ(7, coords.getAxisValue(1))
-            << "getAxisValue should return value of axis";
-
     // Set an axis with an id between the others.  (inserting value in the middle)
     ASSERT_EQ(OK, coords.setAxisValue(2, 1));
     ASSERT_EQ(0x0000000fULL, coords.bits);
     ASSERT_EQ(4, coords.values[0]);
-    ASSERT_EQ(7, coords.values[1]);
+    ASSERT_EQ(5, coords.values[1]);
     ASSERT_EQ(1, coords.values[2]);
     ASSERT_EQ(2, coords.values[3]);
 
     ASSERT_EQ(4, coords.getAxisValue(0))
             << "getAxisValue should return value of axis";
-    ASSERT_EQ(7, coords.getAxisValue(1))
+    ASSERT_EQ(5, coords.getAxisValue(1))
             << "getAxisValue should return value of axis";
     ASSERT_EQ(1, coords.getAxisValue(2))
             << "getAxisValue should return value of axis";
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 8db2009..37d061c 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -49,11 +49,6 @@
 
 // ---------------------------------------------------------------------------
 
-RefBase::Destroyer::~Destroyer() {
-}
-
-// ---------------------------------------------------------------------------
-
 class RefBase::weakref_impl : public RefBase::weakref_type
 {
 public:
@@ -61,7 +56,6 @@
     volatile int32_t    mWeak;
     RefBase* const      mBase;
     volatile int32_t    mFlags;
-    Destroyer*          mDestroyer;
 
 #if !DEBUG_REFS
 
@@ -70,7 +64,6 @@
         , mWeak(0)
         , mBase(base)
         , mFlags(0)
-        , mDestroyer(0)
     {
     }
 
@@ -113,7 +106,7 @@
                 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
                 refs->stack.dump();
-#endif;
+#endif
                 refs = refs->next;
             }
         }
@@ -131,7 +124,7 @@
                 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
 #if DEBUG_REFS_CALLSTACK_ENABLED
                 refs->stack.dump();
-#endif;
+#endif
                 refs = refs->next;
             }
         }
@@ -193,7 +186,7 @@
         String8 text;
 
         {
-            Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
+            Mutex::Autolock _l(mMutex);
             char buf[128];
             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
             text.append(buf);
@@ -318,7 +311,7 @@
         }
     }
 
-    Mutex mMutex;
+    mutable Mutex mMutex;
     ref_entry* mStrongRefs;
     ref_entry* mWeakRefs;
 
@@ -348,7 +341,7 @@
     }
 
     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
-    const_cast<RefBase*>(this)->onFirstRef();
+    refs->mBase->onFirstRef();
 }
 
 void RefBase::decStrong(const void* id) const
@@ -361,13 +354,9 @@
 #endif
     LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
     if (c == 1) {
-        const_cast<RefBase*>(this)->onLastStrongRef(id);
-        if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
-            if (refs->mDestroyer) {
-                refs->mDestroyer->destroy(this);
-            } else {
-                delete this;
-            }
+        refs->mBase->onLastStrongRef(id);
+        if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+            delete this;
         }
     }
     refs->decWeak(id);
@@ -391,7 +380,7 @@
         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
         // fall through...
     case 0:
-        const_cast<RefBase*>(this)->onFirstRef();
+        refs->mBase->onFirstRef();
     }
 }
 
@@ -400,10 +389,6 @@
     return mRefs->mStrong;
 }
 
-void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
-    mRefs->mDestroyer = destroyer;
-}
-
 RefBase* RefBase::weakref_type::refBase() const
 {
     return static_cast<const weakref_impl*>(this)->mBase;
@@ -417,6 +402,7 @@
     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
 }
 
+
 void RefBase::weakref_type::decWeak(const void* id)
 {
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
@@ -424,30 +410,27 @@
     const int32_t c = android_atomic_dec(&impl->mWeak);
     LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
     if (c != 1) return;
-    
-    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+
+    if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+        // This is the regular lifetime case. The object is destroyed
+        // when the last strong reference goes away. Since weakref_impl
+        // outlive the object, it is not destroyed in the dtor, and
+        // we'll have to do it here.
         if (impl->mStrong == INITIAL_STRONG_VALUE) {
-            if (impl->mBase) {
-                if (impl->mDestroyer) {
-                    impl->mDestroyer->destroy(impl->mBase);
-                } else {
-                    delete impl->mBase;
-                }
-            }
+            // Special case: we never had a strong reference, so we need to
+            // destroy the object now.
+            delete impl->mBase;
         } else {
             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
             delete impl;
         }
     } else {
+        // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
         impl->mBase->onLastWeakRef(id);
-        if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
-            if (impl->mBase) {
-                if (impl->mDestroyer) {
-                    impl->mDestroyer->destroy(impl->mBase);
-                } else {
-                    delete impl->mBase;
-                }
-            }
+        if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
+            // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+            // is gone, we can destroy the object.
+            delete impl->mBase;
         }
     }
 }
@@ -569,11 +552,23 @@
 
 RefBase::~RefBase()
 {
-    if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) {
-        if (mRefs->mWeak == 0) {
-            delete mRefs;
+    if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
+        // we never acquired a strong (and/or weak) reference on this object.
+        delete mRefs;
+    } else {
+        // life-time of this object is extended to WEAK or FOREVER, in
+        // which case weakref_impl doesn't out-live the object and we
+        // can free it now.
+        if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
+            // It's possible that the weak count is not 0 if the object
+            // re-acquired a weak reference in its destructor
+            if (mRefs->mWeak == 0) {
+                delete mRefs;
+            }
         }
     }
+    // for debugging purposes, clear this.
+    const_cast<weakref_impl*&>(mRefs) = NULL;
 }
 
 void RefBase::extendObjectLifetime(int32_t mode)
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 8726a53..b97f52f 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -8,7 +8,8 @@
 	ObbFile_test.cpp \
 	Looper_test.cpp \
 	String8_test.cpp \
-	Unicode_test.cpp
+	Unicode_test.cpp \
+	ZipFileRO_test.cpp \
 
 shared_libraries := \
 	libz \
diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp
new file mode 100644
index 0000000..7a1d0bd
--- /dev/null
+++ b/libs/utils/tests/ZipFileRO_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ZipFileRO_test"
+#include <utils/Log.h>
+#include <utils/ZipFileRO.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+class ZipFileROTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+};
+
+TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+    struct tm t;
+
+    // 2011-06-29 14:40:40
+    long when = 0x3EDD7514;
+
+    ZipFileRO::zipTimeToTimespec(when, &t);
+
+    EXPECT_EQ(2011, t.tm_year + 1900)
+            << "Year was improperly converted.";
+
+    EXPECT_EQ(6, t.tm_mon)
+            << "Month was improperly converted.";
+
+    EXPECT_EQ(29, t.tm_mday)
+            << "Day was improperly converted.";
+
+    EXPECT_EQ(14, t.tm_hour)
+            << "Hour was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_min)
+            << "Minute was improperly converted.";
+
+    EXPECT_EQ(40, t.tm_sec)
+            << "Second was improperly converted.";
+}
+
+}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ba5d29a..10cea22 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -363,6 +363,12 @@
         EGLConfig iConfig = dp->configs[intptr_t(config)].config;
         EGLint format;
 
+        if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
+            LOGE("EGLNativeWindowType %p already connected to another API",
+                    window);
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+        }
+
         // set the native window's buffers format to match this config
         if (cnx->egl.eglGetConfigAttrib(iDpy,
                 iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
@@ -371,6 +377,7 @@
                 if (err != 0) {
                     LOGE("error setting native window pixel format: %s (%d)",
                             strerror(-err), err);
+                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
                     return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
                 }
             }
@@ -383,6 +390,10 @@
                     dp->configs[intptr_t(config)].impl, cnx);
             return s;
         }
+
+        // EGLSurface creation failed
+        native_window_set_buffers_format(window, 0);
+        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
     }
     return EGL_NO_SURFACE;
 }
@@ -443,8 +454,12 @@
     EGLBoolean result = s->cnx->egl.eglDestroySurface(
             dp->disp[s->impl].dpy, s->surface);
     if (result == EGL_TRUE) {
-        if (s->win != NULL) {
-            native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
+        ANativeWindow* const window = s->win.get();
+        if (window != NULL) {
+            native_window_set_buffers_format(window, 0);
+            if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) {
+                LOGE("EGLNativeWindowType %p disconnected failed", window);
+            }
         }
         _s.terminate();
     }
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index df53b62..8ca031b 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -48,31 +48,35 @@
     EGLNativeWindowType window = android_createDisplaySurface();
 
     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+    eglInitialize(dpy, &majorVersion, &minorVersion);
     eglGetConfigs(dpy, NULL, 0, &numConfigs);
     printf("# configs = %d\n", numConfigs);
 
     status_t err = EGLUtils::selectConfigForNativeWindow(
             dpy, configAttribs, window, &config);
     if (err) {
-        fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+        fprintf(stderr, "error: %s", EGLUtils::strerror(eglGetError()));
+        eglTerminate(dpy);
         return 0;
     }
 
-    EGLint r,g,b,a;
+    EGLint r,g,b,a, vid;
     eglGetConfigAttrib(dpy, config, EGL_RED_SIZE,   &r);
     eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
     eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE,  &b);
     eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+    eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &vid);
 
     surface = eglCreateWindowSurface(dpy, config, window, NULL);
     if (surface == EGL_NO_SURFACE) {
         EGLint err = eglGetError();
-        fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
-                EGLUtils::strerror(err), config, r,g,b,a);
+        fprintf(stderr, "error: %s, config=%p, format = %d-%d-%d-%d, visual-id = %d\n",
+                EGLUtils::strerror(err), config, r,g,b,a, vid);
+        eglTerminate(dpy);
         return 0;
     } else {
-        printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+        printf("config=%p, format = %d-%d-%d-%d, visual-id = %d\n",
+                config, r,g,b,a, vid);
     }
 
     context = eglCreateContext(dpy, config, NULL, NULL);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index f67c82e..b178e49 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -22,7 +22,7 @@
 	LOCAL_CFLAGS += -DNO_RGBX_8888
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
-	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
+	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
 endif
 
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 7bf3e0a..f4be168 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,6 +40,7 @@
 
 #include "GLExtensions.h"
 #include "HWComposer.h"
+#include "SurfaceFlinger.h"
 
 using namespace android;
 
@@ -75,7 +76,7 @@
         const sp<SurfaceFlinger>& flinger,
         uint32_t dpy)
     : DisplayHardwareBase(flinger, dpy),
-      mFlags(0), mHwc(0)
+      mFlinger(flinger), mFlags(0), mHwc(0)
 {
     init(dpy);
 }
@@ -310,7 +311,7 @@
 
 
     // initialize the H/W composer
-    mHwc = new HWComposer();
+    mHwc = new HWComposer(mFlinger);
     if (mHwc->initCheck() == NO_ERROR) {
         mHwc->setFrameBuffer(mDisplay, mSurface);
     }
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index cdf89fd..40a6f1e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -95,6 +95,7 @@
     void init(uint32_t displayIndex) __attribute__((noinline));
     void fini() __attribute__((noinline));
 
+    sp<SurfaceFlinger> mFlinger;
     EGLDisplay      mDisplay;
     EGLSurface      mSurface;
     EGLContext      mContext;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 30eb258..3ebc7b6 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -37,7 +37,7 @@
 
                 ~DisplayHardwareBase();
 
-    // console managment
+    // console management
     void releaseScreen() const;
     void acquireScreen() const;
     bool isScreenAcquired() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a3b20d..7d1bdf0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,12 +30,14 @@
 #include <EGL/egl.h>
 
 #include "HWComposer.h"
+#include "SurfaceFlinger.h"
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-HWComposer::HWComposer()
-    : mModule(0), mHwc(0), mList(0), mCapacity(0),
+HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+    : mFlinger(flinger),
+      mModule(0), mHwc(0), mList(0), mCapacity(0),
       mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
 {
     int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
@@ -44,6 +46,13 @@
         err = hwc_open(mModule, &mHwc);
         LOGE_IF(err, "%s device failed to initialize (%s)",
                 HWC_HARDWARE_COMPOSER, strerror(-err));
+        if (err == 0) {
+            if (mHwc->registerProcs) {
+                mCBContext.hwc = this;
+                mCBContext.procs.invalidate = &hook_invalidate;
+                mHwc->registerProcs(mHwc, &mCBContext.procs);
+            }
+        }
     }
 }
 
@@ -58,6 +67,14 @@
     return mHwc ? NO_ERROR : NO_INIT;
 }
 
+void HWComposer::hook_invalidate(struct hwc_procs* procs) {
+    reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+}
+
+void HWComposer::invalidate() {
+    mFlinger->signalEvent();
+}
+
 void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
     mDpy = (hwc_display_t)dpy;
     mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5a9e9eb..983898a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -24,16 +24,19 @@
 
 #include <hardware/hwcomposer.h>
 
+#include <utils/StrongPointer.h>
+
 namespace android {
 // ---------------------------------------------------------------------------
 
 class String8;
+class SurfaceFlinger;
 
 class HWComposer
 {
 public:
 
-    HWComposer();
+    HWComposer(const sp<SurfaceFlinger>& flinger);
     ~HWComposer();
 
     status_t initCheck() const;
@@ -60,12 +63,21 @@
     void dump(String8& out, char* scratch, size_t SIZE) const;
 
 private:
+    struct cb_context {
+        hwc_procs_t procs;
+        HWComposer* hwc;
+    };
+    static void hook_invalidate(struct hwc_procs* procs);
+    void invalidate();
+
+    sp<SurfaceFlinger>      mFlinger;
     hw_module_t const*      mModule;
     hwc_composer_device_t*  mHwc;
     hwc_layer_list_t*       mList;
     size_t                  mCapacity;
     hwc_display_t           mDpy;
     hwc_surface_t           mSur;
+    cb_context              mCBContext;
 };
 
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7d6a14d..0425fc3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -65,14 +65,9 @@
     glGenTextures(1, &mTextureName);
 }
 
-void Layer::destroy(RefBase const* base) {
-    mFlinger->destroyLayer(static_cast<LayerBase const*>(base));
-}
-
 void Layer::onFirstRef()
 {
     LayerBaseClient::onFirstRef();
-    setDestroyer(this);
 
     struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
         FrameQueuedListener(Layer* layer) : mLayer(layer) { }
@@ -93,7 +88,16 @@
 
 Layer::~Layer()
 {
-    glDeleteTextures(1, &mTextureName);
+    class MessageDestroyGLState : public MessageBase {
+        GLuint texture;
+    public:
+        MessageDestroyGLState(GLuint texture) : texture(texture) { }
+        virtual bool handler() {
+            glDeleteTextures(1, &texture);
+            return true;
+        }
+    };
+    mFlinger->postMessageAsync( new MessageDestroyGLState(mTextureName) );
 }
 
 void Layer::onFrameQueued() {
@@ -105,6 +109,7 @@
 // in the purgatory list
 void Layer::onRemoved()
 {
+    mSurfaceTexture->abandon();
 }
 
 sp<ISurface> Layer::createSurface()
@@ -171,17 +176,14 @@
 
 void Layer::setGeometry(hwc_layer_t* hwcl)
 {
-    hwcl->compositionType = HWC_FRAMEBUFFER;
-    hwcl->hints = 0;
-    hwcl->flags = 0;
-    hwcl->transform = 0;
-    hwcl->blending = HWC_BLENDING_NONE;
+    LayerBaseClient::setGeometry(hwcl);
+
+    hwcl->flags &= ~HWC_SKIP_LAYER;
 
     // we can't do alpha-fade with the hwc HAL
     const State& s(drawingState());
     if (s.alpha < 0xFF) {
         hwcl->flags = HWC_SKIP_LAYER;
-        return;
     }
 
     /*
@@ -189,14 +191,13 @@
      * 1) buffer orientation/flip/mirror
      * 2) state transformation (window manager)
      * 3) layer orientation (screen orientation)
+     * mOrientation is already the composition of (2) and (3)
      * (NOTE: the matrices are multiplied in reverse order)
      */
 
     const Transform bufferOrientation(mCurrentTransform);
-    const Transform& stateTransform(s.transform);
     const Transform layerOrientation(mOrientation);
-
-    const Transform tr(layerOrientation * stateTransform * bufferOrientation);
+    const Transform tr(layerOrientation * bufferOrientation);
 
     // this gives us only the "orientation" component of the transform
     const uint32_t finalTransform = tr.getOrientation();
@@ -204,26 +205,9 @@
     // we can only handle simple transformation
     if (finalTransform & Transform::ROT_INVALID) {
         hwcl->flags = HWC_SKIP_LAYER;
-        return;
+    } else {
+        hwcl->transform = finalTransform;
     }
-
-    hwcl->transform = finalTransform;
-
-    if (!isOpaque()) {
-        hwcl->blending = mPremultipliedAlpha ?
-                HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
-    }
-
-    // scaling is already applied in mTransformedBounds
-    hwcl->displayFrame.left   = mTransformedBounds.left;
-    hwcl->displayFrame.top    = mTransformedBounds.top;
-    hwcl->displayFrame.right  = mTransformedBounds.right;
-    hwcl->displayFrame.bottom = mTransformedBounds.bottom;
-
-    hwcl->visibleRegionScreen.rects =
-            reinterpret_cast<hwc_rect_t const *>(
-                    visibleRegionScreen.getArray(
-                            &hwcl->visibleRegionScreen.numRects));
 }
 
 void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -234,9 +218,9 @@
         // HWC handle it.
         hwcl->flags |= HWC_SKIP_LAYER;
         hwcl->handle = NULL;
-        return;
+    } else {
+        hwcl->handle = buffer->handle;
     }
-    hwcl->handle = buffer->handle;
 
     if (isCropped()) {
         hwcl->sourceCrop.left   = mCurrentCrop.left;
@@ -246,8 +230,13 @@
     } else {
         hwcl->sourceCrop.left   = 0;
         hwcl->sourceCrop.top    = 0;
-        hwcl->sourceCrop.right  = buffer->width;
-        hwcl->sourceCrop.bottom = buffer->height;
+        if (buffer != NULL) {
+            hwcl->sourceCrop.right  = buffer->width;
+            hwcl->sourceCrop.bottom = buffer->height;
+        } else {
+            hwcl->sourceCrop.right  = mTransformedBounds.width();
+            hwcl->sourceCrop.bottom = mTransformedBounds.height();
+        }
     }
 }
 
@@ -326,8 +315,9 @@
 {
     // if we don't have a buffer yet, we're translucent regardless of the
     // layer's opaque flag.
-    if (mActiveBuffer == 0)
+    if (mActiveBuffer == 0) {
         return false;
+    }
 
     // if the layer has the opaque flag, then we're always opaque,
     // otherwise we use the current buffer's format.
@@ -411,6 +401,8 @@
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
     if (mQueuedFrames > 0) {
+        const bool oldOpacity = isOpaque();
+
         // signal another event if we have more frames pending
         if (android_atomic_dec(&mQueuedFrames) > 1) {
             mFlinger->signalEvent();
@@ -438,9 +430,8 @@
             mFlinger->invalidateHwcGeometry();
         }
 
-        const bool opacity(getOpacityForFormat(mActiveBuffer->format));
-        if (opacity != mCurrentOpacity) {
-            mCurrentOpacity = opacity;
+        mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+        if (oldOpacity != isOpaque()) {
             recomputeVisibleRegions = true;
         }
 
@@ -545,7 +536,7 @@
     }
     snprintf(buffer, SIZE,
             "      "
-            "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+            "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
             " freezeLock=%p, queued-frames=%d\n",
             mFormat, w0, h0, s0,f0,
             getFreezeLock().get(), mQueuedFrames);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ddfc666..d3ddab4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,7 +45,7 @@
 
 // ---------------------------------------------------------------------------
 
-class Layer : public LayerBaseClient, private RefBase::Destroyer
+class Layer : public LayerBaseClient
 {
 public:
             Layer(SurfaceFlinger* flinger, DisplayID display,
@@ -78,7 +78,6 @@
     inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
 
 protected:
-    virtual void destroy(RefBase const* base);
     virtual void onFirstRef();
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index c86c659..e04c533 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -302,13 +302,47 @@
     }
 }
 
-void LayerBase::setGeometry(hwc_layer_t* hwcl) {
-    hwcl->flags |= HWC_SKIP_LAYER;
+void LayerBase::setGeometry(hwc_layer_t* hwcl)
+{
+    hwcl->compositionType = HWC_FRAMEBUFFER;
+    hwcl->hints = 0;
+    hwcl->flags = HWC_SKIP_LAYER;
+    hwcl->transform = 0;
+    hwcl->blending = HWC_BLENDING_NONE;
+
+    // this gives us only the "orientation" component of the transform
+    const State& s(drawingState());
+    const uint32_t finalTransform = s.transform.getOrientation();
+    // we can only handle simple transformation
+    if (finalTransform & Transform::ROT_INVALID) {
+        hwcl->flags = HWC_SKIP_LAYER;
+    } else {
+        hwcl->transform = finalTransform;
+    }
+
+    if (!isOpaque()) {
+        hwcl->blending = mPremultipliedAlpha ?
+                HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+    }
+
+    // scaling is already applied in mTransformedBounds
+    hwcl->displayFrame.left   = mTransformedBounds.left;
+    hwcl->displayFrame.top    = mTransformedBounds.top;
+    hwcl->displayFrame.right  = mTransformedBounds.right;
+    hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+    hwcl->visibleRegionScreen.rects =
+            reinterpret_cast<hwc_rect_t const *>(
+                    visibleRegionScreen.getArray(
+                            &hwcl->visibleRegionScreen.numRects));
 }
 
 void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
     hwcl->compositionType = HWC_FRAMEBUFFER;
     hwcl->handle = NULL;
+    hwcl->sourceCrop.left   = 0;
+    hwcl->sourceCrop.top    = 0;
+    hwcl->sourceCrop.right  = mTransformedBounds.width();
+    hwcl->sourceCrop.bottom = mTransformedBounds.height();
 }
 
 void LayerBase::setFiltering(bool filtering)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a27701..082effe 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -402,9 +402,6 @@
 {
     waitForEvent();
 
-    // call Layer's destructor
-    handleDestroyLayers();
-
     // check for transactions
     if (UNLIKELY(mConsoleSignals)) {
         handleConsoleEvents();
@@ -597,31 +594,6 @@
     commitTransaction();
 }
 
-void SurfaceFlinger::destroyLayer(LayerBase const* layer)
-{
-    Mutex::Autolock _l(mDestroyedLayerLock);
-    mDestroyedLayers.add(layer);
-    signalEvent();
-}
-
-void SurfaceFlinger::handleDestroyLayers()
-{
-    Vector<LayerBase const *> destroyedLayers;
-
-    { // scope for the lock
-        Mutex::Autolock _l(mDestroyedLayerLock);
-        destroyedLayers = mDestroyedLayers;
-        mDestroyedLayers.clear();
-    }
-
-    // call destructors without a lock held
-    const size_t count = destroyedLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        //LOGD("destroying %s", destroyedLayers[i]->getName().string());
-        delete destroyedLayers[i];
-    }
-}
-
 sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
 {
     return new FreezeLock(const_cast<SurfaceFlinger *>(this));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 15661f0..6f93f5b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -189,7 +189,6 @@
     status_t addLayer(const sp<LayerBase>& layer);
     status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
     void invalidateHwcGeometry();
-    void destroyLayer(LayerBase const* layer);
 
     sp<Layer> getLayer(const sp<ISurface>& sur) const;
 
@@ -266,7 +265,6 @@
             void        handleConsoleEvents();
             void        handleTransaction(uint32_t transactionFlags);
             void        handleTransactionLocked(uint32_t transactionFlags);
-            void        handleDestroyLayers();
 
             void        computeVisibleRegions(
                             const LayerVector& currentLayers,
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 91e010f..79cd0c3 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -86,6 +86,42 @@
     return res;
 }
 
+status_t SurfaceTextureLayer::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    status_t err = SurfaceTexture::connect(api,
+            outWidth, outHeight, outTransform);
+    if (err == NO_ERROR) {
+        sp<Layer> layer(mLayer.promote());
+        if (layer != NULL) {
+            uint32_t orientation = layer->getOrientation();
+            if (orientation & Transform::ROT_INVALID) {
+                orientation = 0;
+            }
+            *outTransform = orientation;
+        }
+        switch(api) {
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                // Camera preview and videos are rate-limited on the producer
+                // side.  If enabled for this build, we use async mode to always
+                // show the most recent frame at the cost of requiring an
+                // additional buffer.
+#ifndef NEVER_DEFAULT_TO_ASYNC_MODE
+                err = setSynchronousMode(false);
+                break;
+#endif
+                // fall through to set synchronous mode when not defaulting to
+                // async mode.
+            deafult:
+                err = setSynchronousMode(true);
+                break;
+        }
+        if (err != NO_ERROR) {
+            disconnect(api);
+        }
+    }
+    return err;
+}
 
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 29a9cbe..9508524 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -50,6 +50,9 @@
 
     virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
             uint32_t format, uint32_t usage);
+
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
 };
 
 // ---------------------------------------------------------------------------