Fix issue #2095422: Some fades from opaque to transparent don't work

ViewRoot was using Surface.clear(), which has different behavior
in different processes -- in the system process it would kill the
surface, causing all windows in that process to immediately disappear
instead of animating away.

This change makes Surface.release() public and uses that instead.  It
also renames Surface.clear() to Surface.destroy().

Also fixed some issues in the window manager that were causing the
wallpaper to not get immediately resized when the orientation changes
and its target window is removed and re-added.

Change-Id: I2a992e365cf5747511f0bf1193db32dc2525b218
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index b4f4768..c8ff6cb 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -1207,8 +1207,11 @@
                 || mLowerWallpaperTarget != null;
     }
     
-    boolean adjustWallpaperWindowsLocked() {
-        boolean changed = false;
+    static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
+    static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
+    
+    int adjustWallpaperWindowsLocked() {
+        int changed = 0;
         
         final int dw = mDisplay.getWidth();
         final int dh = mDisplay.getHeight();
@@ -1274,12 +1277,12 @@
             if (mWallpaperTarget != null && mWallpaperTarget.mAppToken != null) {
                 if (DEBUG_WALLPAPER) Log.v(TAG,
                         "Wallpaper not changing: waiting for app anim in current target");
-                return false;
+                return 0;
             }
             if (foundW != null && foundW.mAppToken != null) {
                 if (DEBUG_WALLPAPER) Log.v(TAG,
                         "Wallpaper not changing: waiting for app anim in found target");
-                return false;
+                return 0;
             }
         }
         
@@ -1410,7 +1413,13 @@
         while (curTokenIndex > 0) {
             curTokenIndex--;
             WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            token.hidden = !visible;
+            if (token.hidden == visible) {
+                changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED;
+                token.hidden = !visible;
+                // Need to do a layout to ensure the wallpaper now has the
+                // correct size.
+                mLayoutNeeded = true;
+            }
             
             int curWallpaperIndex = token.windows.size();
             while (curWallpaperIndex > 0) {
@@ -1463,7 +1472,7 @@
                         + " from " + oldIndex + " to " + foundI);
                 
                 localmWindows.add(foundI, wallpaper);
-                changed = true;
+                changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
             }
         }
         
@@ -1574,7 +1583,12 @@
         while (curTokenIndex > 0) {
             curTokenIndex--;
             WindowToken token = mWallpaperTokens.get(curTokenIndex);
-            token.hidden = !visible;
+            if (token.hidden == visible) {
+                token.hidden = !visible;
+                // Need to do a layout to ensure the wallpaper now has the
+                // correct size.
+                mLayoutNeeded = true;
+            }
             
             int curWallpaperIndex = token.windows.size();
             while (curWallpaperIndex > 0) {
@@ -1999,10 +2013,15 @@
             synchronized (mWindowMap) {
                 WindowState w = windowForClientLocked(session, client);
                 if ((w != null) && (w.mSurface != null)) {
+                    if (SHOW_TRANSACTIONS) Log.i(TAG, ">>> OPEN TRANSACTION");
                     Surface.openTransaction();
                     try {
+                        if (SHOW_TRANSACTIONS) Log.i(
+                                TAG, "  SURFACE " + w.mSurface
+                                + ": transparentRegionHint=" + region);
                         w.mSurface.setTransparentRegionHint(region);
                     } finally {
+                        if (SHOW_TRANSACTIONS) Log.i(TAG, "<<< CLOSE TRANSACTION");
                         Surface.closeTransaction();
                     }
                 }
@@ -2149,13 +2168,17 @@
                     Surface surface = win.createSurfaceLocked();
                     if (surface != null) {
                         outSurface.copyFrom(surface);
+                        if (SHOW_TRANSACTIONS) Log.i(TAG,
+                                "  OUT SURFACE " + outSurface + ": copied");
                     } else {
-                        outSurface.clear();
+                        // For some reason there isn't a surface.  Clear the
+                        // caller's object so they see the same state.
+                        outSurface.release();
                     }
                 } catch (Exception e) {
                     Log.w(TAG, "Exception thrown when creating surface for client "
-                         + client + " (" + win.mAttrs.getTitle() + ")",
-                         e);
+                             + client + " (" + win.mAttrs.getTitle() + ")",
+                             e);
                     Binder.restoreCallingIdentity(origId);
                     return 0;
                 }
@@ -2196,7 +2219,11 @@
                         }
                     }
                 }
-                outSurface.clear();
+                // We are being called from a local process, which
+                // means outSurface holds its current surface.  Ensure the
+                // surface object is cleared, but we don't want it actually
+                // destroyed at this point.
+                outSurface.release();
             }
 
             if (focusMayChange) {
@@ -2217,7 +2244,7 @@
                 }
             }
             if (wallpaperMayMove) {
-                if (adjustWallpaperWindowsLocked()) {
+                if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
                     assignLayers = true;
                 }
             }
