Merge changes I82e361a6,I83694682 into jb-mr2-dev

* changes:
  libgui_test: increase the tolerance for a YUV test
  libgui: fix an EGLImage leak
diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h
index 77da0bf..c89f2d6 100644
--- a/include/media/drm/DrmAPI.h
+++ b/include/media/drm/DrmAPI.h
@@ -1,4 +1,4 @@
- /*
+/*
  * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +22,7 @@
 #include <utils/Vector.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/Mutex.h>
 #include <media/stagefright/foundation/ABase.h>
 
 //  Loadable DrmEngine shared libraries should define the entry points
@@ -34,7 +35,8 @@
 
 namespace android {
 
-    struct DrmPlugin;
+    class DrmPlugin;
+    class DrmPluginListener;
 
     // DRMs are implemented in DrmEngine plugins, which are dynamically
     // loadable shared libraries that implement the entry points
@@ -70,18 +72,18 @@
     class DrmPlugin {
     public:
         enum EventType {
-            kDrmPluginEventProvisionRequired,
-            kDrmPluginEventLicenseNeeded,
-            kDrmPluginEventLicenseExpired,
+            kDrmPluginEventProvisionRequired = 1,
+            kDrmPluginEventKeyNeeded,
+            kDrmPluginEventKeyExpired,
             kDrmPluginEventVendorDefined
         };
 
-        // A license can be for offline content or for online streaming.
-        // Offline licenses are persisted on the device and may be used when the device
+        // Drm keys can be for offline content or for online streaming.
+        // Offline keys are persisted on the device and may be used when the device
         // is disconnected from the network.
-        enum LicenseType {
-            kLicenseType_Offline,
-            kLicenseType_Streaming
+        enum KeyType {
+            kKeyType_Offline,
+            kKeyType_Streaming
         };
 
         DrmPlugin() {}
@@ -94,38 +96,45 @@
         // Close a session on the DrmPlugin object.
         virtual status_t closeSession(Vector<uint8_t> const &sessionId) = 0;
 
-        // A license request/response exchange occurs between the app and a License
-        // Server to obtain the keys required to decrypt the content.  getLicenseRequest()
-        // is used to obtain an opaque license request blob that is delivered to the
+        // A key request/response exchange occurs between the app and a License
+        // Server to obtain the keys required to decrypt the content.  getKeyRequest()
+        // is used to obtain an opaque key request blob that is delivered to the
         // license server.
         //
-        // The init data passed to getLicenseRequest is container-specific and its
+        // The init data passed to getKeyRequest is container-specific and its
         // meaning is interpreted based on the mime type provided in the mimeType
-        // parameter to getLicenseRequest.  It could contain, for example, the content
+        // parameter to getKeyRequest.  It could contain, for example, the content
         // ID, key ID or other data obtained from the content metadata that is required
-        // in generating the license request.
+        // in generating the key request.
         //
-        // licenseType specifes if the license is for streaming or offline content
+        // keyType specifes if the keys are to be used for streaming or offline content
         //
-        // optionalParameters are included in the license server request message to
-        // allow a client application to provide additional message parameters to the
-        // server.
+        // optionalParameters are included in the key request message to allow a
+        // client application to provide additional message parameters to the server.
         //
-        // If successful, the opaque license request blob is returned to the caller.
+        // If successful, the opaque key request blob is returned to the caller.
         virtual status_t
-            getLicenseRequest(Vector<uint8_t> const &sessionId,
-                              Vector<uint8_t> const &initData,
-                              String8 const &mimeType, LicenseType licenseType,
-                              KeyedVector<String8, String8> const &optionalParameters,
-                              Vector<uint8_t> &request, String8 &defaultUrl) = 0;
+            getKeyRequest(Vector<uint8_t> const &sessionId,
+                          Vector<uint8_t> const &initData,
+                          String8 const &mimeType, KeyType keyType,
+                          KeyedVector<String8, String8> const &optionalParameters,
+                          Vector<uint8_t> &request, String8 &defaultUrl) = 0;
 
-        // After a license response is received by the app, it is provided to the
-        // Drm plugin using provideLicenseResponse.
-        virtual status_t provideLicenseResponse(Vector<uint8_t> const &sessionId,
-                                                Vector<uint8_t> const &response) = 0;
+        // After a key response is received by the app, it is provided to the
+        // Drm plugin using provideKeyResponse.  Returns the id of the key set
+        // in keySetId.  The keySetId can be used by removeKeys or restoreKeys
+        // when the keys are used for offline content.
+        virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+                                            Vector<uint8_t> const &response,
+                                            Vector<uint8_t> &keySetId) = 0;
 
-        // Remove the keys associated with a license.
-        virtual status_t removeLicense(Vector<uint8_t> const &sessionId) = 0;
+        // Remove the persisted keys associated with an offline license for a session.
+        virtual status_t removeKeys(Vector<uint8_t> const &keySetId) = 0;
+
+        // Restore persisted offline keys into a new session.  keySetId identifies
+        // the keys to load, obtained from a prior call to provideKeyResponse().
+        virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+                                     Vector<uint8_t> const &keySetId) = 0;
 
         // Request an informative description of the license for the session.  The status
         // is in the form of {name, value} pairs.  Since DRM license policies vary by
@@ -133,12 +142,12 @@
         // Refer to your DRM provider documentation for definitions of the field names
         // for a particular DrmEngine.
         virtual status_t
-            queryLicenseStatus(Vector<uint8_t> const &sessionId,
-                               KeyedVector<String8, String8> &infoMap) const = 0;
+            queryKeyStatus(Vector<uint8_t> const &sessionId,
+                           KeyedVector<String8, String8> &infoMap) const = 0;
 
         // A provision request/response exchange occurs between the app and a
         // provisioning server to retrieve a device certificate.  getProvisionRequest
-        // is used to obtain an opaque license request blob that is delivered to the
+        // is used to obtain an opaque key request blob that is delivered to the
         // provisioning server.
         //
         // If successful, the opaque provision request blob is returned to the caller.
@@ -195,11 +204,105 @@
         virtual status_t setPropertyByteArray(String8 const &name,
                                               Vector<uint8_t> const &value ) = 0;
 
-        // TODO: provide way to send an event
+        // The following methods implement operations on a CryptoSession to support
+        // encrypt, decrypt, sign verify operations on operator-provided
+        // session keys.
+
+        //
+        // The algorithm string conforms to JCA Standard Names for Cipher
+        // Transforms and is case insensitive.  For example "AES/CBC/PKCS5Padding".
+        //
+        // Return OK if the algorithm is supported, otherwise return BAD_VALUE
+        //
+        virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+                                            String8 const &algorithm) = 0;
+
+        //
+        // The algorithm string conforms to JCA Standard Names for Mac
+        // Algorithms and is case insensitive.  For example "HmacSHA256".
+        //
+        // Return OK if the algorithm is supported, otherwise return BAD_VALUE
+        //
+        virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+                                         String8 const &algorithm) = 0;
+
+        // Encrypt the provided input buffer with the cipher algorithm
+        // specified by setCipherAlgorithm and the key selected by keyId,
+        // and return the encrypted data.
+        virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+                                 Vector<uint8_t> const &keyId,
+                                 Vector<uint8_t> const &input,
+                                 Vector<uint8_t> const &iv,
+                                 Vector<uint8_t> &output) = 0;
+
+        // Decrypt the provided input buffer with the cipher algorithm
+        // specified by setCipherAlgorithm and the key selected by keyId,
+        // and return the decrypted data.
+        virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+                                 Vector<uint8_t> const &keyId,
+                                 Vector<uint8_t> const &input,
+                                 Vector<uint8_t> const &iv,
+                                 Vector<uint8_t> &output) = 0;
+
+        // Compute a signature on the provided message using the mac algorithm
+        // specified by setMacAlgorithm and the key selected by keyId,
+        // and return the signature.
+        virtual status_t sign(Vector<uint8_t> const &sessionId,
+                              Vector<uint8_t> const &keyId,
+                              Vector<uint8_t> const &message,
+                              Vector<uint8_t> &signature) = 0;
+
+        // Compute a signature on the provided message using the mac algorithm
+        // specified by setMacAlgorithm and the key selected by keyId,
+        // and compare with the expected result.  Set result to true or
+        // false depending on the outcome.
+        virtual status_t verify(Vector<uint8_t> const &sessionId,
+                                Vector<uint8_t> const &keyId,
+                                Vector<uint8_t> const &message,
+                                Vector<uint8_t> const &signature,
+                                bool &match) = 0;
+
+
+        status_t setListener(const sp<DrmPluginListener>& listener) {
+            Mutex::Autolock lock(mEventLock);
+            mListener = listener;
+            return OK;
+        }
+
+    protected:
+        // Plugins call sendEvent to deliver events to the java app
+        void sendEvent(EventType eventType, int extra,
+                       Vector<uint8_t> const *sessionId,
+                       Vector<uint8_t> const *data);
+
     private:
+        Mutex mEventLock;
+        sp<DrmPluginListener> mListener;
+
         DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
     };
 
+    class DrmPluginListener: virtual public RefBase
+    {
+    public:
+        virtual void sendEvent(DrmPlugin::EventType eventType, int extra,
+                               Vector<uint8_t> const *sesionId,
+                               Vector<uint8_t> const *data) = 0;
+    };
+
+    inline void DrmPlugin::sendEvent(EventType eventType, int extra,
+                                     Vector<uint8_t> const *sessionId,
+                                     Vector<uint8_t> const *data) {
+
+        mEventLock.lock();
+        sp<DrmPluginListener> listener = mListener;
+        mEventLock.unlock();
+
+        if (listener != NULL) {
+            listener->sendEvent(eventType, extra, sessionId, data);
+        }
+    }
+
 }  // namespace android
 
 #endif // DRM_API_H_
diff --git a/include/ui/Region.h b/include/ui/Region.h
index ffcd429..ce91f3b 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -108,6 +108,10 @@
     inline  Region&     operator += (const Point& pt);
 
     
+    // returns true if the regions share the same underlying storage
+    bool isTriviallyEqual(const Region& region) const;
+
+
     /* various ways to access the rectangle list */
 
     
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 488fba3..bf01488 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -239,6 +239,10 @@
     mStorage.add(Rect(w,h));
 }
 
