Merge "Skip layout if performShow fails."
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index c29ef3f..1442883 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -336,6 +336,10 @@
         }
 
         service.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+            service.debugLayoutRepeats("AppWindowToken");
+        }
+
         clearAnimation();
         animating = false;
         if (animLayerAdjustment != 0) {
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 7aa6716..fbfd9ec 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -67,24 +67,32 @@
         final int NAT = mService.mAppTokens.size();
         for (i=0; i<NAT; i++) {
             final AppWindowToken appToken = mService.mAppTokens.get(i);
-            final boolean wasAnimating = appToken.animation != null;
+            final boolean wasAnimating = appToken.animation != null
+                    && appToken.animation != WindowManagerService.sDummyAnimation;
             if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
                 mAnimating = true;
             } else if (wasAnimating) {
                 // stopped animating, do one more pass through the layout
                 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                    mService.debugLayoutRepeats("appToken " + appToken + " done");
+                }
             }
         }
         
         final int NEAT = mService.mExitingAppTokens.size();
         for (i=0; i<NEAT; i++) {
             final AppWindowToken appToken = mService.mExitingAppTokens.get(i);
-            final boolean wasAnimating = appToken.animation != null;
+            final boolean wasAnimating = appToken.animation != null
+                    && appToken.animation != WindowManagerService.sDummyAnimation;
             if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
                 mAnimating = true;
             } else if (wasAnimating) {
                 // stopped animating, do one more pass through the layout
                 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                    mService.debugLayoutRepeats("exiting appToken " + appToken + " done");
+                }
             }
         }
 
@@ -119,6 +127,9 @@
                                 "First draw done in potential wallpaper target " + w);
                         mService.mInnerFields.mWallpaperMayChange = true;
                         mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 1");
+                        }
                     }
                 }
 
@@ -192,6 +203,9 @@
                 if (wasAnimating && !w.mAnimating && mService.mWallpaperTarget == w) {
                     mService.mInnerFields.mWallpaperMayChange = true;
                     mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                        mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2");
+                    }
                 }
 
                 if (mPolicy.doesForceHide(w, attrs)) {
@@ -201,6 +215,9 @@
                                 + w);
                         mService.mInnerFields.mWallpaperForceHidingChanged = true;
                         mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3");
+                        }
                         mService.mFocusMayChange = true;
                     } else if (w.isReadyForDisplay() && w.mAnimation == null) {
                         mForceHiding = true;
@@ -239,6 +256,9 @@
                             & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
                         mService.mInnerFields.mWallpaperMayChange = true;
                         mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4");
+                        }
                     }
                 }
             }
@@ -286,8 +306,12 @@
                     }
                 }
             } else if (w.mReadyToShow) {
-                w.performShowLocked();
-                mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+                if (w.performShowLocked()) {
+                    mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+                    if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                        mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5");
+                    }
+                }
             }
             if (atoken != null && atoken.thumbnail != null) {
                 if (atoken.thumbnailTransactionSeq != mTransactionSequence) {
@@ -331,6 +355,9 @@
                             + " drawn=" + wtoken.numDrawnWindows);
                     wtoken.allDrawn = true;
                     mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+                    if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+                        mService.debugLayoutRepeats("testTokenMayBeDrawnLocked");
+                    }
 
                     // We can now show all of the drawn windows!
                     if (!mService.mOpeningApps.contains(wtoken)) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index a978b35..3ecbf77 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -170,10 +170,12 @@
     static final boolean DEBUG_SCREEN_ON = false;
     static final boolean DEBUG_SCREENSHOT = false;
     static final boolean DEBUG_BOOT = false;
+    static final boolean DEBUG_LAYOUT_REPEATS = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
     static final boolean HIDE_STACK_CRAWLS = true;
+    static final int LAYOUT_REPEAT_THRESHOLD = 4;
 
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean localLOGV = DEBUG;
@@ -3326,6 +3328,7 @@
         return wtoken.appWindowToken;
     }
 
+    @Override
     public void addWindowToken(IBinder token, int type) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addWindowToken()")) {
@@ -8378,6 +8381,8 @@
                     break;
                 }
 
+                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner");
+
                 if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
                     if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
                         assignLayersLocked();
@@ -8407,6 +8412,7 @@
                 // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
                 // it is animating.
                 mPendingLayoutChanges = 0;
+                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount);
                 mPolicy.beginAnimationLw(dw, dh);
                 for (i = mWindows.size() - 1; i >= 0; i--) {
                     WindowState w = mWindows.get(i);
@@ -8415,7 +8421,7 @@
                     }
                 }
                 mPendingLayoutChanges |= mPolicy.finishAnimationLw();
-                
+                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw");
             } while (mPendingLayoutChanges != 0);
 
             final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
@@ -8460,6 +8466,7 @@
         // to go.
         if (mAppTransitionReady) {
             mPendingLayoutChanges |= handleAppTransitionReadyLocked();
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked");
         }
 
         mInnerFields.mAdjResult = 0;
@@ -8472,6 +8479,7 @@
             // be out of sync with it.  So here we will just rebuild the
             // entire app window list.  Fun!
             mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock");
         }
 
         if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
@@ -8483,12 +8491,15 @@
             // hard -- the wallpaper now needs to be shown behind
             // something that was hidden.
             mPendingLayoutChanges |= animateAwayWallpaperLocked();
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked");
         }
 
         mPendingLayoutChanges |= testWallpaperAndBackgroundLocked();
+        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after testWallpaperAndBackgroundLocked");
 
         if (mLayoutNeeded) {
             mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded");
         }
 
         final int N = mWindows.size();
@@ -8502,6 +8513,7 @@
         // associated with exiting/removed apps
         mAnimator.animate();
         mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges;
+        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animate()");
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
@@ -9757,4 +9769,11 @@
     public interface OnHardKeyboardStatusChangeListener {
         public void onHardKeyboardStatusChange(boolean available, boolean enabled);
     }
+    
+    void debugLayoutRepeats(final String msg) {
+        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
+            Slog.v(TAG, "Layouts looping: " + msg);
+            Slog.v(TAG, "mPendingLayoutChanges = 0x" + Integer.toHexString(mPendingLayoutChanges));
+        }
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index cf61f7f..1146189 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -989,6 +989,8 @@
                 }
                 mAppToken.updateReportedVisibilityLocked();
             }
+        } else {
+            return false;
         }
         return true;
     }
@@ -1128,6 +1130,7 @@
 
         finishExit();
         mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState");
 
         if (mAppToken != null) {
             mAppToken.updateReportedVisibilityLocked();