@@ -6281,6 +6308,8 @@
                 if (localLOGV) Log.v(
                     TAG, "First window added to " + this + ", creating SurfaceSession");
                 mSurfaceSession = new SurfaceSession();
+                if (SHOW_TRANSACTIONS) Log.i(
+                        TAG, "  NEW SURFACE SESSION " + mSurfaceSession);
                 mSessions.add(this);
             }
             mNumWindow++;
@@ -6298,6 +6327,8 @@
                     if (localLOGV) Log.v(
                         TAG, "Last window removed from " + this
                         + ", destroying " + mSurfaceSession);
+                    if (SHOW_TRANSACTIONS) Log.i(
+                            TAG, "  KILL SURFACE SESSION " + mSurfaceSession);
                     try {
                         mSurfaceSession.kill();
                     } catch (Exception e) {
@@ -6794,6 +6825,12 @@
                     mSurface = new Surface(
                             mSession.mSurfaceSession, mSession.mPid,
                             0, w, h, mAttrs.format, flags);
+                    if (SHOW_TRANSACTIONS) Log.i(TAG, "  CREATE SURFACE "
+                            + mSurface + " IN SESSION "
+                            + mSession.mSurfaceSession
+                            + ": pid=" + mSession.mPid + " format="
+                            + mAttrs.format + " flags=0x"
+                            + Integer.toHexString(flags));
                 } catch (Surface.OutOfResourcesException e) {
                     Log.w(TAG, "OutOfResourcesException creating surface");
                     reclaimSomeSurfaceMemoryLocked(this, "create");
@@ -6823,6 +6860,8 @@
                         mSurface.setLayer(mAnimLayer);
                         mSurface.hide();
                         if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
+                            if (SHOW_TRANSACTIONS) Log.i(TAG, "  SURFACE "
+                                    + mSurface + ": DITHER");
                             mSurface.setFlags(Surface.SURFACE_DITHER,
                                     Surface.SURFACE_DITHER);
                         }
@@ -6868,7 +6907,7 @@
                         Log.i(TAG, "  SURFACE " + mSurface + ": DESTROY ("
                                 + mAttrs.getTitle() + ")", ex);
                     }