+bool Region::isTriviallyEqual(const Region& region) const {
+    return begin() == region.begin();
+}
+
 // ----------------------------------------------------------------------------
 
 void Region::addRectUnchecked(int l, int t, int r, int b)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 9ee3686..00bfa5a 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -27,9 +27,9 @@
 
 #include <EGL/egl.h>
 
+#include "../glestrace.h"
+
 #include "egldefs.h"
-#include "glestrace.h"
-#include "hooks.h"
 #include "Loader.h"
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index a6e91e0..6ac8724 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -32,11 +32,11 @@
 #include <utils/CallStack.h>
 #include <utils/String8.h>
 
-#include "egldefs.h"
-#include "egl_impl.h"
+#include "../egl_impl.h"
+#include "../glestrace.h"
+
 #include "egl_tls.h"
-#include "glestrace.h"
-#include "hooks.h"
+#include "egldefs.h"
 #include "Loader.h"
 
 #include "egl_display.h"
@@ -387,7 +387,7 @@
 #define EGL_ENTRY(_r, _api, ...) #_api,
 
 char const * const gl_names[] = {
-    #include "entries.in"
+    #include "../entries.in"
     NULL
 };
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1be4961..f6bc069 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -37,13 +37,11 @@
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
-#include "egl_impl.h"
-#include "egl_tls.h"
-#include "glestrace.h"
-#include "hooks.h"
+#include "../egl_impl.h"
+#include "../glestrace.h"
+#include "../hooks.h"
 
 #include "egl_display.h"
