Removed child windows from WindowToken window list

With the window container hierarchy model, containers should only
link to their direct children and delegate any operation on
decendants of their children to their children.

Bug: 30060889
Change-Id: I99ca0d181d54cfe75bbe24c1b0daaa06cf7cfd9a
This commit is contained in:
Wale Ogunwale
2016-08-10 14:44:22 -07:00
parent b3847d8e92
commit 9bc4773636
10 changed files with 854 additions and 493 deletions

View File

@@ -2464,7 +2464,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// entrance of the new window to be properly animated.
// Note here we always set the replacing window first, as the flags might be needed
// during the relaunch. If we end up not doing any relaunch, we clear the flags later.
mWindowManager.setReplacingWindow(topActivity.appToken, animate);
mWindowManager.setWillReplaceWindow(topActivity.appToken, animate);
}
mWindowManager.deferSurfaceLayout();
@@ -2506,7 +2506,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
// window), we need to clear the replace window settings. Otherwise, we schedule a
// timeout to remove the old window if the replacing window is not coming in time.
mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
mWindowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
}
if (!deferResume) {

View File

@@ -20,15 +20,11 @@ import static android.app.ActivityManager.StackId;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -37,7 +33,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
import static com.android.server.wm.WindowManagerService.logWithStack;
import com.android.server.input.InputApplicationHandle;
@@ -50,7 +45,6 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Slog;
import android.view.IApplicationToken;
@@ -132,6 +126,8 @@ class AppWindowToken extends WindowToken {
boolean startingDisplayed;
boolean startingMoved;
boolean firstWindowDrawn;
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
// Input application handle used by the input dispatcher.
final InputApplicationHandle mInputApplicationHandle;
@@ -162,19 +158,10 @@ class AppWindowToken extends WindowToken {
}
void sendAppVisibilityToClients() {
final int N = windows.size();
for (int i=0; i<N; i++) {
WindowState win = windows.get(i);
if (win == startingWindow && clientHidden) {
// Don't hide the starting window.
continue;
}
try {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Setting visibility of " + win + ": " + (!clientHidden));
win.mClient.dispatchAppVisibility(!clientHidden);
} catch (RemoteException e) {
}
final int count = windows.size();
for (int i = 0; i < count; i++) {
final WindowState win = windows.get(i);
win.sendAppVisibilityToClients(clientHidden);
}
}
@@ -189,7 +176,7 @@ class AppWindowToken extends WindowToken {
firstWindowDrawn = true;
// We now have a good window to show, remove dead placeholders
removeAllDeadWindows();
removeDeadWindows();
if (startingData != null) {
if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
@@ -209,50 +196,21 @@ class AppWindowToken extends WindowToken {
return;
}
int numInteresting = 0;
int numVisible = 0;
int numDrawn = 0;
boolean nowGone = true;
if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
final int count = windows.size();
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Update reported visibility: " + this);
final int N = windows.size();
for (int i=0; i<N; i++) {
WindowState win = windows.get(i);
if (win == startingWindow || win.mAppFreezing
|| win.mViewVisibility != View.VISIBLE
|| win.mAttrs.type == TYPE_APPLICATION_STARTING
|| win.mDestroying) {
continue;
}
if (DEBUG_VISIBILITY) {
Slog.v(TAG, "Win " + win + ": isDrawn="
+ win.isDrawnLw()
+ ", isAnimationSet=" + win.mWinAnimator.isAnimationSet());
if (!win.isDrawnLw()) {
Slog.v(TAG, "Not displayed: s=" +
win.mWinAnimator.mSurfaceController
+ " pv=" + win.mPolicyVisibility
+ " mDrawState=" + win.mWinAnimator.mDrawState
+ " ph=" + win.isParentWindowHidden()
+ " th="
+ (win.mAppToken != null
? win.mAppToken.hiddenRequested : false)
+ " a=" + win.mWinAnimator.mAnimating);
}
}
numInteresting++;
if (win.isDrawnLw()) {
numDrawn++;
if (!win.mWinAnimator.isAnimationSet()) {
numVisible++;
}
nowGone = false;
} else if (win.mWinAnimator.isAnimationSet()) {
nowGone = false;
}
mReportedVisibilityResults.reset();
for (int i = 0; i < count; i++) {
final WindowState win = windows.get(i);
win.updateReportedVisibility(mReportedVisibilityResults);
}
int numInteresting = mReportedVisibilityResults.numInteresting;
int numVisible = mReportedVisibilityResults.numVisible;
int numDrawn = mReportedVisibilityResults.numDrawn;
boolean nowGone = mReportedVisibilityResults.nowGone;
boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
if (!nowGone) {
@@ -268,23 +226,16 @@ class AppWindowToken extends WindowToken {
+ numInteresting + " visible=" + numVisible);
if (nowDrawn != reportedDrawn) {
if (nowDrawn) {
Message m = mService.mH.obtainMessage(
H.REPORT_APPLICATION_TOKEN_DRAWN, this);
mService.mH.sendMessage(m);
mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget();
}
reportedDrawn = nowDrawn;
}
if (nowVisible != reportedVisible) {
if (DEBUG_VISIBILITY) Slog.v(
TAG, "Visibility changed in " + this
+ ": vis=" + nowVisible);
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Visibility changed in " + this + ": vis=" + nowVisible);
reportedVisible = nowVisible;
Message m = mService.mH.obtainMessage(
H.REPORT_APPLICATION_TOKEN_WINDOWS,
nowVisible ? 1 : 0,
nowGone ? 1 : 0,
this);
mService.mH.sendMessage(m);
mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS,
nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget();
}
}
@@ -332,45 +283,7 @@ class AppWindowToken extends WindowToken {
final int windowsCount = windows.size();
for (int i = 0; i < windowsCount; i++) {
final WindowState win = windows.get(i);
if (win == startingWindow) {
// Starting window that's exiting will be removed when the animation finishes.
// Mark all relevant flags for that onExitAnimationDone will proceed all the way
// to actually remove it.
if (!visible && win.isVisibleNow() && mAppAnimator.isAnimating()) {
win.mAnimatingExit = true;
win.mRemoveOnExit = true;
win.mWindowRemovalAllowed = true;
}
continue;
}
//Slog.i(TAG_WM, "Window " + win + ": vis=" + win.isVisible());
//win.dump(" ");
if (visible) {
if (!win.isVisibleNow()) {
if (!runningAppAnimation) {
win.mWinAnimator.applyAnimationLocked(TRANSIT_ENTER, true);
//TODO (multidisplay): Magnification is supported only for the default
if (accessibilityController != null
&& win.getDisplayId() == DEFAULT_DISPLAY) {
accessibilityController.onWindowTransitionLocked(win, TRANSIT_ENTER);
}
}
changed = true;
win.setDisplayLayoutNeeded();
}
} else if (win.isVisibleNow()) {
if (!runningAppAnimation) {
win.mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
//TODO (multidisplay): Magnification is supported only for the default
if (accessibilityController != null
&& win.getDisplayId() == DEFAULT_DISPLAY) {
accessibilityController.onWindowTransitionLocked(win,TRANSIT_EXIT);
}
}
changed = true;
win.setDisplayLayoutNeeded();
}
changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
}
hidden = hiddenRequested = !visible;
@@ -378,12 +291,11 @@ class AppWindowToken extends WindowToken {
if (!visible) {
stopFreezingScreen(true, true);
} else {
// If we are being set visible, and the starting window is
// not yet displayed, then make sure it doesn't get displayed.
WindowState swin = startingWindow;
if (swin != null && !swin.isDrawnLw()) {
swin.mPolicyVisibility = false;
swin.mPolicyVisibilityAfterAnim = false;
// If we are being set visible, and the starting window is not yet displayed,
// then make sure it doesn't get displayed.
if (startingWindow != null && !startingWindow.isDrawnLw()) {
startingWindow.mPolicyVisibility = false;
startingWindow.mPolicyVisibilityAfterAnim = false;
}
}
@@ -406,7 +318,7 @@ class AppWindowToken extends WindowToken {
}
for (int i = windows.size() - 1; i >= 0 && !delayed; i--) {
if (windows.get(i).mWinAnimator.isWindowAnimationSet()) {
if (windows.get(i).isWindowAnimationSet()) {
delayed = true;
}
}
@@ -436,9 +348,11 @@ class AppWindowToken extends WindowToken {
int j = windows.size();
while (j > 0) {
j--;
WindowState win = windows.get(j);
if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
|| win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
final WindowState win = windows.get(j);
final int type = win.mAttrs.type;
// No need to loop through child window as base application and starting types can't be
// child windows.
if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) {
// In cases where there are multiple windows, we prefer the non-exiting window. This
// happens for example when replacing windows during an activity relaunch. When
// constructing the animation, we want the new window, not the exiting one.
@@ -457,24 +371,17 @@ class AppWindowToken extends WindowToken {
}
boolean isVisible() {
final int N = windows.size();
for (int i=0; i<N; i++) {
WindowState win = windows.get(i);
// If we're animating with a saved surface, we're already visible.
// Return true so that the alpha doesn't get cleared.
if (!win.mAppFreezing
&& (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface()
|| (win.mWinAnimator.isAnimationSet()
&& !mService.mAppTransition.isTransitionSet()))
&& !win.mDestroying
&& win.isDrawnLw()) {
final int count = windows.size();
for (int i = 0; i < count; i++) {
final WindowState win = windows.get(i);
if (win.isVisible()) {
return true;
}
}
return false;
}
boolean isVisibleForUser() {
boolean canBeVisibleForCurrentUser() {
for (int j = windows.size() - 1; j >= 0; j--) {
final WindowState w = windows.get(j);
if (!w.isHiddenFromUserLocked()) {
@@ -503,35 +410,7 @@ class AppWindowToken extends WindowToken {
boolean wallpaperMightChange = false;
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState win = windows.get(i);
// We don't want to clear it out for windows that get replaced, because the
// animation depends on the flag to remove the replaced window.
//
// We also don't clear the mAnimatingExit flag for windows which have the
// mRemoveOnExit flag. This indicates an explicit remove request has been issued
// by the client. We should let animation proceed and not clear this flag or
// they won't eventually be removed by WindowStateAnimator#finishExit.
if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
// Clear mAnimating flag together with mAnimatingExit. When animation
// changes from exiting to entering, we need to clear this flag until the
// new animation gets applied, so that isAnimationStarting() becomes true
// until then.
// Otherwise applySurfaceChangesTransaction will faill to skip surface
// placement for this window during this period, one or more frame will
// show up with wrong position or scale.
if (win.mAnimatingExit) {
win.mAnimatingExit = false;
wallpaperMightChange = true;
}
if (win.mWinAnimator.mAnimating) {
win.mWinAnimator.mAnimating = false;
wallpaperMightChange = true;
}
if (win.mDestroying) {
win.mDestroying = false;
mService.mDestroySurface.remove(win);
wallpaperMightChange = true;
}
}
wallpaperMightChange |= win.clearAnimatingFlags();
}
if (wallpaperMightChange) {
requestUpdateWallpaperIfNeeded();
@@ -551,42 +430,18 @@ class AppWindowToken extends WindowToken {
* others so that they are ready to be reused. If set to false (common case), destroy all
* surfaces that's eligible, if the app is already stopped.
*/
private void destroySurfaces(boolean cleanupOnResume) {
final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) windows.clone();
final DisplayContentList displayList = new DisplayContentList();
for (int i = allWindows.size() - 1; i >= 0; i--) {
final WindowState win = allWindows.get(i);
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState win = windows.get(i);
final boolean destroyed = win.destroySurface(cleanupOnResume, mAppStopped);
if (!(mAppStopped || win.mWindowRemovalAllowed || cleanupOnResume)) {
continue;
if (destroyed) {
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent != null && !displayList.contains(displayContent)) {
displayList.add(displayContent);
}
}
win.mWinAnimator.destroyPreservedSurfaceLocked();
if (!win.mDestroying) {
continue;
}
if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
+ " destroySurfaces: mAppStopped=" + mAppStopped
+ " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
+ " win.mRemoveOnExit=" + win.mRemoveOnExit);
if (!cleanupOnResume || win.mRemoveOnExit) {
win.destroyOrSaveSurface();
}
if (win.mRemoveOnExit) {
win.remove();
}
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent != null && !displayList.contains(displayContent)) {
displayList.add(displayContent);
}
if (cleanupOnResume) {
win.requestUpdateWallpaperIfNeeded();
}
win.mDestroying = false;
}
for (int i = 0; i < displayList.size(); i++) {
final DisplayContent displayContent = displayList.get(i);
@@ -646,10 +501,10 @@ class AppWindowToken extends WindowToken {
return false;
}
void clearVisibleBeforeClientHidden() {
void clearWasVisibleBeforeClientHidden() {
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState w = windows.get(i);
w.clearVisibleBeforeClientHidden();
w.clearWasVisibleBeforeClientHidden();
}
}
@@ -674,14 +529,7 @@ class AppWindowToken extends WindowToken {
void stopUsingSavedSurfaceLocked() {
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState w = windows.get(i);
if (w.isAnimatingInvisibleWithSavedSurface()) {
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
"stopUsingSavedSurfaceLocked: " + w);
w.clearAnimatingWithSavedSurface();
w.mDestroying = true;
w.mWinAnimator.hide("stopUsingSavedSurfaceLocked");
mService.mWallpaperControllerLocked.hideWallpapers(w);
}
w.stopUsingSavedSurface();
}
destroySurfaces();
}
@@ -689,51 +537,40 @@ class AppWindowToken extends WindowToken {
void markSavedSurfaceExiting() {
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState w = windows.get(i);
if (w.isAnimatingInvisibleWithSavedSurface()) {
w.mAnimatingExit = true;
w.mWinAnimator.mAnimating = true;
}
w.markSavedSurfaceExiting();
}
}
void restoreSavedSurfaces() {
void restoreSavedSurfaceForInterestingWindows() {
if (!canRestoreSurfaces()) {
clearVisibleBeforeClientHidden();
clearWasVisibleBeforeClientHidden();
return;
}
// Check if we have enough drawn windows to mark allDrawn= true.
int numInteresting = 0;
int numDrawn = 0;
// Check if all interesting windows are drawn and we can mark allDrawn=true.
int interestingNotDrawn = -1;
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState w = windows.get(i);
if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden()
&& (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
numInteresting++;
if (w.hasSavedSurface()) {
w.restoreSavedSurface();
}
if (w.isDrawnLw()) {
numDrawn++;
}
}
final WindowState w = windows.get(i);
interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow();
}
if (!allDrawn) {
allDrawn = (numInteresting > 0) && (numInteresting == numDrawn);
allDrawn = (interestingNotDrawn == 0);
if (allDrawn) {
mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
}
}
clearVisibleBeforeClientHidden();
clearWasVisibleBeforeClientHidden();
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
"restoreSavedSurfaces: " + this + " allDrawn=" + allDrawn
+ " numInteresting=" + numInteresting + " numDrawn=" + numDrawn);
"restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn
+ " interestingNotDrawn=" + interestingNotDrawn);
}
void destroySavedSurfaces() {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState win = windows.get(i);
final WindowState win = windows.get(i);
win.destroySavedSurface();
}
}
@@ -764,7 +601,7 @@ class AppWindowToken extends WindowToken {
}
}
void removeAllDeadWindows() {
void removeDeadWindows() {
for (int winNdx = windows.size() - 1; winNdx >= 0;
// WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
// windows if the window to be removed has child windows. It also may
@@ -775,9 +612,10 @@ class AppWindowToken extends WindowToken {
WindowState win = windows.get(winNdx);
if (win.mAppDied) {
if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
"removeAllDeadWindows: " + win);
"removeDeadWindows: " + win);
// Set mDestroying, we don't want any animation or delayed removal here.
win.mDestroying = true;
// Also removes child windows.
win.removeIfPossible();
}
}
@@ -785,6 +623,8 @@ class AppWindowToken extends WindowToken {
boolean hasWindowsAlive() {
for (int i = windows.size() - 1; i >= 0; i--) {
// No need to loop through child windows as the answer should be the same as that of the
// parent window.
if (!windows.get(i).mAppDied) {
return true;
}
@@ -792,42 +632,40 @@ class AppWindowToken extends WindowToken {
return false;
}
void setReplacingWindows(boolean animate) {
void setWillReplaceWindows(boolean animate) {
if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
"Marking app token " + this + " with replacing windows.");
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState w = windows.get(i);
w.setReplacing(animate);
w.setWillReplaceWindow(animate);
}
if (animate) {
// Set-up dummy animation so we can start treating windows associated with this
// token like they are in transition before the new app window is ready for us to
// run the real transition animation.
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
"setReplacingWindow() Setting dummy animation on: " + this);
"setWillReplaceWindow() Setting dummy animation on: " + this);
mAppAnimator.setDummyAnimation();
}
}
void setReplacingChildren() {
void setWillReplaceChildWindows() {
if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
+ " with replacing child windows.");
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState w = windows.get(i);
if (w.shouldBeReplacedWithChildren()) {
w.setReplacing(false /* animate */);
}
w.setWillReplaceChildWindows();
}
}
void resetReplacingWindows() {
void clearWillReplaceWindows() {
if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
"Resetting app token " + this + " of replacing window marks.");
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState w = windows.get(i);
w.resetReplacing();
w.clearWillReplaceWindow();
}
}
@@ -872,49 +710,31 @@ class AppWindowToken extends WindowToken {
void addWindow(WindowState w) {
super.addWindow(w);
boolean gotReplacementWindow = false;
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState candidate = windows.get(i);
if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null
&& candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
}
candidate.mReplacingWindow = w;
w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
// if we got a replacement window, reset the timeout to give drawing more time
mService.scheduleReplacingWindowTimeouts(this);
}
// if we got a replacement window, reset the timeout to give drawing more time
if (gotReplacementWindow) {
mService.scheduleWindowReplacementTimeouts(this);
}
}
boolean waitingForReplacement() {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState candidate = windows.get(i);
if (candidate.mWillReplaceWindow) {
final WindowState candidate = windows.get(i);
if (candidate.waitingForReplacement()) {
return true;
}
}
return false;
}
void clearTimedoutReplacesLocked() {
for (int i = windows.size() - 1; i >= 0;
// WindowState#remove() at bottom of loop may remove multiple entries from windows if
// the window to be removed has child windows. It also may not remove any windows from
// windows at all if win is exiting and currently animating away. This ensures that
// winNdx is monotonically decreasing and never beyond windows bounds.
i = Math.min(i - 1, windows.size() - 1)) {
final WindowState candidate = windows.get(i);
if (!candidate.mWillReplaceWindow) {
continue;
}
candidate.mWillReplaceWindow = false;
if (candidate.mReplacingWindow != null) {
candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
}
// Since the window already timed out, remove it immediately now.
// Use WindowState#remove() instead of WindowState#removeIfPossible(), as the latter
// delays removal on certain conditions, which will leave the stale window in the
// stack and marked mWillReplaceWindow=false, so the window will never be removed.
candidate.remove();
void onWindowReplacementTimeout() {
for (int i = windows.size() - 1; i >= 0; --i) {
windows.get(i).onWindowReplacementTimeout();
}
}
@@ -956,14 +776,7 @@ class AppWindowToken extends WindowToken {
}
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState win = windows.get(i);
if (!win.mHasSurface) {
continue;
}
win.mLayoutNeeded = true;
win.setDisplayLayoutNeeded();
if (!mService.mResizingWindows.contains(win)) {
mService.mResizingWindows.add(win);
}
win.onUnfreezeBounds();
}
mService.mWindowPlacerLocked.performSurfacePlacement();
}
@@ -1019,52 +832,21 @@ class AppWindowToken extends WindowToken {
void setWaitingForDrawnIfResizingChanged() {
for (int i = windows.size() - 1; i >= 0; --i) {
final WindowState win = windows.get(i);
if (win.isDragResizeChanged()) {
mService.mWaitingForDrawn.add(win);
}
win.setWaitingForDrawnIfResizingChanged();
}
}
void resizeWindows() {
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
// Some windows won't go through the resizing process, if they don't have a surface, so
// destroy all saved surfaces here.
destroySavedSurfaces();
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (win.mHasSurface && !resizingWindows.contains(win)) {
if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
resizingWindows.add(win);
// If we are not drag resizing, force recreating of a new surface so updating
// the content and positioning that surface will be in sync.
//
// As we use this flag as a hint to freeze surface boundary updates,
// we'd like to only apply this to TYPE_BASE_APPLICATION,
// windows of TYPE_APPLICATION (or TYPE_DRAWN_APPLICATION) like dialogs,
// could appear to not be drag resizing while they resize, but we'd
// still like to manipulate their frame to update crop, etc...
//
// Anyway we don't need to synchronize position and content updates for these
// windows since they aren't at the base layer and could be moved around anyway.
if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
!mTask.mStack.getBoundsAnimating() && !win.isGoneForLayoutLw() &&
!mTask.inPinnedWorkspace()) {
win.setResizedWhileNotDragResizing(true);
}
}
if (win.isGoneForLayoutLw()) {
win.mResizedWhileGone = true;
}
win.addToResizingList();
}
}
void moveWindows() {
void setMovedByResize() {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
win.mMovedByResize = true;
win.setMovedByResize();
}
}
@@ -1087,6 +869,7 @@ class AppWindowToken extends WindowToken {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
// We are in the middle of changing the state of displays/stacks/tasks. We need
// to finish that, before we let layout interfere with it.
// Also removes child windows.
windows.get(winNdx).removeIfPossible();
doAnotherLayoutPass = true;
}
@@ -1097,18 +880,13 @@ class AppWindowToken extends WindowToken {
void forceWindowsScaleableInTransaction(boolean force) {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
if (winAnimator == null || !winAnimator.hasSurface()) {
continue;
}
winAnimator.mSurfaceController.forceScaleableInTransaction(force);
windows.get(winNdx).forceWindowsScaleableInTransaction(force);
}
}
boolean isAnimating() {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
if (windows.get(winNdx).isAnimating()) {
return true;
}
}
@@ -1118,6 +896,7 @@ class AppWindowToken extends WindowToken {
void setAppLayoutChanges(int changes, String reason, int displayId) {
final WindowAnimator windowAnimator = mAppAnimator.mAnimator;
for (int i = windows.size() - 1; i >= 0; i--) {
// Child windows will be on the same display as their parents.
if (displayId == windows.get(i).getDisplayId()) {
windowAnimator.setPendingLayoutChanges(displayId, changes);
if (DEBUG_LAYOUT_REPEATS) {
@@ -1132,17 +911,16 @@ class AppWindowToken extends WindowToken {
void removeReplacedWindowIfNeeded(WindowState replacement) {
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState win = windows.get(i);
if (win.mWillReplaceWindow && win.mReplacingWindow == replacement
&& replacement.hasDrawnLw()) {
replacement.mSkipEnterAnimationForSeamlessReplacement = false;
win.removeReplacedWindow();
if (win.removeReplacedWindowIfNeeded(replacement)) {
return;
}
}
}
void startFreezingScreen() {
if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
+ hidden + " freezing=" + mAppAnimator.freezingScreen);
+ hidden + " freezing=" + mAppAnimator.freezingScreen + " hiddenRequested="
+ hiddenRequested);
if (!hiddenRequested) {
if (!mAppAnimator.freezingScreen) {
mAppAnimator.freezingScreen = true;
@@ -1157,7 +935,7 @@ class AppWindowToken extends WindowToken {
final int count = windows.size();
for (int i = 0; i < count; i++) {
final WindowState w = windows.get(i);
w.mAppFreezing = true;
w.onStartFreezingScreen();
}
}
}
@@ -1171,18 +949,7 @@ class AppWindowToken extends WindowToken {
boolean unfrozeWindows = false;
for (int i = 0; i < count; i++) {
final WindowState w = windows.get(i);
if (w.mAppFreezing) {
w.mAppFreezing = false;
if (w.mHasSurface && !w.mOrientationChanging
&& mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + w);
w.mOrientationChanging = true;
mService.mWindowPlacerLocked.mOrientationChangeComplete = false;
}
w.mLastFreezeDuration = 0;
unfrozeWindows = true;
w.setDisplayLayoutNeeded();
}
unfrozeWindows |= w.onStopFreezingScreen();
}
if (force || unfrozeWindows) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
@@ -1297,8 +1064,8 @@ class AppWindowToken extends WindowToken {
return false;
}
int getWindowsCount() {
return windows.size();
boolean isLastWindow(WindowState win) {
return windows.size() == 1 && windows.get(0) == win;
}
void setAllAppWinAnimators() {
@@ -1307,7 +1074,7 @@ class AppWindowToken extends WindowToken {
final int windowsCount = windows.size();
for (int j = 0; j < windowsCount; j++) {
allAppWinAnimators.add(windows.get(j).mWinAnimator);
windows.get(j).addWinAnimatorToList(allAppWinAnimators);
}
}

View File

@@ -202,7 +202,7 @@ final class Session extends IWindowSession.Stub
@Override
public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) {
mService.setReplacingWindows(appToken, childrenOnly);
mService.setWillReplaceWindows(appToken, childrenOnly);
}
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,

View File

@@ -17,18 +17,14 @@
package com.android.server.wm;
import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import android.app.ActivityManager.StackId;
import android.content.pm.ActivityInfo;
@@ -44,7 +40,6 @@ import android.view.SurfaceControl;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
import java.util.ArrayList;
class Task implements DimLayer.DimLayerUser {
static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
@@ -311,7 +306,7 @@ class Task implements DimLayer.DimLayerUser {
if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
resizeWindows();
} else {
moveWindows();
setMovedByResize();
}
return true;
}
@@ -545,9 +540,9 @@ class Task implements DimLayer.DimLayerUser {
}
}
void moveWindows() {
void setMovedByResize() {
for (int i = mAppTokens.size() - 1; i >= 0; --i) {
mAppTokens.get(i).moveWindows();
mAppTokens.get(i).setMovedByResize();
}
}
@@ -616,10 +611,6 @@ class Task implements DimLayer.DimLayerUser {
return null;
}
AppWindowToken getTopAppToken() {
return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null;
}
@Override
public boolean dimFullscreen() {
return isHomeTask() || isFullscreen();

View File

@@ -91,4 +91,9 @@ class WindowContainer {
}
return false;
}
/** Returns the top child container or this container if there are no children. */
WindowContainer getTop() {
return mChildren.isEmpty() ? this : mChildren.peekLast();
}
}

View File

@@ -431,7 +431,7 @@ public class WindowManagerService extends IWindowManager.Stub
* List of app window tokens that are waiting for replacing windows. If the
* replacement doesn't come in time the stale windows needs to be disposed of.
*/
final ArrayList<AppWindowToken> mReplacingWindowTimeouts = new ArrayList<>();
final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();
/**
* The input consumer added to the window manager which consumes input events to windows below
@@ -3646,7 +3646,7 @@ public class WindowManagerService extends IWindowManager.Stub
// If the app is dead while it was visible, we kept its dead window on screen.
// Now that the app is going invisible, we can remove it. It will be restarted
// if made visible again.
wtoken.removeAllDeadWindows();
wtoken.removeDeadWindows();
wtoken.setVisibleBeforeClientHidden();
} else if (visible) {
if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
@@ -7748,11 +7748,11 @@ public class WindowManagerService extends IWindowManager.Stub
break;
case WINDOW_REPLACEMENT_TIMEOUT: {
synchronized (mWindowMap) {
for (int i = mReplacingWindowTimeouts.size() - 1; i >= 0; i--) {
final AppWindowToken token = mReplacingWindowTimeouts.get(i);
token.clearTimedoutReplacesLocked();
for (int i = mWindowReplacementTimeouts.size() - 1; i >= 0; i--) {
final AppWindowToken token = mWindowReplacementTimeouts.get(i);
token.onWindowReplacementTimeout();
}
mReplacingWindowTimeouts.clear();
mWindowReplacementTimeouts.clear();
}
}
case NOTIFY_APP_TRANSITION_STARTING: {
@@ -7877,7 +7877,7 @@ public class WindowManagerService extends IWindowManager.Stub
&& imFocus.mAppToken != null) {
// The client has definitely started, so it really should
// have a window in this app token. Let's look for it.
final WindowState w = imFocus.mAppToken.getFirstWindow(imFocus);
final WindowState w = imFocus.mAppToken.getFirstNonStartingWindow();
if (w != null) {
if (DEBUG_INPUT_METHOD) Slog.i(TAG_WM,
"Switching to real app window: " + w);
@@ -8519,7 +8519,7 @@ public class WindowManagerService extends IWindowManager.Stub
// If it's a dead window left on screen, and the configuration changed,
// there is nothing we can do about it. Remove the window now.
if (w.mAppToken != null && w.mAppDied) {
w.mAppToken.removeAllDeadWindows();
w.mAppToken.removeDeadWindows();
return;
}
@@ -10016,16 +10016,15 @@ public class WindowManagerService extends IWindowManager.Stub
* a window.
* @param token Application token for which the activity will be relaunched.
*/
public void setReplacingWindow(IBinder token, boolean animate) {
AppWindowToken appWindowToken = null;
public void setWillReplaceWindow(IBinder token, boolean animate) {
synchronized (mWindowMap) {
appWindowToken = findAppWindowToken(token);
final AppWindowToken appWindowToken = findAppWindowToken(token);
if (appWindowToken == null || !appWindowToken.isVisible()) {
Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ token);
return;
}
appWindowToken.setReplacingWindows(animate);
appWindowToken.setWillReplaceWindows(animate);
}
}
@@ -10039,10 +10038,11 @@ public class WindowManagerService extends IWindowManager.Stub
* reused rather than replaced).
*
*/
public void setReplacingWindows(IBinder token, boolean childrenOnly) {
AppWindowToken appWindowToken = null;
// TODO: The s at the end of the method name is the only difference with the name of the method
// above. We should combine them or find better names.
public void setWillReplaceWindows(IBinder token, boolean childrenOnly) {
synchronized (mWindowMap) {
appWindowToken = findAppWindowToken(token);
final AppWindowToken appWindowToken = findAppWindowToken(token);
if (appWindowToken == null || !appWindowToken.isVisible()) {
Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ token);
@@ -10050,12 +10050,12 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (childrenOnly) {
appWindowToken.setReplacingChildren();
appWindowToken.setWillReplaceChildWindows();
} else {
appWindowToken.setReplacingWindows(false /* animate */);
appWindowToken.setWillReplaceWindows(false /* animate */);
}
scheduleClearReplacingWindowIfNeeded(token, true /* replacing */);
scheduleClearWillReplaceWindows(token, true /* replacing */);
}
}
@@ -10068,26 +10068,25 @@ public class WindowManagerService extends IWindowManager.Stub
* @param token Application token for the activity whose window might be replaced.
* @param replacing Whether the window is being replaced or not.
*/
public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) {
AppWindowToken appWindowToken = null;
public void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) {
synchronized (mWindowMap) {
appWindowToken = findAppWindowToken(token);
final AppWindowToken appWindowToken = findAppWindowToken(token);
if (appWindowToken == null) {
Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
+ token);
return;
}
if (replacing) {
scheduleReplacingWindowTimeouts(appWindowToken);
scheduleWindowReplacementTimeouts(appWindowToken);
} else {
appWindowToken.resetReplacingWindows();
appWindowToken.clearWillReplaceWindows();
}
}
}
void scheduleReplacingWindowTimeouts(AppWindowToken appWindowToken) {
if (!mReplacingWindowTimeouts.contains(appWindowToken)) {
mReplacingWindowTimeouts.add(appWindowToken);
void scheduleWindowReplacementTimeouts(AppWindowToken appWindowToken) {
if (!mWindowReplacementTimeouts.contains(appWindowToken)) {
mWindowReplacementTimeouts.add(appWindowToken);
}
mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
mH.sendEmptyMessageDelayed(

View File

@@ -99,6 +99,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
@@ -117,6 +118,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -126,6 +128,7 @@ import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -486,7 +489,7 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
boolean mAnimateReplacingWindow = false;
// If not null, the window that will be used to replace the old one. This is being set when
// the window is added and unset when this window reports its first draw.
WindowState mReplacingWindow = null;
WindowState mReplacementWindow = null;
// For the new window in the replacement transition, if we have
// requested to replace without animation, then we should
// make sure we also don't apply an enter animation for
@@ -531,6 +534,8 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
*/
boolean mSeamlesslyRotated = false;
private static final Region sEmptyRegion = new Region();
/**
* Compares to window sub-layers and returns -1 if the first is lesser than the second in terms
* of z-order and 1 otherwise.
@@ -599,7 +604,7 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
}
mDeathRecipient = deathRecipient;
if ((mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW)) {
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(parentWindow.mAttrs.type)
@@ -1165,6 +1170,26 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
}
}
// TODO: Sigh...another is visible method...tried to consolidate with other isVisible methods
// below, but failed. Need to figure-out a good way to handle this long term...
boolean isVisible() {
// If we're animating with a saved surface, we're already visible.
// Return true so that the alpha doesn't get cleared.
if (!mAppFreezing && isDrawnLw()
&& (mViewVisibility == View.VISIBLE || isAnimatingWithSavedSurface()
|| (mWinAnimator.isAnimationSet() && !mService.mAppTransition.isTransitionSet()))) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.isVisible()) {
return true;
}
}
return false;
}
/**
* Does the minimal check for visibility. Callers generally want to use one of the public
* methods as they perform additional checks on the app token.
@@ -1402,6 +1427,131 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
&& (mAppToken == null || mAppToken.mAppAnimator.animation == null);
}
void setMovedByResize() {
if (DEBUG_RESIZE) Slog.d(TAG, "setMovedByResize: Moving " + this);
mMovedByResize = true;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.setMovedByResize();
}
}
boolean onAppVisibilityChanged(boolean visible, boolean runningAppAnimation) {
boolean changed = false;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
changed |= c.onAppVisibilityChanged(visible, runningAppAnimation);
}
if (mAttrs.type == TYPE_APPLICATION_STARTING) {
// Starting window that's exiting will be removed when the animation finishes.
// Mark all relevant flags for that onExitAnimationDone will proceed all the way
// to actually remove it.
if (!visible && isVisibleNow() && mAppToken.mAppAnimator.isAnimating()) {
mAnimatingExit = true;
mRemoveOnExit = true;
mWindowRemovalAllowed = true;
}
return changed;
}
if (visible != isVisibleNow()) {
if (!runningAppAnimation) {
final AccessibilityController accessibilityController =
mService.mAccessibilityController;
final int winTransit = visible ? TRANSIT_ENTER : TRANSIT_EXIT;
mWinAnimator.applyAnimationLocked(winTransit, visible);
//TODO (multidisplay): Magnification is supported only for the default
if (accessibilityController != null && getDisplayId() == DEFAULT_DISPLAY) {
accessibilityController.onWindowTransitionLocked(this, winTransit);
}
}
changed = true;
setDisplayLayoutNeeded();
}
return changed;
}
boolean onSetAppExiting() {
final DisplayContent displayContent = getDisplayContent();
boolean changed = false;
if (isVisibleNow()) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
//TODO (multidisplay): Magnification is supported only for the default
if (mService.mAccessibilityController != null && isDefaultDisplay()) {
mService.mAccessibilityController.onWindowTransitionLocked(this, TRANSIT_EXIT);
}
changed = true;
if (displayContent != null) {
displayContent.layoutNeeded = true;
}
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
changed |= c.onSetAppExiting();
}
return changed;
}
void addToResizingList() {
// Some windows won't go through the resizing process, if they don't have a surface, so
// destroy all saved surfaces here.
destroySavedSurface();
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
if (mHasSurface && !resizingWindows.contains(this)) {
if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + this);
resizingWindows.add(this);
// If we are not drag resizing, force recreating of a new surface so updating
// the content and positioning that surface will be in sync.
//
// As we use this flag as a hint to freeze surface boundary updates, we'd like to only
// apply this to TYPE_BASE_APPLICATION, windows of TYPE_APPLICATION like dialogs, could
// appear to not be drag resizing while they resize, but we'd still like to manipulate
// their frame to update crop, etc...
//
// Anyway we don't need to synchronize position and content updates for these
// windows since they aren't at the base layer and could be moved around anyway.
if (!computeDragResizing() && mAttrs.type == TYPE_BASE_APPLICATION &&
!getTask().mStack.getBoundsAnimating() && !isGoneForLayoutLw() &&
!getTask().inPinnedWorkspace()) {
setResizedWhileNotDragResizing(true);
}
}
if (isGoneForLayoutLw()) {
mResizedWhileGone = true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.addToResizingList();
}
}
void onUnfreezeBounds() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.onUnfreezeBounds();
}
if (!mHasSurface) {
return;
}
mLayoutNeeded = true;
setDisplayLayoutNeeded();
if (!mService.mResizingWindows.contains(this)) {
mService.mResizingWindows.add(this);
}
}
/**
* Return whether this window has moved. (Only makes
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
@@ -1451,6 +1601,34 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
&& mAppToken.mTask.mStack.isAdjustedForMinimizedDock();
}
void onWindowReplacementTimeout() {
if (mWillReplaceWindow) {
// Since the window already timed out, remove it immediately now.
// Use WindowState#remove() instead of WindowState#removeIfPossible(), as the latter
// delays removal on certain conditions, which will leave the stale window in the
// stack and marked mWillReplaceWindow=false, so the window will never be removed.
//
// Also removes child windows.
remove();
} else {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.onWindowReplacementTimeout();
}
}
}
void forceWindowsScaleableInTransaction(boolean force) {
if (mWinAnimator != null && mWinAnimator.hasSurface()) {
mWinAnimator.mSurfaceController.forceScaleableInTransaction(force);
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.forceWindowsScaleableInTransaction(force);
}
}
@Override
void remove() {
super.remove();
@@ -1463,6 +1641,11 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
mRemoved = true;
mWillReplaceWindow = false;
if (mReplacementWindow != null) {
mReplacementWindow.mSkipEnterAnimationForSeamlessReplacement = false;
}
if (mService.mInputMethodTarget == this) {
mService.moveInputMethodWindowsIfNeededLocked(false);
}
@@ -1490,6 +1673,10 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
}
void removeIfPossible() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.removeIfPossible(false /*keepVisibleDeadWindow*/);
}
removeIfPossible(false /*keepVisibleDeadWindow*/);
}
@@ -1598,7 +1785,7 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
final boolean isAnimating =
mWinAnimator.isAnimationSet() && !mWinAnimator.isDummyAnimation();
final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null
&& mAppToken.getWindowsCount() == 1;
&& mAppToken.isLastWindow(this);
// We delay the removal of a window if it has a showing surface that can be used to run
// exit animation and it is marked as exiting.
// Also, If isn't the an animating starting window that is the last window in the app.
@@ -1690,6 +1877,11 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
*/
void notifyMovedInStack() {
mJustMovedInStack = true;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.notifyMovedInStack();
}
}
/**
@@ -1706,6 +1898,11 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
*/
void resetJustMovedInStack() {
mJustMovedInStack = false;
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
c.resetJustMovedInStack();
}
}
private final class DeadWindowEventReceiver extends InputEventReceiver {
@@ -1789,6 +1986,23 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return getStack();
}
/** Returns true if the replacement window was removed. */
boolean removeReplacedWindowIfNeeded(WindowState replacement) {
if (mWillReplaceWindow && mReplacementWindow == replacement && replacement.hasDrawnLw()) {
replacement.mSkipEnterAnimationForSeamlessReplacement = false;
removeReplacedWindow();
return true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.removeReplacedWindowIfNeeded(replacement)) {
return true;
}
}
return false;
}
void removeReplacedWindow() {
if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + this);
if (isDimming()) {
@@ -1797,12 +2011,31 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
mWillReplaceWindow = false;
mAnimateReplacingWindow = false;
mReplacingRemoveRequested = false;
mReplacingWindow = null;
mReplacementWindow = null;
if (mAnimatingExit || !mAnimateReplacingWindow) {
remove();
}
}
boolean setReplacementWindowIfNeeded(WindowState replacementCandidate) {
boolean replacementSet = false;
if (mWillReplaceWindow && mReplacementWindow == null
&& getWindowTag().toString().equals(replacementCandidate.getWindowTag().toString())) {
mReplacementWindow = replacementCandidate;
replacementCandidate.mSkipEnterAnimationForSeamlessReplacement = !mAnimateReplacingWindow;
replacementSet = true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
replacementSet |= c.setReplacementWindowIfNeeded(replacementCandidate);
}
return replacementSet;
}
void setDisplayLayoutNeeded() {
if (mDisplayContent != null) {
mDisplayContent.layoutNeeded = true;
@@ -2058,8 +2291,7 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
doAnimation = false;
}
}
boolean current = doAnimation ? mPolicyVisibilityAfterAnim
: mPolicyVisibility;
boolean current = doAnimation ? mPolicyVisibilityAfterAnim : mPolicyVisibility;
if (!current) {
// Already hiding.
return false;
@@ -2070,11 +2302,9 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
doAnimation = false;
}
}
if (doAnimation) {
mPolicyVisibilityAfterAnim = false;
} else {
mPolicyVisibilityAfterAnim = false;
if (!doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility false: " + this);
mPolicyVisibilityAfterAnim = false;
mPolicyVisibility = false;
// Window is no longer visible -- make sure if we were waiting
// for it to be displayed before enabling the display, that
@@ -2146,24 +2376,141 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return mAnimatingWithSavedSurface;
}
boolean isAnimating() {
if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.isAnimating()) {
return true;
}
}
return false;
}
boolean isAnimatingInvisibleWithSavedSurface() {
return mAnimatingWithSavedSurface
&& (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed);
if (mAnimatingWithSavedSurface
&& (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed)) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.isAnimatingInvisibleWithSavedSurface()) {
return true;
}
}
return false;
}
void stopUsingSavedSurface() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.stopUsingSavedSurface();
}
if (!isAnimatingInvisibleWithSavedSurface()) {
return;
}
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, "stopUsingSavedSurface: " + this);
clearAnimatingWithSavedSurface();
mDestroying = true;
mWinAnimator.hide("stopUsingSavedSurface");
mService.mWallpaperControllerLocked.hideWallpapers(this);
}
void markSavedSurfaceExiting() {
if (isAnimatingInvisibleWithSavedSurface()) {
mAnimatingExit = true;
mWinAnimator.mAnimating = true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.markSavedSurfaceExiting();
}
}
void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
animators.add(mWinAnimator);
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.addWinAnimatorToList(animators);
}
}
void sendAppVisibilityToClients(boolean clientHidden) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.sendAppVisibilityToClients(clientHidden);
}
if (mAttrs.type == TYPE_APPLICATION_STARTING && clientHidden) {
// Don't hide the starting window.
return;
}
try {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Setting visibility of " + this + ": " + (!clientHidden));
mClient.dispatchAppVisibility(!clientHidden);
} catch (RemoteException e) {
}
}
public void setVisibleBeforeClientHidden() {
mWasVisibleBeforeClientHidden |=
(mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface);
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.setVisibleBeforeClientHidden();
}
}
public void clearVisibleBeforeClientHidden() {
public void clearWasVisibleBeforeClientHidden() {
mWasVisibleBeforeClientHidden = false;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.clearWasVisibleBeforeClientHidden();
}
}
public boolean wasVisibleBeforeClientHidden() {
return mWasVisibleBeforeClientHidden;
}
void onStartFreezingScreen() {
mAppFreezing = true;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.onStartFreezingScreen();
}
}
boolean onStopFreezingScreen() {
boolean unfrozeWindows = false;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
unfrozeWindows |= c.onStopFreezingScreen();
}
if (!mAppFreezing) {
return unfrozeWindows;
}
if (mHasSurface && !mOrientationChanging
&& mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this);
mOrientationChanging = true;
mService.mWindowPlacerLocked.mOrientationChangeComplete = false;
}
mLastFreezeDuration = 0;
setDisplayLayoutNeeded();
return true;
}
private boolean shouldSaveSurface() {
if (mWinAnimator.mSurfaceController == null) {
// Don't bother if the surface controller is gone for any reason.
@@ -2212,7 +2559,38 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return mAppToken.shouldSaveSurface();
}
static final Region sEmptyRegion = new Region();
boolean destroySurface(boolean cleanupOnResume, boolean appStopped) {
boolean destroyedSomething = false;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
destroyedSomething |= c.destroySurface(cleanupOnResume, appStopped);
}
if (appStopped || mWindowRemovalAllowed || cleanupOnResume) {
mWinAnimator.destroyPreservedSurfaceLocked();
if (mDestroying) {
if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + this
+ " destroySurfaces: appStopped=" + appStopped
+ " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
+ " win.mRemoveOnExit=" + mRemoveOnExit);
if (!cleanupOnResume || mRemoveOnExit) {
destroyOrSaveSurface();
}
if (mRemoveOnExit) {
remove();
}
if (cleanupOnResume) {
requestUpdateWallpaperIfNeeded();
}
mDestroying = false;
destroyedSomething = true;
}
}
return destroyedSomething;
}
void destroyOrSaveSurface() {
mSurfaceSaved = shouldSaveSurface();
@@ -2243,29 +2621,65 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
}
void destroySavedSurface() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.destroySavedSurface();
}
if (mSurfaceSaved) {
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
Slog.v(TAG, "Destroying saved surface: " + this);
}
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "Destroying saved surface: " + this);
mWinAnimator.destroySurfaceLocked();
mSurfaceSaved = false;
}
mWasVisibleBeforeClientHidden = false;
}
void restoreSavedSurface() {
if (!mSurfaceSaved) {
return;
/** Returns -1 if there are no interesting windows or number of interesting windows not drawn.*/
int restoreSavedSurfaceForInterestingWindow() {
int interestingNotDrawn = -1;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
final int childInterestingNotDrawn = c.restoreSavedSurfaceForInterestingWindow();
if (childInterestingNotDrawn != -1) {
if (interestingNotDrawn == -1) {
interestingNotDrawn = childInterestingNotDrawn;
} else {
interestingNotDrawn += childInterestingNotDrawn;
}
}
}
// Sometimes we save surfaces due to layout invisible
// directly after rotation occurs. However this means
// the surface was never laid out in the new orientation.
// We can only restore to the last rotation we were
// laid out as visible in.
if (mAttrs.type == TYPE_APPLICATION_STARTING
|| mAppDied || !wasVisibleBeforeClientHidden()
|| (mAppToken.mAppAnimator.freezingScreen && mAppFreezing)) {
// Window isn't interesting...
return interestingNotDrawn;
}
restoreSavedSurface();
if (!isDrawnLw()) {
if (interestingNotDrawn == -1) {
interestingNotDrawn = 1;
} else {
interestingNotDrawn++;
}
}
return interestingNotDrawn;
}
/** Returns true if the saved surface was restored. */
boolean restoreSavedSurface() {
if (!mSurfaceSaved) {
return false;
}
// Sometimes we save surfaces due to layout invisible directly after rotation occurs.
// However this means the surface was never laid out in the new orientation.
// We can only restore to the last rotation we were laid out as visible in.
if (mLastVisibleLayoutRotation != mService.mRotation) {
destroySavedSurface();
return;
return false;
}
mSurfaceSaved = false;
@@ -2285,10 +2699,23 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
// or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
}
return true;
}
boolean canRestoreSurface() {
return mWasVisibleBeforeClientHidden && mSurfaceSaved;
if (mWasVisibleBeforeClientHidden && mSurfaceSaved) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.canRestoreSurface()) {
return true;
}
}
return false;
}
boolean hasSavedSurface() {
@@ -2601,6 +3028,16 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return mDragResizing != computeDragResizing();
}
void setWaitingForDrawnIfResizingChanged() {
if (isDragResizeChanged()) {
mService.mWaitingForDrawn.add(this);
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.setWaitingForDrawnIfResizingChanged();
}
}
/**
* @return Whether we reported a drag resize change to the application or not already.
*/
@@ -2613,6 +3050,10 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
*/
void resetDragResizingChangeReported() {
mDragResizingChangeReported = false;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.resetDragResizingChangeReported();
}
}
/**
@@ -3009,7 +3450,8 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
WindowState getBottomChild() {
// Child windows are z-ordered based on sub-layer using {@link #sWindowSubLayerComparator}
// and the child with the lowest z-order will be at the head of the list.
return (WindowState) mChildren.peekFirst();
WindowContainer c = mChildren.peekFirst();
return c == null ? null : (WindowState)c;
}
boolean layoutInParentFrame() {
@@ -3038,7 +3480,12 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return (parent == null) ? false : parent.mHidden;
}
void setReplacing(boolean animate) {
void setWillReplaceWindow(boolean animate) {
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
c.setWillReplaceWindow(animate);
}
if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
|| mAttrs.type == TYPE_APPLICATION_STARTING) {
// We don't set replacing on starting windows since they are added by window manager and
@@ -3047,14 +3494,33 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
}
mWillReplaceWindow = true;
mReplacingWindow = null;
mReplacementWindow = null;
mAnimateReplacingWindow = animate;
}
void resetReplacing() {
void clearWillReplaceWindow() {
mWillReplaceWindow = false;
mReplacingWindow = null;
mReplacementWindow = null;
mAnimateReplacingWindow = false;
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
c.clearWillReplaceWindow();
}
}
boolean waitingForReplacement() {
if (mWillReplaceWindow) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.waitingForReplacement()) {
return true;
}
}
return false;
}
void requestUpdateWallpaperIfNeeded() {
@@ -3063,6 +3529,11 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
mDisplayContent.layoutNeeded = true;
mService.mWindowPlacerLocked.requestTraversal();
}
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
c.requestUpdateWallpaperIfNeeded();
}
}
float translateToWindowX(float x) {
@@ -3085,7 +3556,7 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
if (dimLayerUser != null && mDisplayContent != null) {
mDisplayContent.mDimLayerController.applyDim(dimLayerUser,
mReplacingWindow.mWinAnimator,
mReplacementWindow.mWinAnimator,
(mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? true : false);
}
}
@@ -3103,6 +3574,30 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
|| mAttrs.type == TYPE_DRAWN_APPLICATION;
}
void setWillReplaceChildWindows() {
if (shouldBeReplacedWithChildren()) {
setWillReplaceWindow(false /* animate */);
}
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
c.setWillReplaceChildWindows();
}
}
WindowState getReplacingWindow() {
if (mAnimatingExit && mWillReplaceWindow && mAnimateReplacingWindow) {
return this;
}
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
final WindowState replacing = c.getReplacingWindow();
if (replacing != null) {
return replacing;
}
}
return null;
}
public int getRotationAnimationHint() {
if (mAppToken != null) {
return mAppToken.mRotationAnimationHint;
@@ -3211,13 +3706,30 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return windowInfo;
}
void adjustAnimLayer(int adj) {
mWinAnimator.mAnimLayer = mLayer + adj;
if (DEBUG_LAYERS) Slog.v(TAG_WM, "win=" + this + " anim layer: " + mWinAnimator.mAnimLayer);
int getHighestAnimLayer() {
int highest = mWinAnimator.mAnimLayer;
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState c = (WindowState) mChildren.get(i);
final int childLayer = c.getHighestAnimLayer();
if (childLayer > highest) {
highest = childLayer;
}
}
return highest;
}
int adjustAnimLayer(int adj) {
int highestAnimLayer = mWinAnimator.mAnimLayer = mLayer + adj;
if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG_WM,
"adjustAnimLayer win=" + this + " anim layer: " + mWinAnimator.mAnimLayer);
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState childWindow = (WindowState) mChildren.get(i);
childWindow.adjustAnimLayer(adj);
if (childWindow.mWinAnimator.mAnimLayer > highestAnimLayer) {
highestAnimLayer = childWindow.mWinAnimator.mAnimLayer;
}
}
return highestAnimLayer;
}
// TODO: come-up with a better name for this method that represents what it does.
@@ -3280,6 +3792,19 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
return interestingPos;
}
boolean isWindowAnimationSet() {
if (mWinAnimator.isWindowAnimationSet()) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
if (c.isWindowAnimationSet()) {
return true;
}
}
return false;
}
void onExitAnimationDone() {
if (DEBUG_ANIM) Slog.v(TAG, "onExitAnimationDone in " + this
+ ": exiting=" + mAnimatingExit + " remove=" + mRemoveOnExit
@@ -3351,11 +3876,54 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
mService.mWallpaperControllerLocked.hideWallpapers(this);
}
boolean clearAnimatingFlags() {
boolean didSomething = false;
// We don't want to clear it out for windows that get replaced, because the
// animation depends on the flag to remove the replaced window.
//
// We also don't clear the mAnimatingExit flag for windows which have the
// mRemoveOnExit flag. This indicates an explicit remove request has been issued
// by the client. We should let animation proceed and not clear this flag or
// they won't eventually be removed by WindowStateAnimator#finishExit.
if (!mWillReplaceWindow && !mRemoveOnExit) {
// Clear mAnimating flag together with mAnimatingExit. When animation
// changes from exiting to entering, we need to clear this flag until the
// new animation gets applied, so that isAnimationStarting() becomes true
// until then.
// Otherwise applySurfaceChangesTransaction will fail to skip surface
// placement for this window during this period, one or more frame will
// show up with wrong position or scale.
if (mAnimatingExit) {
mAnimatingExit = false;
didSomething = true;
}
if (mWinAnimator.mAnimating) {
mWinAnimator.mAnimating = false;
didSomething = true;
}
if (mDestroying) {
mDestroying = false;
mService.mDestroySurface.remove(this);
didSomething = true;
}
}
for (int i = mChildren.size() - 1; i >= 0; --i) {
didSomething |= ((WindowState) mChildren.get(i)).clearAnimatingFlags();
}
return didSomething;
}
public boolean isRtl() {
return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
void hideWallpaperWindow(boolean wasDeferred, String reason) {
for (int j = mChildren.size() - 1; j >= 0; --j) {
final WindowState c = (WindowState) mChildren.get(j);
c.hideWallpaperWindow(wasDeferred, reason);
}
if (!mWinAnimator.mLastHidden || wasDeferred) {
mWinAnimator.hide(reason);
dispatchWallpaperVisibility(false);
@@ -3388,6 +3956,19 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
}
}
boolean hasVisibleNotDrawnWallpaper() {
if (mWallpaperVisible && !isDrawnLw()) {
return true;
}
for (int j = mChildren.size() - 1; j >= 0; --j) {
final WindowState c = (WindowState) mChildren.get(j);
if (c.hasVisibleNotDrawnWallpaper()) {
return true;
}
}
return false;
}
/** Places this window after the input window in the window list. */
void addWindowToListAfter(WindowState pos) {
final WindowList windows = pos.getWindowList();
@@ -3441,4 +4022,57 @@ class WindowState extends WindowContainer implements WindowManagerPolicy.WindowS
windows.add(i, this);
mService.mWindowsChanged = true;
}
void updateReportedVisibility(UpdateReportedVisibilityResults results) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = (WindowState) mChildren.get(i);
c.updateReportedVisibility(results);
}
if (mAppFreezing || mViewVisibility != View.VISIBLE
|| mAttrs.type == TYPE_APPLICATION_STARTING
|| mDestroying) {
return;
}
if (DEBUG_VISIBILITY) {
Slog.v(TAG, "Win " + this + ": isDrawn=" + isDrawnLw()
+ ", isAnimationSet=" + mWinAnimator.isAnimationSet());
if (!isDrawnLw()) {
Slog.v(TAG, "Not displayed: s=" + mWinAnimator.mSurfaceController
+ " pv=" + mPolicyVisibility
+ " mDrawState=" + mWinAnimator.mDrawState
+ " ph=" + isParentWindowHidden()
+ " th=" + (mAppToken != null ? mAppToken.hiddenRequested : false)
+ " a=" + mWinAnimator.mAnimating);
}
}
results.numInteresting++;
if (isDrawnLw()) {
results.numDrawn++;
if (!mWinAnimator.isAnimationSet()) {
results.numVisible++;
}
results.nowGone = false;
} else if (mWinAnimator.isAnimationSet()) {
results.nowGone = false;
}
}
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
// access to its windows children. Need to investigate re-writing
// {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
static final class UpdateReportedVisibilityResults {
int numInteresting;
int numVisible;
int numDrawn;
boolean nowGone = true;
void reset() {
numInteresting = 0;
numVisible = 0;
numDrawn = 0;
nowGone = true;
}
}
}

