AI 143901: am: CL 143899 am: CL 143896 Fix issue #1748954 and #1737952:
  #1748954 (New status bar fades into all white background): FrameLayout wasn't updating its foreground drawable when its padding changed, which would happen as the status bar is shown and hidden.  To fix this I also ended up fixing a problem in the view debug stuff where we couldn't get a bitmap for a view that is the full screen size because it is too big...  actually I just went ahead and added another function to snapshot the view hierarchy which works a lot better for us anyway.
  #1737952 (Home screen icons overlap with the notification bar after exiting any camera app): Originally I punted this because it only happened in rare situations, but now that home is always portrait it happens a lot more so it is more important to fix.  This involved a few things to clean up hiding/showing the status bar:
  - We now determine when to hide and show it during layout, which allows us to do this at the time it is actually needed rather than during animation after we can actually catch it for the initial display of a window.  This required tweaking the layout API so the policy can request a second layout pass if needed.
  - When doing layout, we are now much more aggressive about skipping the layout of windows.  Basically anything that we know will be hidden in the near future is ignored for layout, so that it doesn't glitch as it is transfered out of the screen.  The theory being that it is better to leave it as it was originally placed while we are transitioning it out, than to switch it to something slightly more correct.
  Original author: hackbod
  Merged from: //branches/cupcake/...
  Original author: android-build
  Merged from: //branches/donutburger/...

Automated import of CL 143901
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9f4143c..8a65219 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5535,7 +5535,7 @@
                 (mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE);
 
             if (width <= 0 || height <= 0 ||
-                    (width * height * (opaque ? 2 : 4) >= // Projected bitmap size in bytes
+                    (width * height * (opaque ? 2 : 4) > // Projected bitmap size in bytes
                             ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
                 destroyDrawingCache();
                 return;
@@ -5632,6 +5632,62 @@
     }
 
     /**
+     * Create a snapshot of the view into a bitmap.  We should probably make
+     * some form of this public, but should think about the API.
+     */
+    /*package*/ Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor) {
+        final int width = mRight - mLeft;
+        final int height = mBottom - mTop;
+
+        Bitmap bitmap = Bitmap.createBitmap(width, height, quality);
+        if (bitmap == null) {
+            throw new OutOfMemoryError();
+        }
+
+        Canvas canvas;
+        final AttachInfo attachInfo = mAttachInfo;
+        if (attachInfo != null) {
+            canvas = attachInfo.mCanvas;
+            if (canvas == null) {
+                canvas = new Canvas();
+            }
+            canvas.setBitmap(bitmap);
+            // Temporarily clobber the cached Canvas in case one of our children
+            // is also using a drawing cache. Without this, the children would
+            // steal the canvas by attaching their own bitmap to it and bad, bad
+            // things would happen (invisible views, corrupted drawings, etc.)
+            attachInfo.mCanvas = null;
+        } else {
+            // This case should hopefully never or seldom happen
+            canvas = new Canvas(bitmap);
+        }
+
+        if ((backgroundColor&0xff000000) != 0) {
+            bitmap.eraseColor(backgroundColor);
+        }
+
+        computeScroll();
+        final int restoreCount = canvas.save();
+        canvas.translate(-mScrollX, -mScrollY);
+
+        // Fast path for layouts with no backgrounds
+        if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+            dispatchDraw(canvas);
+        } else {
+            draw(canvas);
+        }
+
+        canvas.restoreToCount(restoreCount);
+
+        if (attachInfo != null) {
+            // Restore the cached Canvas for our siblings
+            attachInfo.mCanvas = canvas;
+        }
+        
+        return bitmap;
+    }
+
+    /**
      * Indicates whether this View is currently in edit mode. A View is usually
      * in edit mode when displayed within a developer tool. For instance, if
      * this View is being drawn by a visual user interface builder, this method
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index f604bc5..c1e9ed8 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -741,22 +741,18 @@
             final CountDownLatch latch = new CountDownLatch(1);
             final Bitmap[] cache = new Bitmap[1];
 
-            final boolean hasCache = captureView.isDrawingCacheEnabled();
-            final boolean willNotCache = captureView.willNotCacheDrawing();
-
-            if (willNotCache) {
-                // TODO: Should happen on the UI thread
-                captureView.setWillNotCacheDrawing(false);
-            }
-
             root.post(new Runnable() {
                 public void run() {
                     try {
-                        if (!hasCache) {
-                            captureView.buildDrawingCache();
+                        cache[0] = captureView.createSnapshot(
+                                Bitmap.Config.ARGB_8888, 0);
+                    } catch (OutOfMemoryError e) {
+                        try {
+                            cache[0] = captureView.createSnapshot(
+                                    Bitmap.Config.ARGB_4444, 0);
+                        } catch (OutOfMemoryError e2) {
+                            Log.w("View", "Out of memory for bitmap");
                         }
-
-                        cache[0] = captureView.getDrawingCache();
                     } finally {
                         latch.countDown();
                     }
@@ -776,20 +772,15 @@
                         if (out != null) {
                             out.close();
                         }
+                        cache[0].recycle();
                     }
+                } else {
+                    Log.w("View", "Failed to create capture bitmap!");
+                    clientStream.close();
                 }
             } catch (InterruptedException e) {
                 Log.w("View", "Could not complete the capture of the view " + captureView);
                 Thread.currentThread().interrupt();
-            } finally {
-                if (willNotCache) {
-                    // TODO: Should happen on the UI thread
-                    captureView.setWillNotCacheDrawing(true);
-                }
-                if (!hasCache) {
-                    // TODO: Should happen on the UI thread                    
-                    captureView.destroyDrawingCache();
-                }
             }
         }
     }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 220869c..1371932 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -580,8 +580,11 @@
      * Called when layout of the windows is finished.  After this function has
      * returned, all windows given to layoutWindow() <em>must</em> have had a
      * frame assigned.
+     *  
+     * @return Return true if layout state may have changed (so that another 
+     *         layout will be performed).
      */