-#include "egl_impl.h"
 #include "egl_object.h"
 #include "egl_tls.h"
 #include "egldefs.h"
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 72655df..03397a9 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -14,9 +14,10 @@
  ** limitations under the License.
  */
 
+#include "../egl_impl.h"
+
 #include "egl_cache.h"
 #include "egl_display.h"
-#include "egl_impl.h"
 #include "egldefs.h"
 
 #include <fcntl.h>
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 59dd2d9..1955904 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -18,11 +18,12 @@
 
 #include <string.h>
 
+#include "../egl_impl.h"
+
 #include "egl_cache.h"
 #include "egl_display.h"
 #include "egl_object.h"
 #include "egl_tls.h"
-#include "egl_impl.h"
 #include "Loader.h"
 #include <cutils/properties.h>
 
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 8bb32f4..754085c 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -31,7 +31,7 @@
 #include <utils/String8.h>
 
 #include "egldefs.h"
-#include "hooks.h"
+#include "../hooks.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 2442ca0..56c5dba 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -22,7 +22,6 @@
 #include <EGL/egl.h>
 
 #include "egldefs.h"
-#include "hooks.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index c900c1c..1cfe561 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_EGLDEFS_H
 #define ANDROID_EGLDEFS_H
 
-#include "hooks.h"
+#include "../hooks.h"
 
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 4
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index 1909232..c160aa0 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -21,7 +21,6 @@
 #include <cutils/log.h>
 
 #include "egldefs.h"
