Merge "Fix issue #2461567: Home screen redraw messed up"
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 9808832..0279d84 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -210,9 +210,16 @@
 
     status_t dequeueBuffer(sp<GraphicBuffer>* buffer);
 
+    void dispatch_setUsage(va_list args);
+    int  dispatch_connect(va_list args);
+    int  dispatch_disconnect(va_list args);
     
     void setUsage(uint32_t reqUsage);
+    int  connect(int api);
+    int  disconnect(int api);
+
     uint32_t getUsage() const;
+    int      getConnectedApi() const;
     
     // constants
     sp<SurfaceComposerClient>   mClient;
@@ -227,6 +234,7 @@
     // protected by mSurfaceLock
     Rect                        mSwapRectangle;
     uint32_t                    mUsage;
+    int                         mConnected;
     
     // protected by mSurfaceLock. These are also used from lock/unlock
     // but in that case, they must be called form the same thread.
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 3740db5..773fd93 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -69,7 +69,14 @@
 
 /* valid operations for the (*perform)() hook */
 enum {
-    NATIVE_WINDOW_SET_USAGE = 0
+    NATIVE_WINDOW_SET_USAGE  = 0,
+    NATIVE_WINDOW_CONNECT    = 1,
+    NATIVE_WINDOW_DISCONNECT = 2
+};
+
+/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
+enum {
+    NATIVE_WINDOW_API_EGL = 1
 };
 
 typedef struct android_native_window_t 
@@ -157,8 +164,13 @@
      * This hook should not be called directly, instead use the helper functions
      * defined below.
      * 
+     *  (*perform)() returns -ENOENT if the 'what' parameter is not supported
+     *  by the surface's implementation.
+     *
      * The valid operations are:
      *     NATIVE_WINDOW_SET_USAGE
+     *     NATIVE_WINDOW_CONNECT
+     *     NATIVE_WINDOW_DISCONNECT
      *  
      */
     
@@ -185,6 +197,30 @@
     return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
 }
 
+/*
+ * native_window_connect(..., NATIVE_WINDOW_API_EGL) must be called
+ * by EGL when the window is made current.
+ * Returns -EINVAL if for some reason the window cannot be connected, which
+ * can happen if it's connected to some other API.
+ */
+static inline int native_window_connect(
+        android_native_window_t* window, int api)
+{
+    return window->perform(window, NATIVE_WINDOW_CONNECT, api);
+}
+
+/*
+ * native_window_disconnect(..., NATIVE_WINDOW_API_EGL) must be called
+ * by EGL when the window is made not current.
+ * An error is returned if for instance the window wasn't connected in the
+ * first place.
+ */
+static inline int native_window_disconnect(
+        android_native_window_t* window, int api)
+{
+    return window->perform(window, NATIVE_WINDOW_DISCONNECT, api);
+}
+
 
 // ---------------------------------------------------------------------------
 
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index fdf6627..140f10c 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -54,7 +54,7 @@
       mOrientation(0),
       mLeft(0), mTop(0),
       mTransactionFlags(0),
-      mPremultipliedAlpha(true),
+      mPremultipliedAlpha(true), mDebug(false),
       mInvalidate(0)
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
@@ -65,6 +65,14 @@
 {
 }
 