View File

@@ -597,10 +597,9 @@ class WindowStateAnimator {
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
if (w.hasSavedSurface()) {
if (w.restoreSavedSurface()) {
if (DEBUG_ANIM) Slog.i(TAG,
"createSurface: " + this + ": called when we had a saved surface");
w.restoreSavedSurface();
return mSurfaceController;
}

View File

@@ -1352,7 +1352,7 @@ class WindowSurfacePlacer {
}
final boolean drawnBeforeRestoring = wtoken.allDrawn;
wtoken.restoreSavedSurfaces();
wtoken.restoreSavedSurfaceForInterestingWindows();
if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
return false;

View File

@@ -28,14 +28,13 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -96,14 +95,8 @@ class WindowToken {
}
void removeAllWindows() {
for (int winNdx = windows.size() - 1; winNdx >= 0;
// WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
// allAppWindows if the window to be removed has child windows. It also may not
// remove any windows from allAppWindows at all if win is exiting and currently
// animating away. This ensures that winNdx is monotonically decreasing and never
// beyond allAppWindows bounds.
winNdx = Math.min(winNdx - 1, windows.size() - 1)) {
WindowState win = windows.get(winNdx);
for (int i = windows.size() - 1; i >= 0; --i) {
final WindowState win = windows.get(i);
if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM, "removeAllWindows: removing win=" + win);
win.removeIfPossible();
}
@@ -115,30 +108,20 @@ class WindowToken {
return;
}
boolean delayed = false;
final int count = windows.size();
boolean changed = false;
boolean delayed = false;
DisplayContent displayContent = null;
for (int i = 0; i < count; i++) {
final WindowState win = windows.get(i);
displayContent = win.getDisplayContent();
if (win.mWinAnimator.isAnimationSet()) {
delayed = true;
// TODO: This is technically wrong as a token can have windows on multi-displays
// currently. That will change moving forward though.
displayContent = win.getDisplayContent();
}
if (win.isVisibleNow()) {
win.mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
//TODO (multidisplay): Magnification is supported only for the default
if (mService.mAccessibilityController != null && win.isDefaultDisplay()) {
mService.mAccessibilityController.onWindowTransitionLocked(win, TRANSIT_EXIT);
}
changed = true;
if (displayContent != null) {
displayContent.layoutNeeded = true;
}
}
changed |= win.onSetAppExiting();
}
hidden = true;
@@ -157,12 +140,9 @@ class WindowToken {
int highestAnimLayer = -1;
for (int j = windows.size() - 1; j >= 0; j--) {
final WindowState w = windows.get(j);
w.adjustAnimLayer(adj);
final int animLayer = w.mWinAnimator.mAnimLayer;
if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG,
"adjustAnimLayer win " + w + " anim layer: " + animLayer);
if (animLayer > highestAnimLayer) {
highestAnimLayer = animLayer;
final int winHighestAnimLayer = w.adjustAnimLayer(adj);
if (winHighestAnimLayer > highestAnimLayer) {
highestAnimLayer = winHighestAnimLayer;
}
if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
mService.mLayersController.setInputMethodAnimLayerAdjustment(adj);
@@ -175,7 +155,7 @@ class WindowToken {
if (windows.isEmpty()) {
return null;
}
return windows.get(windows.size() - 1);
return (WindowState) windows.get(windows.size() - 1).getTop();
}
/**
@@ -198,18 +178,22 @@ class WindowToken {
* @param displayContent The display we are interested in.
* @return List of windows from token that are on displayContent.
*/
protected WindowList getTokenWindowsOnDisplay(DisplayContent displayContent) {
private WindowList getTokenWindowsOnDisplay(DisplayContent displayContent) {
final WindowList windowList = new WindowList();
final int count = windows.size();
final WindowList displayWindows = displayContent.getWindowList();
final int count = displayWindows.size();
for (int i = 0; i < count; i++) {
final WindowState win = windows.get(i);
if (win.getDisplayContent() == displayContent) {
final WindowState win = displayWindows.get(i);
if (win.mToken == this) {
windowList.add(win);
}
}
return windowList;
}
// TODO: Now that we are no longer adding child windows to token directly, the rest of the code
// in this method doesn't really belong here, but is it difficult to move at the moment. Need to
// re-evaluate when figuring-out what to do about display window list.
private void addChildWindow(final WindowState win) {
final DisplayContent displayContent = win.getDisplayContent();
if (displayContent == null) {
@@ -235,30 +219,18 @@ class WindowToken {
if (sublayer < 0) {
// For negative sublayers, we go below all windows in the same sublayer.
if (wSublayer >= sublayer) {
if (!windows.contains(win)) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
windows.add(i, win);
}
win.addWindowToListBefore(wSublayer >= 0 ? parentWindow : w);
break;
}
} else {
// For positive sublayers, we go above all windows in the same sublayer.
if (wSublayer > sublayer) {
if (!windows.contains(win)) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
windows.add(i, win);
}
win.addWindowToListBefore(w);
break;
}
}
}
if (i >= wCount) {
if (!windows.contains(win)) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
windows.add(win);
}
if (sublayer < 0) {
win.addWindowToListBefore(parentWindow);
} else {
@@ -364,7 +336,7 @@ class WindowToken {
for ( ; taskNdx >= 0; --taskNdx) {
AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
for ( ; tokenNdx >= 0; --tokenNdx) {
final AppWindowToken t = tokens.get(tokenNdx);
final WindowToken t = tokens.get(tokenNdx);
tokenWindowList = t.getTokenWindowsOnDisplay(displayContent);
final int NW = tokenWindowList.size();
if (NW > 0) {
@@ -455,16 +427,6 @@ class WindowToken {
final int count = windows.size();
for (int i = 0; i < count; i++) {
final WindowState win = windows.get(i);
if (win.isChildWindow()) {
// The WindowState.reAddWindow below already takes care of re-adding the
// child windows for any parent window in this token. This is a side effect of
// ensuring child windows are in the same WindowToken as their parent window.
//
// TODO: Can be removed once WindowToken no longer contains child windows. i.e it is
// using WindowContainer which uses the hierarchy to access child windows through
// their parent window.
continue;
}
final DisplayContent winDisplayContent = win.getDisplayContent();
if (winDisplayContent == displayContent || winDisplayContent == null) {
win.mDisplayContent = displayContent;
@@ -489,11 +451,13 @@ class WindowToken {
return -1;
}
/** Return the first window in the token window list that isn't the exclude window or null. */
WindowState getFirstWindow(WindowState exclude) {
for (int i = 0; i < windows.size(); i++) {
WindowState w = windows.get(i);
if (w != exclude) {
/** Return the first window in the token window list that isn't a starting window or null. */
WindowState getFirstNonStartingWindow() {
final int count = windows.size();
// We only care about parent windows so no need to loop through child windows.
for (int i = 0; i < count; i++) {
final WindowState w = windows.get(i);
if (w.mAttrs.type != TYPE_APPLICATION_STARTING) {
return w;
}
}
@@ -513,8 +477,9 @@ class WindowToken {
WindowState getReplacingWindow() {
for (int i = windows.size() - 1; i >= 0; i--) {
final WindowState win = windows.get(i);
if (win.mAnimatingExit && win.mWillReplaceWindow && win.mAnimateReplacingWindow) {
return win;
final WindowState replacing = win.getReplacingWindow();
if (replacing != null) {
return replacing;
}
}
return null;
@@ -665,7 +630,7 @@ class WindowToken {
boolean hasVisibleNotDrawnWallpaper() {
for (int j = windows.size() - 1; j >= 0; --j) {
final WindowState wallpaper = windows.get(j);
if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
if (wallpaper.hasVisibleNotDrawnWallpaper()) {
return true;
}
}
@@ -673,14 +638,15 @@ class WindowToken {
}
int getHighestAnimLayer() {
int layer = -1;
int highest = -1;
for (int j = 0; j < windows.size(); j++) {
final WindowState win = windows.get(j);
if (win.mWinAnimator.mAnimLayer > layer) {
layer = win.mWinAnimator.mAnimLayer;
final WindowState w = windows.get(j);
final int wLayer = w.getHighestAnimLayer();
if (wLayer > highest) {
highest = wLayer;
}
}
return layer;
return highest;
}
AppWindowToken asAppWindowToken() {