-#include "hooks.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index dd454bd..fad2176 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -27,8 +27,8 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
-#include "hooks.h"
-#include "egl_impl.h"
+#include "../hooks.h"
+#include "../egl_impl.h"
 
 using namespace android;
 
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 8ac8ff9..a5bbdc6 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -26,8 +26,8 @@
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
-#include "hooks.h"
-#include "egl_impl.h"
+#include "../hooks.h"
+#include "../egl_impl.h"
 
 using namespace android;
 
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6936a7f..68b0b7f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -143,6 +143,15 @@
     }
 }
 
+void DisplayDevice::disconnect(HWComposer& hwc) {
+    if (mHwcDisplayId >= 0) {
+        hwc.disconnectDisplay(mHwcDisplayId);
+        if (mHwcDisplayId >= DISPLAY_VIRTUAL)
+            hwc.freeDisplayId(mHwcDisplayId);
+        mHwcDisplayId = -1;
+    }
+}
+
 bool DisplayDevice::isValid() const {
     return mFlinger != NULL;
 }
@@ -419,11 +428,11 @@
     const Transform& tr(mGlobalTransform);
     snprintf(buffer, SIZE,
         "+ DisplayDevice: %s\n"
-        "   type=%x, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
+        "   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), "
         "flips=%u, isSecure=%d, secureVis=%d, acquired=%d, numLayers=%u\n"
         "   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
         "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
-        mDisplayName.string(), mType,
+        mDisplayName.string(), mType, mHwcDisplayId,
         mLayerStack, mDisplayWidth, mDisplayHeight, mNativeWindow.get(),
         mOrientation, tr.getType(), getPageFlipCount(),
         mIsSecure, mSecureLayerVisible, mScreenAcquired, mVisibleLayersSortedByZ.size(),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d4a6daa..377d924 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -146,6 +146,9 @@
     bool isScreenAcquired() const;
     bool canDraw() const;
 
+    // release HWC resources (if any) for removable displays
+    void disconnect(HWComposer& hwc);
+
     /* ------------------------------------------------------------------------
      * Debugging
      */
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 1936893..54a3ce8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -33,8 +33,8 @@
 #include <gui/GraphicBufferAlloc.h>
 #include <ui/GraphicBuffer.h>
 
-#include "DisplayHardware/FramebufferSurface.h"
-#include "DisplayHardware/HWComposer.h"
+#include "FramebufferSurface.h"
+#include "HWComposer.h"
 
 #ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
 #define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2)
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 497593b..3f00f07 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include <utils/CallStack.h>
 #include <utils/Errors.h>
 #include <utils/misc.h>
 #include <utils/String8.h>
@@ -37,13 +38,15 @@
 #include <hardware/hardware.h>
 #include <hardware/hwcomposer.h>
 
+#include <android/configuration.h>
+
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
-#include "Layer.h"           // needed only for debugging
 #include "HWComposer.h"
-#include "SurfaceFlinger.h"
-#include <utils/CallStack.h>
+
+#include "../Layer.h"           // needed only for debugging
+#include "../SurfaceFlinger.h"
 
 namespace android {
 
@@ -296,6 +299,11 @@
     mEventHandler.onHotplugReceived(disp, bool(connected));
 }
 
+static float getDefaultDensity(uint32_t height) {
+    if (height >= 1080) return ACONFIGURATION_DENSITY_XHIGH;
+    else                return ACONFIGURATION_DENSITY_TV;
+}
+
 static const uint32_t DISPLAY_ATTRIBUTES[] = {
     HWC_DISPLAY_VSYNC_PERIOD,
     HWC_DISPLAY_WIDTH,
@@ -306,10 +314,6 @@
 };
 #define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
 
-// http://developer.android.com/reference/android/util/DisplayMetrics.html
-#define ANDROID_DENSITY_TV    213
-#define ANDROID_DENSITY_XHIGH 320
-
 status_t HWComposer::queryDisplayProperties(int disp) {
 
     LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
@@ -363,18 +367,26 @@
     mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;
     mDisplayData[disp].connected = true;
     if (mDisplayData[disp].xdpi == 0.0f || mDisplayData[disp].ydpi == 0.0f) {
-        // is there anything smarter we can do?
-        if (h >= 1080) {
-            mDisplayData[disp].xdpi = ANDROID_DENSITY_XHIGH;
-            mDisplayData[disp].ydpi = ANDROID_DENSITY_XHIGH;
-        } else {
-            mDisplayData[disp].xdpi = ANDROID_DENSITY_TV;
-            mDisplayData[disp].ydpi = ANDROID_DENSITY_TV;
-        }
+        float dpi = getDefaultDensity(h);
+        mDisplayData[disp].xdpi = dpi;
+        mDisplayData[disp].ydpi = dpi;
     }
     return NO_ERROR;
 }
 
+status_t HWComposer::setVirtualDisplayProperties(int32_t id,
+        uint32_t w, uint32_t h, uint32_t format) {
+    if (id < VIRTUAL_DISPLAY_ID_BASE || id >= int32_t(mNumDisplays) ||
+            !mAllocatedDisplayIDs.hasBit(id)) {
+        return BAD_INDEX;
+    }
+    mDisplayData[id].width = w;
+    mDisplayData[id].height = h;
+    mDisplayData[id].format = format;
+    mDisplayData[id].xdpi = mDisplayData[id].ydpi = getDefaultDensity(h);
+    return NO_ERROR;
+}
+
 int32_t HWComposer::allocateDisplayId() {
     if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
         return NO_MEMORY;
@@ -415,7 +427,6 @@
     return mDisplayData[disp].lastDisplayFence;
 }
 
-
 uint32_t HWComposer::getWidth(int disp) const {
     return mDisplayData[disp].width;
 }
@@ -953,17 +964,17 @@
         result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
         for (size_t i=0 ; i<mNumDisplays ; i++) {
             const DisplayData& disp(mDisplayData[i]);
+            if (!disp.connected)
+                continue;
 
             const Vector< sp<Layer> >& visibleLayersSortedByZ =
                     mFlinger->getLayerSortedByZForHwcDisplay(i);
 
-            if (disp.connected) {
-                result.appendFormat(
-                        "  Display[%d] : %ux%u, xdpi=%f, ydpi=%f, refresh=%lld\n",
-                        i, disp.width, disp.height, disp.xdpi, disp.ydpi, disp.refresh);
-            }
+            result.appendFormat(
+                    "  Display[%d] : %ux%u, xdpi=%f, ydpi=%f, refresh=%lld\n",
+                    i, disp.width, disp.height, disp.xdpi, disp.ydpi, disp.refresh);
 
-            if (disp.list && disp.connected) {
+            if (disp.list) {
                 result.appendFormat(
                         "  numHwLayers=%u, flags=%08x\n",
                         disp.list->numHwLayers, disp.list->flags);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 58f7e8f..604de38 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -253,6 +253,9 @@
     float getDpiY(int disp) const;
     bool isConnected(int disp) const;
 
+    status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
+            uint32_t format);
+
     // this class is only used to fake the VSync event on systems that don't
     // have it.
     class VSyncThread : public Thread {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index d2b3edb..7e14d95 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -76,7 +76,11 @@
     if (result != NO_ERROR)
         return result;
 
-    return mHwc.fbPost(mDisplayId, fence, mAcquiredBuffer);
+    result = mHwc.fbPost(mDisplayId, fence, mAcquiredBuffer);
+    if (result == NO_ERROR) {
+        result = mHwc.setOutputBuffer(mDisplayId, fence, mAcquiredBuffer);
+    }
+    return result;
 }
 
 void VirtualDisplaySurface::onFrameCommitted() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a4c613c..2302367 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -881,8 +881,7 @@
     return true;
 }
 bool Layer::setTransparentRegionHint(const Region& transparent) {
-    mCurrentState.sequence++;
-    mCurrentState.transparentRegion = transparent;
+    mCurrentState.requestedTransparentRegion = transparent;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1008,7 +1007,6 @@
                     swap(bufWidth, bufHeight);
                 }
 
-
                 bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
                 if (front.active != front.requested) {
 
@@ -1061,6 +1059,17 @@
                         return true;
                     }
                 }
+
+                // if the transparent region has changed (this test is
+                // conservative, but that's fine, worst case we're doing
+                // a bit of extra work), we latch the new one and we
+                // trigger a visible-region recompute.
+                if (!front.activeTransparentRegion.isTriviallyEqual(
+                        front.requestedTransparentRegion)) {
+                    front.activeTransparentRegion = front.requestedTransparentRegion;
+                    recomputeVisibleRegions = true;
+                }
+
                 return false;
             }
         };
