From ef25d7a01910d5547b60c9cc52d4fa4a9e40b6fa Mon Sep 17 00:00:00 2001 From: Craig Mautner Date: Tue, 15 May 2012 23:01:47 -0700 Subject: [PATCH] Change method of tracking moving AppWindowTokens. Stop trying to keep track of the AppTokens that have been moved to the top and bottom and then try and match the WindowStates when transitions are goodToGo. Instead rebuild the WindowState order based on the AppToken order when we are goodToGo. When moving AppWindowTokens lower in mAppTokens create a new ArrayList of AppWindowTokens to keep track of the apps in Z order while animating. Fixes bug 6481078. Change-Id: I29b33a507b45752f15feb10a9f4b47a3f5eb9f0e --- .../com/android/server/wm/WindowAnimator.java | 10 +- .../server/wm/WindowManagerService.java | 217 +++++++++++------- .../com/android/server/wm/WindowState.java | 4 +- .../server/wm/WindowStateAnimator.java | 13 +- .../com/android/server/wm/WindowToken.java | 7 +- 5 files changed, 146 insertions(+), 105 deletions(-) diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index 480992beaa150..d85aac00caafe 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -134,10 +134,11 @@ public class WindowAnimator { } private void updateWindowsAppsAndRotationAnimationsLocked() { + final ArrayList appTokens = mService.mAnimatingAppTokens; int i; - final int NAT = mService.mAppTokens.size(); + final int NAT = appTokens.size(); for (i=0; i appTokens = mService.mAnimatingAppTokens; + final int NT = appTokens.size(); for (int i=0; i 0 && wtoken.numDrawnWindows >= numInteresting) { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index b3ac6f1a8cf61..e298a81c7ee38 100755 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -351,12 +351,19 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList mExitingTokens = new ArrayList(); /** - * Z-ordered (bottom-most first) list of all application tokens, for - * controlling the ordering of windows in different applications. This - * contains AppWindowToken objects. + * List controlling the ordering of windows in different applications which must + * be kept in sync with ActivityManager. */ final ArrayList mAppTokens = new ArrayList(); + /** + * AppWindowTokens in the Z order they were in at the start of an animation. Between + * animations this list is maintained in the exact order of mAppTokens. If tokens + * are added to mAppTokens during an animation an attempt is made to insert them at the same + * logical location in this list. Note that this list is always in sync with mWindows. + */ + ArrayList mAnimatingAppTokens = new ArrayList(); + /** * Application tokens that are in the process of exiting, but still * on screen for animations. @@ -529,8 +536,6 @@ public class WindowManagerService extends IWindowManager.Stub boolean mSkipAppTransitionAnimation = false; final ArrayList mOpeningApps = new ArrayList(); final ArrayList mClosingApps = new ArrayList(); - final ArrayList mToTopApps = new ArrayList(); - final ArrayList mToBottomApps = new ArrayList(); Display mDisplay; @@ -1008,10 +1013,10 @@ public class WindowManagerService extends IWindowManager.Stub + client.asBinder() + " (token=" + token + ")"); // Figure out where the window should go, based on the // order of applications. - final int NA = mAppTokens.size(); + final int NA = mAnimatingAppTokens.size(); WindowState pos = null; for (i=NA-1; i>=0; i--) { - AppWindowToken t = mAppTokens.get(i); + AppWindowToken t = mAnimatingAppTokens.get(i); if (t == token) { i--; break; @@ -1044,7 +1049,7 @@ public class WindowManagerService extends IWindowManager.Stub // Continue looking down until we find the first // token that has windows. while (i >= 0) { - AppWindowToken t = mAppTokens.get(i); + AppWindowToken t = mAnimatingAppTokens.get(i); final int NW = t.windows.size(); if (NW > 0) { pos = t.windows.get(NW-1); @@ -1165,6 +1170,7 @@ public class WindowManagerService extends IWindowManager.Stub } } + /** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */ static boolean canBeImeTarget(WindowState w) { final int fl = w.mAttrs.flags & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); @@ -1869,7 +1875,7 @@ public class WindowManagerService extends IWindowManager.Stub } wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment; - if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win " + if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "adjustWallpaper win " + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); // First, if this window is at the current index, then all @@ -1923,7 +1929,7 @@ public class WindowManagerService extends IWindowManager.Stub curWallpaperIndex--; WindowState wallpaper = token.windows.get(curWallpaperIndex); wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj; - if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win " + if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win " + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); } } @@ -3498,6 +3504,25 @@ public class WindowManagerService extends IWindowManager.Stub Binder.restoreCallingIdentity(origId); } + /** + * Find the location to insert a new AppWindowToken into the window-ordered app token list. + * Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1. + * @param addPos The location the token was inserted into in mAppTokens. + * @param wtoken The token to insert. + */ + private void addAppTokenToAnimating(final int addPos, final AppWindowToken wtoken) { + if (addPos == 0 || addPos == mAnimatingAppTokens.size()) { + // It was inserted into the beginning or end of mAppTokens. Honor that. + mAnimatingAppTokens.add(addPos, wtoken); + return; + } + // Find the item immediately above the mAppTokens insertion point and put the token + // immediately below that one in mAnimatingAppTokens. + final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1); + mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken); + } + + @Override public void addAppToken(int addPos, IApplicationToken token, int groupId, int requestedOrientation, boolean fullscreen) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, @@ -3532,6 +3557,7 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.requestedOrientation = requestedOrientation; if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + wtoken); mAppTokens.add(addPos, wtoken); + addAppTokenToAnimating(addPos, wtoken); mTokenMap.put(token.asBinder(), wtoken); // Application tokens start out hidden. @@ -3849,7 +3875,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Prepare app transition: transit=" + transit + " mNextAppTransition=" + mNextAppTransition - + "\nCallers=" + Debug.getCallers(3)); + + " Callers=" + Debug.getCallers(3)); if (okToDisplay()) { if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { @@ -4481,6 +4507,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: " + wtoken); mAppTokens.remove(wtoken); + mAnimatingAppTokens.remove(wtoken); wtoken.removed = true; if (wtoken.startingData != null) { startingToken = wtoken; @@ -4512,11 +4539,13 @@ public class WindowManagerService extends IWindowManager.Stub private boolean tmpRemoveAppWindowsLocked(WindowToken token) { final int NW = token.windows.size(); + if (NW > 0) { + mWindowsChanged = true; + } for (int i=0; i 0) { j--; @@ -4535,6 +4564,12 @@ public class WindowManagerService extends IWindowManager.Stub } } + void dumpAnimatingAppTokensLocked() { + for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) { + Slog.v(TAG, " #" + i + ": " + mAnimatingAppTokens.get(i).token); + } + } + void dumpWindowsLocked() { for (int i=mWindows.size()-1; i>=0; i--) { Slog.v(TAG, " #" + i + ": " + mWindows.get(i)); @@ -4544,7 +4579,7 @@ public class WindowManagerService extends IWindowManager.Stub private int findWindowOffsetLocked(int tokenPos) { final int NW = mWindows.size(); - if (tokenPos >= mAppTokens.size()) { + if (tokenPos >= mAnimatingAppTokens.size()) { int i = NW; while (i > 0) { i--; @@ -4558,7 +4593,7 @@ public class WindowManagerService extends IWindowManager.Stub while (tokenPos > 0) { // Find the first app token below the new position that has // a window displayed. - final AppWindowToken wtoken = mAppTokens.get(tokenPos-1); + final AppWindowToken wtoken = mAnimatingAppTokens.get(tokenPos-1); if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ " + tokenPos + " -- " + wtoken.token); if (wtoken.sendingToBottom) { @@ -4646,9 +4681,16 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:"); if (DEBUG_REORDER) dumpAppTokensLocked(); final AppWindowToken wtoken = findAppWindowToken(token); + final int oldIndex = mAppTokens.indexOf(wtoken); if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG, "Start moving token " + wtoken + " initially at " - + mAppTokens.indexOf(wtoken)); + + oldIndex); + if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET + && !mAppTransitionRunning) { + // animation towards back has not started, copy old list for duration of animation. + mAnimatingAppTokens.clear(); + mAnimatingAppTokens.addAll(mAppTokens); + } if (wtoken == null || !mAppTokens.remove(wtoken)) { Slog.w(TAG, "Attempting to reorder token that doesn't exist: " + token + " (" + wtoken + ")"); @@ -4658,24 +4700,30 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":"); else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index); if (DEBUG_REORDER) dumpAppTokensLocked(); + if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) { + // Not animating, bring animating app list in line with mAppTokens. + mAnimatingAppTokens.clear(); + mAnimatingAppTokens.addAll(mAppTokens); - final long origId = Binder.clearCallingIdentity(); - if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":"); - if (DEBUG_REORDER) dumpWindowsLocked(); - if (tmpRemoveAppWindowsLocked(wtoken)) { - if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:"); + // Bring window ordering, window focus and input window in line with new app token + final long origId = Binder.clearCallingIdentity(); + if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":"); if (DEBUG_REORDER) dumpWindowsLocked(); - reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken); - if (DEBUG_REORDER) Slog.v(TAG, "Final window list:"); - if (DEBUG_REORDER) dumpWindowsLocked(); - updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, - false /*updateInputWindows*/); - mLayoutNeeded = true; - mInputMonitor.setUpdateInputWindowsNeededLw(); - performLayoutAndPlaceSurfacesLocked(); - mInputMonitor.updateInputWindowsLw(false /*force*/); + if (tmpRemoveAppWindowsLocked(wtoken)) { + if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:"); + if (DEBUG_REORDER) dumpWindowsLocked(); + reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken); + if (DEBUG_REORDER) Slog.v(TAG, "Final window list:"); + if (DEBUG_REORDER) dumpWindowsLocked(); + updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, + false /*updateInputWindows*/); + mLayoutNeeded = true; + mInputMonitor.setUpdateInputWindowsNeededLw(); + performLayoutAndPlaceSurfacesLocked(); + mInputMonitor.updateInputWindowsLw(false /*force*/); + } + Binder.restoreCallingIdentity(origId); } - Binder.restoreCallingIdentity(origId); } } @@ -4716,7 +4764,9 @@ public class WindowManagerService extends IWindowManager.Stub assignLayersLocked(); } mLayoutNeeded = true; - performLayoutAndPlaceSurfacesLocked(); + if (!mInLayout) { + performLayoutAndPlaceSurfacesLocked(); + } mInputMonitor.updateInputWindowsLw(false /*force*/); } } @@ -4772,22 +4822,22 @@ public class WindowManagerService extends IWindowManager.Stub "Adding next to top: " + wt); mAppTokens.add(wt); if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { - mToTopApps.remove(wt); - mToBottomApps.remove(wt); - mToTopApps.add(wt); wt.sendingToBottom = false; - wt.sendingToTop = true; } } } - if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) { + if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET + && !mAppTransitionRunning) { + mAnimatingAppTokens.clear(); + mAnimatingAppTokens.addAll(mAppTokens); moveAppWindowsLocked(tokens, mAppTokens.size()); } } Binder.restoreCallingIdentity(origId); } + @Override public void moveAppTokensToBottom(List tokens) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "moveAppTokensToBottom()")) { @@ -4796,8 +4846,14 @@ public class WindowManagerService extends IWindowManager.Stub final long origId = Binder.clearCallingIdentity(); synchronized(mWindowMap) { - removeAppTokensLocked(tokens); final int N = tokens.size(); + if (N > 0 && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET + && !mAppTransitionRunning) { + // animating towards back, hang onto old list for duration of animation. + mAnimatingAppTokens.clear(); + mAnimatingAppTokens.addAll(mAppTokens); + } + removeAppTokensLocked(tokens); int pos = 0; for (int i=0; i 0) { for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) { try { @@ -9006,7 +9036,7 @@ public class WindowManagerService extends IWindowManager.Stub AppWindowToken thisApp = win.mAppToken; // If this window's application has been removed, just skip it. - if (thisApp != null && thisApp.removed) { + if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) { continue; } @@ -9409,6 +9439,21 @@ public class WindowManagerService extends IWindowManager.Stub } } } + if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) { + pw.println(); + pw.println(" Application tokens during animation:"); + for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) { + WindowToken token = mAnimatingAppTokens.get(i); + pw.print(" App moving to bottom #"); pw.print(i); + pw.print(' '); pw.print(token); + if (dumpAll) { + pw.println(':'); + token.dump(pw, " "); + } else { + pw.println(); + } + } + } pw.println(); if (mOpeningApps.size() > 0) { pw.print(" mOpeningApps="); pw.println(mOpeningApps); @@ -9416,12 +9461,6 @@ public class WindowManagerService extends IWindowManager.Stub if (mClosingApps.size() > 0) { pw.print(" mClosingApps="); pw.println(mClosingApps); } - if (mToTopApps.size() > 0) { - pw.print(" mToTopApps="); pw.println(mToTopApps); - } - if (mToBottomApps.size() > 0) { - pw.print(" mToBottomApps="); pw.println(mToBottomApps); - } } void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) { diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 1fd80c26c8dc7..615221f0c7e48 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -842,7 +842,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } - /** Returns true if this window desires key events. */ + /** Returns true if this window desires key events. + * TODO(cmautner): Is this the same as {@link WindowManagerService#canBeImeTarget} + */ public final boolean canReceiveKeys() { return isVisibleOrAdding() && (mViewVisibility == View.VISIBLE) diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index 5516dea82067c..1804ec0ee38e9 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -405,8 +405,8 @@ class WindowStateAnimator { boolean finishDrawingLocked() { if (mDrawState == DRAW_PENDING) { - if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v( - TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in " + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) + Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in " + mSurface); mDrawState = COMMIT_DRAW_PENDING; return true; @@ -419,7 +419,7 @@ class WindowStateAnimator { if (mDrawState != COMMIT_DRAW_PENDING) { return false; } - if (DEBUG_ANIM) + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurface); mDrawState = READY_TO_SHOW; final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING; @@ -506,7 +506,9 @@ class WindowStateAnimator { @Override public void setWindowCrop(Rect crop) { super.setWindowCrop(crop); - mWindowCrop.set(crop); + if (crop != null) { + mWindowCrop.set(crop); + } Slog.v(SURFACE_TAG, "setWindowCrop: " + this + ". Called by " + Debug.getCallers(3)); } @@ -1247,7 +1249,8 @@ class WindowStateAnimator { // Force the show in the next prepareSurfaceLocked() call. mLastAlpha = -1; - if (DEBUG_ANIM) Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN"); + if (DEBUG_SURFACE_TRACE || DEBUG_ANIM) + Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN in " + this); mDrawState = HAS_DRAWN; mService.scheduleAnimationLocked(); diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java index 3cd256e85054e..5ec151b8e805b 100644 --- a/services/java/com/android/server/wm/WindowToken.java +++ b/services/java/com/android/server/wm/WindowToken.java @@ -71,10 +71,6 @@ class WindowToken { // windows will be put to the bottom of the list. boolean sendingToBottom; - // Set to true when this token is in a pending transaction where its - // windows will be put to the top of the list. - boolean sendingToTop; - WindowToken(WindowManagerService _service, IBinder _token, int type, boolean _explicit) { service = _service; token = _token; @@ -88,11 +84,10 @@ class WindowToken { pw.print(prefix); pw.print("windowType="); pw.print(windowType); pw.print(" hidden="); pw.print(hidden); pw.print(" hasVisible="); pw.println(hasVisible); - if (waitingToShow || waitingToHide || sendingToBottom || sendingToTop) { + if (waitingToShow || waitingToHide || sendingToBottom) { pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); pw.print(" waitingToHide="); pw.print(waitingToHide); pw.print(" sendingToBottom="); pw.print(sendingToBottom); - pw.print(" sendingToTop="); pw.println(sendingToTop); } }