-    public void finishLayoutLw();
+    public boolean finishLayoutLw();
 
     /**
      * Called when animation of the windows is about to start.
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 47db6f2..80fbf9e 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.Gravity;
 import android.widget.RemoteViews.RemoteView;
@@ -45,21 +46,31 @@
  */
 @RemoteView
 public class FrameLayout extends ViewGroup {
+    @ViewDebug.ExportedProperty
     boolean mMeasureAllChildren = false;
 
+    @ViewDebug.ExportedProperty
     private Drawable mForeground;
+    @ViewDebug.ExportedProperty
     private int mForegroundPaddingLeft = 0;
+    @ViewDebug.ExportedProperty
     private int mForegroundPaddingTop = 0;
+    @ViewDebug.ExportedProperty
     private int mForegroundPaddingRight = 0;
+    @ViewDebug.ExportedProperty
     private int mForegroundPaddingBottom = 0;
 
     private final Rect mSelfBounds = new Rect();
     private final Rect mOverlayBounds = new Rect();
+    @ViewDebug.ExportedProperty
     private int mForegroundGravity = Gravity.FILL;
 
     /** {@hide} */
+    @ViewDebug.ExportedProperty
     protected boolean mForegroundInPadding = true;
 
+    boolean mForegroundBoundsChanged = false;
+    
     public FrameLayout(Context context) {
         super(context);
     }
@@ -269,6 +280,8 @@
         final int parentTop = mPaddingTop + mForegroundPaddingTop;
         final int parentBottom = bottom - top - mPaddingBottom - mForegroundPaddingBottom;
 
+        mForegroundBoundsChanged = true;
+        
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
             if (child.getVisibility() != GONE) {
@@ -328,22 +341,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-
-        final Drawable foreground = mForeground;
-        if (foreground != null) {
-            final Rect selfBounds = mSelfBounds;
-            final Rect overlayBounds = mOverlayBounds;
-
-            if (mForegroundInPadding) {
-                selfBounds.set(0, 0, w, h);
-            } else {
-                selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
-            }
-
-            Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
-                    foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
-            foreground.setBounds(overlayBounds);
-        }
+        mForegroundBoundsChanged = true;
     }
 
     /**
@@ -354,7 +352,29 @@
         super.draw(canvas);
 
         if (mForeground != null) {
-            mForeground.draw(canvas);
+            final Drawable foreground = mForeground;
+            if (mForegroundBoundsChanged) {
+                mForegroundBoundsChanged = false;
+                if (foreground != null) {
+                    final Rect selfBounds = mSelfBounds;
+                    final Rect overlayBounds = mOverlayBounds;
+
+                    final int w = mRight-mLeft;
+                    final int h = mBottom-mTop;
+                    
+                    if (mForegroundInPadding) {
+                        selfBounds.set(0, 0, w, h);
+                    } else {
+                        selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom);
+                    }
+
+                    Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
+                            foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
+                    foreground.setBounds(overlayBounds);
+                }
+            }
+            
+            foreground.draw(canvas);
         }
     }
 
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 270d15f..0b1ddc8 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7485,11 +7485,12 @@
         final int dh = mDisplay.getHeight();
 
         final int N = mWindows.size();
+        int repeats = 0;
         int i;
 
         // FIRST LOOP: Perform a layout, if needed.
         
-        if (mLayoutNeeded) {
+        while (mLayoutNeeded) {
             mPolicy.beginLayoutLw(dw, dh);
 
             // First perform layout of any root windows (not attached
@@ -7497,10 +7498,18 @@
             int topAttached = -1;
             for (i = N-1; i >= 0; i--) {
                 WindowState win = (WindowState) mWindows.get(i);
-    
-                boolean gone = win.mViewVisibility == View.GONE
+
+                // Don't do layout of a window if it is not visible, or
+                // soon won't be visible, to avoid wasting time and funky
+                // changes while a window is animating away.
+                final AppWindowToken atoken = win.mAppToken;
+                final boolean gone = win.mViewVisibility == View.GONE
                         || !win.mRelayoutCalled
-                        || win.mRootToken.hidden;
+                        || win.mRootToken.hidden
+                        || (atoken != null && atoken.hiddenRequested)
+                        || !win.mPolicyVisibility
+                        || win.mAttachedHidden
+                        || win.mExiting || win.mDestroying;
 
                 // If this view is GONE, then skip it -- keep the current
                 // frame, and let the caller know so they can ignore it
@@ -7536,8 +7545,14 @@
                 }
             }
 
-            mPolicy.finishLayoutLw();
-            mLayoutNeeded = false;
+            if (!mPolicy.finishLayoutLw()) {
+                mLayoutNeeded = false;
+            } else if (repeats > 2) {
+                Log.w(TAG, "Layout repeat aborted after too many iterations");
+                mLayoutNeeded = false;
+            } else {
+                repeats++;
+            }
         }
     }