@@ -1168,7 +1177,7 @@
             getTypeId(), this, getName().string());
     result.append(buffer);
 
-    s.transparentRegion.dump(result, "transparentRegion");
+    s.activeTransparentRegion.dump(result, "transparentRegion");
     visibleRegion.dump(result, "visibleRegion");
     sp<Client> client(mClientRef.promote());
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6bca941..2765db1 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -103,7 +103,11 @@
         uint8_t reserved[2];
         int32_t sequence; // changes when visible regions can change
         Transform transform;
-        Region transparentRegion;
+        // the transparentRegion hint is a bit special, it's latched only
+        // when we receive a buffer -- this is because it's "content"
+        // dependent.
+        Region activeTransparentRegion;
+        Region requestedTransparentRegion;
     };
 
     class LayerMesh {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3ed8b1b..a4426cd 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1102,12 +1102,14 @@
                         // Call makeCurrent() on the primary display so we can
                         // be sure that nothing associated with this display
                         // is current.
-                        const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-                        DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
-                        mDisplays.removeItem(draw.keyAt(i));
-                        getHwComposer().disconnectDisplay(draw[i].type);
+                        const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice());
+                        DisplayDevice::makeCurrent(mEGLDisplay, defaultDisplay, mEGLContext);
+                        sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i)));
+                        if (hw != NULL)
+                            hw->disconnect(getHwComposer());
                         if (draw[i].type < DisplayDevice::NUM_DISPLAY_TYPES)
                             mEventThread->onHotplugReceived(draw[i].type, false);