-                    mSurface.clear();
+                    mSurface.destroy();
                 } catch (RuntimeException e) {
                     Log.w(TAG, "Exception thrown when destroying Window " + this
                         + " surface " + mSurface + " session " + mSession
@@ -8840,6 +8879,8 @@
                         if (w.commitFinishDrawingLocked(currentTime)) {
                             if ((w.mAttrs.flags
                                     & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                                if (DEBUG_WALLPAPER) Log.v(TAG,
+                                        "First draw done in potential wallpaper target " + w);
                                 wallpaperMayChange = true;
                             }
                         }
@@ -9134,10 +9175,23 @@
                 }
                 
                 if (wallpaperMayChange) {
-                    if (adjustWallpaperWindowsLocked()) {
+                    if (DEBUG_WALLPAPER) Log.v(TAG,
+                            "Wallpaper may change!  Adjusting");
+                    int adjResult = adjustWallpaperWindowsLocked();
+                    if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                        if (DEBUG_WALLPAPER) Log.v(TAG,
+                                "Wallpaper layer changed: assigning layers + relayout");
+                        restart = true;
+                        mLayoutNeeded = true;
                         assignLayersLocked();
+                    } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
+                        if (DEBUG_WALLPAPER) Log.v(TAG,
+                                "Wallpaper visibility changed: relayout");
+                        restart = true;
+                        mLayoutNeeded = true;
                     }
                     if (mLayoutNeeded) {
+                        restart = true;
                         performLayoutLockedInner();
                     }
                 }
@@ -9184,6 +9238,10 @@
                         w.mLastRequestedHeight = height;
                         w.mLastShownFrame.set(w.mShownFrame);
                         try {
+                            if (SHOW_TRANSACTIONS) Log.i(
+                                    TAG, "  SURFACE " + w.mSurface
+                                    + ": POS " + w.mShownFrame.left
+                                    + ", " + w.mShownFrame.top);
                             w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
                         } catch (RuntimeException e) {
                             Log.w(TAG, "Error positioning surface in " + w, e);
@@ -9196,14 +9254,6 @@
                         width = w.mShownFrame.width();
                         height = w.mShownFrame.height();
                         w.mLastShownFrame.set(w.mShownFrame);
-                        if (resize) {
-                            if (SHOW_TRANSACTIONS) Log.i(
-                                    TAG, "  SURFACE " + w.mSurface + ": ("
-                                    + w.mShownFrame.left + ","
-                                    + w.mShownFrame.top + ") ("
-                                    + w.mShownFrame.width() + "x"
-                                    + w.mShownFrame.height() + ")");
-                        }
                     }
 
                     if (resize) {
@@ -9211,6 +9261,12 @@
                         if (height < 1) height = 1;
                         if (w.mSurface != null) {
                             try {
+                                if (SHOW_TRANSACTIONS) Log.i(
+                                        TAG, "  SURFACE " + w.mSurface + ": POS "
+                                        + w.mShownFrame.left + ","
+                                        + w.mShownFrame.top + " SIZE "
+                                        + w.mShownFrame.width() + "x"
+                                        + w.mShownFrame.height());
                                 w.mSurface.setSize(width, height);
                                 w.mSurface.setPosition(w.mShownFrame.left,
                                         w.mShownFrame.top);
@@ -9239,6 +9295,22 @@
                             w.mLastFrame.set(w.mFrame);
                             w.mLastContentInsets.set(w.mContentInsets);
                             w.mLastVisibleInsets.set(w.mVisibleInsets);
+                            // If the screen is currently frozen, then keep
+                            // it frozen until this window draws at its new
+                            // orientation.
+                            if (mDisplayFrozen) {
+                                if (DEBUG_ORIENTATION) Log.v(TAG,
+                                        "Resizing while display frozen: " + w);
+                                w.mOrientationChanging = true;
+                                if (mWindowsFreezingScreen) {
+                                    mWindowsFreezingScreen = true;
+                                    // XXX should probably keep timeout from
+                                    // when we first froze the display.
+                                    mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
+                                    mH.sendMessageDelayed(mH.obtainMessage(
+                                            H.WINDOW_FREEZE_TIMEOUT), 2000);
+                                }
+                            }
                             // If the orientation is changing, then we need to
                             // hold off on unfreezing the display until this
                             // window has been redrawn; to do that, we need
@@ -9340,7 +9412,11 @@
                         w.mLastVScale = w.mVScale;
                         if (SHOW_TRANSACTIONS) Log.i(
                                 TAG, "  SURFACE " + w.mSurface + ": alpha="
-                                + w.mShownAlpha + " layer=" + w.mAnimLayer);
+                                + w.mShownAlpha + " layer=" + w.mAnimLayer
+                                + " matrix=[" + (w.mDsDx*w.mHScale)
+                                + "," + (w.mDtDx*w.mVScale)
+                                + "][" + (w.mDsDy*w.mHScale)
+                                + "," + (w.mDtDy*w.mVScale) + "]");
                         if (w.mSurface != null) {
                             try {
                                 w.mSurface.setAlpha(w.mShownAlpha);
@@ -9571,6 +9647,8 @@
                 i--;
                 WindowState win = mResizingWindows.get(i);
                 try {
+                    if (DEBUG_ORIENTATION) Log.v(TAG, "Reporting new frame to "
+                            + win + ": " + win.mFrame);
                     win.mClient.resized(win.mFrame.width(),
                             win.mFrame.height(), win.mLastContentInsets,
                             win.mLastVisibleInsets, win.mDrawPending);
@@ -9642,7 +9720,7 @@
             mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
         }
         if (wallpaperDestroyed) {
-            needRelayout = adjustWallpaperWindowsLocked();            
+            needRelayout = adjustWallpaperWindowsLocked() != 0;
         }
         if (needRelayout) {
             requestAnimationLocked(0);
@@ -9720,7 +9798,7 @@
                                 + " token=" + win.mToken
                                 + " pid=" + ws.mSession.mPid
                                 + " uid=" + ws.mSession.mUid);
-                        ws.mSurface.clear();
+                        ws.mSurface.destroy();
                         ws.mSurface = null;
                         mForceRemoves.add(ws);
                         i--;
@@ -9730,7 +9808,7 @@
                         Log.w(TAG, "LEAKED SURFACE (app token hidden): "
                                 + ws + " surface=" + ws.mSurface
                                 + " token=" + win.mAppToken);
-                        ws.mSurface.clear();
+                        ws.mSurface.destroy();
                         ws.mSurface = null;
                         leakedSurface = true;
                     }
@@ -9766,7 +9844,7 @@
                 // surface and ask the app to request another one.
                 Log.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
                 if (surface != null) {
-                    surface.clear();
+                    surface.destroy();
                     win.mSurface = null;
                 }
 
@@ -10025,6 +10103,16 @@
                     w.dump(pw, "    ");
                 }
             }
+            if (mResizingWindows.size() > 0) {
+                pw.println(" ");
+                pw.println("  Windows waiting to resize:");
+                for (int i=mResizingWindows.size()-1; i>=0; i--) {
+                    WindowState w = mResizingWindows.get(i);
+                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
+                            pw.print(w); pw.println(":");
+                    w.dump(pw, "    ");
+                }
+            }
             if (mSessions.size() > 0) {
                 pw.println(" ");
                 pw.println("  All active sessions:");
@@ -10227,7 +10315,8 @@
             mDimSurface.setLayer(w.mAnimLayer-1);
 
             final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
-            if (SHOW_TRANSACTIONS) Log.i(TAG, "layer=" + (w.mAnimLayer-1) + ", target=" + target);
+            if (SHOW_TRANSACTIONS) Log.i(TAG, "  DIM " + mDimSurface
+                    + ": layer=" + (w.mAnimLayer-1) + " target=" + target);
             if (mDimTargetAlpha != target) {
                 // If the desired dim level has changed, then
                 // start an animation to it.