+void LayerBase::setName(const String8& name) {
+    mName = name;
+}
+
+String8 LayerBase::getName() const {
+    return mName;
+}
+
 const GraphicPlane& LayerBase::graphicPlane(int dpy) const
 { 
     return mFlinger->graphicPlane(dpy);
@@ -698,8 +706,7 @@
 
 LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-    : LayerBase(flinger, display), lcblk(NULL), client(client),
-      mDebug(false), mIndex(i),
+    : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),
       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
 {
     lcblk = new SharedBufferServer(
@@ -724,14 +731,6 @@
     delete lcblk;
 }
 
-void LayerBaseClient::setName(const String8& name) {
-    mName = name;
-}
-
-String8 LayerBaseClient::getName() const {
-    return mName;
-}
-
 int32_t LayerBaseClient::serverIndex() const 
 {
     sp<Client> client(this->client.promote());
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 852b9f9..a6e5644 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -101,6 +101,9 @@
                 Region          transparentRegion;
             };
 
+            void setName(const String8& name);
+            String8 getName() const;
+
             // modify current state
             bool setPosition(int32_t x, int32_t y);
             bool setLayer(uint32_t z);
@@ -121,7 +124,7 @@
             void drawRegion(const Region& reg) const;
 
             void invalidate();
-            
+
     /**
      * draw - performs some global clipping optimizations
      * and calls onDraw().
@@ -287,6 +290,9 @@
 
                 // don't change, don't need a lock
                 bool            mPremultipliedAlpha;
+                String8         mName;
+    mutable     bool            mDebug;
+
 
                 // atomic
     volatile    int32_t         mInvalidate;
@@ -320,8 +326,6 @@
             const sp<Client>& client, int32_t i);
     virtual ~LayerBaseClient();
     virtual void onFirstRef();
-    void setName(const String8& name);
-    String8 getName() const;
 
     const wp<Client>    client;
 
@@ -369,15 +373,11 @@
 
     friend class Surface;
 
-protected:
-    mutable     bool            mDebug;
-
 private:
                 int32_t         mIndex;
     mutable     Mutex           mLock;
     mutable     wp<Surface>     mClientSurface;
     // only read
-                String8         mName;
     const       uint32_t        mIdentity;
     static      int32_t         sIdentity;
 };
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index b2d5856..175f989 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -65,17 +65,14 @@
 Transform::~Transform() {
 }
 
-
-bool Transform::absIsOne(float f) {
-    return fabs(f) == 1.0f;
-}
+static const float EPSILON = 0.0f;
 
 bool Transform::isZero(float f) {
-    return fabs(f) == 0.0f;
+    return fabs(f) <= EPSILON;
 }
 
-bool Transform::absEqual(float a, float b) {
-    return fabs(a) == fabs(b);
+bool Transform::absIsOne(float f) {
+    return isZero(fabs(f) - 1.0f);
 }
 
 Transform Transform::operator * (const Transform& rhs) const
@@ -154,8 +151,14 @@
     mType = UNKNOWN_TYPE;
 }
 
-void Transform::set(uint32_t flags, float w, float h)
+status_t Transform::set(uint32_t flags, float w, float h)
 {
+    if (flags & ROT_INVALID) {
+        // that's not allowed!
+        reset();
+        return BAD_VALUE;
+    }
+
     mType = flags << 8;
     float sx = (flags & FLIP_H) ? -1 : 1;
     float sy = (flags & FLIP_V) ? -1 : 1;
@@ -205,6 +208,8 @@
     M[0][0] = a;    M[1][0] = b;    M[2][0] = x;
     M[0][1] = c;    M[1][1] = d;    M[2][1] = y;
     M[0][2] = 0;    M[1][2] = 0;    M[2][2] = 1;
+
+    return NO_ERROR;
 }
 
 Transform::vec2 Transform::transform(const vec2& v) const {
@@ -295,25 +300,17 @@
         bool scale = false;
         uint32_t flags = ROT_0;
         if (isZero(b) && isZero(c)) {
-            if (absEqual(a, d)) {
-                if (a<0)    flags |= FLIP_H;
-                if (d<0)    flags |= FLIP_V;
-                if (!absIsOne(a) || !absIsOne(d)) {
-                    scale = true;
-                }
-            } else {
-                flags = ROT_INVALID;
+            if (a<0)    flags |= FLIP_H;
+            if (d<0)    flags |= FLIP_V;
+            if (!absIsOne(a) || !absIsOne(d)) {
+                scale = true;
             }
         } else if (isZero(a) && isZero(d)) {
-            if (absEqual(b, c)) {
-                flags |= ROT_90;
-                if (b>0)    flags |= FLIP_H;
-                if (c<0)    flags |= FLIP_V;
-                if (!absIsOne(b) || !absIsOne(c)) {
-                    scale = true;
-                }
-            } else {
-                flags = ROT_INVALID;
+            flags |= ROT_90;
+            if (b>0)    flags |= FLIP_H;
+            if (c<0)    flags |= FLIP_V;
+            if (!absIsOne(b) || !absIsOne(c)) {
+                scale = true;
             }
         } else {
             flags = ROT_INVALID;
@@ -361,15 +358,22 @@
     const mat33& m(mMatrix);
     uint32_t orient = mType >> 8;
 
-    if (orient&ROT_INVALID)
+    if (orient&ROT_INVALID) {
         flags.append("ROT_INVALID ");
-    if (orient&ROT_90)
-        flags.append("ROT_90 ");
-    if (orient&FLIP_V)
-        flags.append("FLIP_V ");
-    if (orient&FLIP_H)
-        flags.append("FLIP_H ");
+    } else {
+        if (orient&ROT_90) {
+            flags.append("ROT_90 ");
+        } else {
+            flags.append("ROT_0 ");
+        }
+        if (orient&FLIP_V)
+            flags.append("FLIP_V ");
+        if (orient&FLIP_H)
+            flags.append("FLIP_H ");
+    }
 
+    if (!(mType&(SCALE|ROTATE|TRANSLATE)))
+        type.append("IDENTITY ");
     if (mType&SCALE)
         type.append("SCALE ");
     if (mType&ROTATE)
@@ -377,10 +381,10 @@
     if (mType&TRANSLATE)
         type.append("TRANSLATE ");
 
-    LOGD("%s (%s, %s)", name, flags.string(), type.string());
-    LOGD("%.2f  %.2f  %.2f", m[0][0], m[1][0], m[2][0]);
-    LOGD("%.2f  %.2f  %.2f", m[0][1], m[1][1], m[2][1]);
-    LOGD("%.2f  %.2f  %.2f", m[0][2], m[1][2], m[2][2]);
+    LOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
+    LOGD("%.4f  %.4f  %.4f", m[0][0], m[1][0], m[2][0]);
+    LOGD("%.4f  %.4f  %.4f", m[0][1], m[1][1], m[2][1]);
+    LOGD("%.4f  %.4f  %.4f", m[0][2], m[1][2], m[2][2]);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
index 51d3e3f..2e5b893 100644
--- a/libs/surfaceflinger/Transform.h
+++ b/libs/surfaceflinger/Transform.h
@@ -69,10 +69,10 @@
             int     ty() const;
 
             // modify the transform
-            void    reset();
-            void    set(float tx, float ty);
-            void    set(float a, float b, float c, float d);
-            void    set(uint32_t flags, float w, float h);
+            void        reset();
+            void        set(float tx, float ty);
+            void        set(float a, float b, float c, float d);
+            status_t    set(uint32_t flags, float w, float h);
 
             // transform data
             Rect    makeBounds(int w, int h) const;
@@ -80,6 +80,9 @@
             Region  transform(const Region& reg) const;
             Transform operator * (const Transform& rhs) const;
 
+            // for debugging
+            void dump(const char* name) const;
+
 private:
     struct vec3 {
         float v[3];
@@ -113,11 +116,8 @@
     Rect transform(const Rect& bounds) const;
     uint32_t type() const;
     static bool absIsOne(float f);
-    static bool absEqual(float a, float b);
     static bool isZero(float f);
 
-    void dump(const char* name) const;
-
     mat33               mMatrix;
     mutable uint32_t    mType;
 };
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index eb3457b..5dd75c3 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -353,6 +353,7 @@
     const_cast<uint32_t&>(android_native_window_t::flags) = 0;
     // be default we request a hardware surface
     mUsage = GRALLOC_USAGE_HW_RENDER;
+    mConnected = 0;
     mNeedFullUpdate = false;
 }
 
@@ -579,28 +580,93 @@
 {
     int res = NO_ERROR;
     switch (operation) {
-        case NATIVE_WINDOW_SET_USAGE:
-            setUsage( va_arg(args, int) );
-            break;
-        default:
-            res = NAME_NOT_FOUND;
-            break;
+    case NATIVE_WINDOW_SET_USAGE:
+        dispatch_setUsage( args );
+        break;
+    case NATIVE_WINDOW_CONNECT:
+        res = dispatch_connect( args );
+        break;
+    case NATIVE_WINDOW_DISCONNECT:
+        res = dispatch_disconnect( args );
+        break;
+    default:
+        res = NAME_NOT_FOUND;
+        break;
     }
     return res;
 }
 
+void Surface::dispatch_setUsage(va_list args) {
+    int usage = va_arg(args, int);
+    setUsage( usage );
+}
+int Surface::dispatch_connect(va_list args) {
+    int api = va_arg(args, int);
+    return connect( api );
+}
+int Surface::dispatch_disconnect(va_list args) {
+    int api = va_arg(args, int);
+    return disconnect( api );
+}
+
+
 void Surface::setUsage(uint32_t reqUsage)
 {
     Mutex::Autolock _l(mSurfaceLock);
     mUsage = reqUsage;
 }
 
+int Surface::connect(int api)
+{
+    Mutex::Autolock _l(mSurfaceLock);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+            if (mConnected) {
+                err = -EINVAL;
+            } else {
+                mConnected = api;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
+int Surface::disconnect(int api)
+{
+    Mutex::Autolock _l(mSurfaceLock);
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+            if (mConnected == api) {
+                mConnected = 0;
+            } else {
+                err = -EINVAL;
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+    return err;
+}
+
 uint32_t Surface::getUsage() const
 {
     Mutex::Autolock _l(mSurfaceLock);
     return mUsage;
 }
 
+int Surface::getConnectedApi() const
+{
+    Mutex::Autolock _l(mSurfaceLock);
+    return mConnected;
+}
+
+
 // ----------------------------------------------------------------------------
 
 status_t Surface::lock(SurfaceInfo* info, bool blocking) {
@@ -609,11 +675,20 @@
 
 status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking) 
 {
+    if (getConnectedApi()) {
+        LOGE("Surface::lock(%p) failed. Already connected to another API",
+                (android_native_window_t*)this);
+        CallStack stack;
+        stack.update();
+        stack.dump("");
+        return INVALID_OPERATION;
+    }
+
     if (mApiLock.tryLock() != NO_ERROR) {
         LOGE("calling Surface::lock from different threads!");
         CallStack stack;
         stack.update();
-        stack.dump("Surface::lock called from different threads");
+        stack.dump("");
         return WOULD_BLOCK;
     }
 
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 1fa2c68..52380a0 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -250,6 +250,8 @@
 {
     switch (operation) {
         case NATIVE_WINDOW_SET_USAGE:
+        case NATIVE_WINDOW_CONNECT:
+        case NATIVE_WINDOW_DISCONNECT:
             break;
         default:
             return NAME_NOT_FOUND;