+                        mDisplays.removeItem(draw.keyAt(i));
                     } else {
                         ALOGW("trying to remove the main display");
                     }
@@ -1120,6 +1122,9 @@
                         // recreating the DisplayDevice, so we just remove it
                         // from the drawing state, so that it get re-added
                         // below.
+                        sp<DisplayDevice> hw(getDisplayDevice(display));
+                        if (hw != NULL)
+                            hw->disconnect(getHwComposer());
                         mDisplays.removeItem(display);
                         mDrawingState.displays.removeItemsAt(i);
                         dc--; i--;
@@ -1150,9 +1155,13 @@
                     const DisplayDeviceState& state(curr[i]);
 
                     sp<DisplaySurface> dispSurface;
-                    int32_t hwcDisplayId = allocateHwcDisplayId(state.type);
+                    int32_t hwcDisplayId = -1;
                     if (state.isVirtualDisplay()) {
+                        // Virtual displays without a surface are dormant:
+                        // they have external state (layer stack, projection,
+                        // etc.) but no internal state (i.e. a DisplayDevice).
                         if (state.surface != NULL) {
+                            hwcDisplayId = allocateHwcDisplayId(state.type);
                             dispSurface = new VirtualDisplaySurface(
                                     *mHwc, hwcDisplayId, state.surface,
                                     state.displayName);
@@ -1162,7 +1171,7 @@
                                 "adding a supported display, but rendering "
                                 "surface is provided (%p), ignoring it",
                                 state.surface.get());
-
+                        hwcDisplayId = allocateHwcDisplayId(state.type);
                         // for supported (by hwc) displays we provide our
                         // own rendering surface
                         dispSurface = new FramebufferSurface(*mHwc, state.type);
@@ -1178,8 +1187,15 @@
                                 state.viewport, state.frame);
                         hw->setDisplayName(state.displayName);
                         mDisplays.add(display, hw);
-                        if (state.type < DisplayDevice::NUM_DISPLAY_TYPES)
+                        if (state.isVirtualDisplay()) {
+                            if (hwcDisplayId >= 0) {
+                                mHwc->setVirtualDisplayProperties(hwcDisplayId,
+                                        hw->getWidth(), hw->getHeight(),
+                                        hw->getFormat());
+                            }
+                        } else {
                             mEventThread->onHotplugReceived(state.type, true);
+                        }
                     }
                 }
             }
@@ -1360,14 +1376,14 @@
                     if (tr.transformed()) {
                         if (tr.preserveRects()) {
                             // transform the transparent region
-                            transparentRegion = tr.transform(s.transparentRegion);
+                            transparentRegion = tr.transform(s.activeTransparentRegion);
                         } else {
                             // transformation too complex, can't do the
                             // transparent region optimization.
                             transparentRegion.clear();
                         }
                     } else {
-                        transparentRegion = s.transparentRegion;
+                        transparentRegion = s.activeTransparentRegion;
                     }
                 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f0e6deb..57ee8b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -108,9 +108,6 @@
     // utility function to delete a texture on the main thread
     void deleteTextureAsync(GLuint texture);
 
-    // allocate a h/w composer display id
-    int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
-
     // enable/disable h/w composer event
     // TODO: this should be made accessible only to EventThread
     void eventControl(int disp, int event, int enabled);
@@ -338,6 +335,9 @@
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
 
+    // allocate a h/w composer display id
+    int32_t allocateHwcDisplayId(DisplayDevice::DisplayType type);
+
     /* ------------------------------------------------------------------------
      * H/W composer
      */