diff options
7 files changed, 88 insertions, 81 deletions
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c1bff3692938..1116fc3900d7 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2287,7 +2287,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mResizingTasksDuringAnimation.clear(); } - void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) { + private class MoveTaskToFullscreenArgs { + public int fromStackId; + public boolean onTop; + }; + // Used only to closure over the arguments to moveTasksToFullscreenStack without + // allocation + private MoveTaskToFullscreenArgs mMoveToFullscreenArgs = new MoveTaskToFullscreenArgs(); + + private void moveTasksToFullscreenStackInnerLocked() { + int fromStackId = mMoveToFullscreenArgs.fromStackId; + boolean onTop = mMoveToFullscreenArgs.onTop; + final ActivityStack stack = getStack(fromStackId); if (stack == null) { return; @@ -2359,6 +2370,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } + void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) { + mMoveToFullscreenArgs.fromStackId = fromStackId; + mMoveToFullscreenArgs.onTop = onTop; + + mWindowManager.inSurfaceTransaction(this::moveTasksToFullscreenStackInnerLocked); + } + void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds, Rect tempDockedTaskInsetBounds, Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) { @@ -2471,12 +2489,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return activityContainer.mStack; } - /** - * Removes the stack associated with the given {@param stackId}. If the {@param stackId} is the - * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but - * instead moved back onto the fullscreen stack. - */ - void removeStackLocked(int stackId) { + + // Used only to closure over the argument to removeStack without allocation. + private int mRemoveStackStackId; + void removeStackInnerLocked() { + int stackId = mRemoveStackStackId; + final ActivityStack stack = getStack(stackId); if (stack == null) { return; @@ -2515,6 +2533,16 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** + * Removes the stack associated with the given {@param stackId}. If the {@param stackId} is the + * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but + * instead moved back onto the fullscreen stack. + */ + void removeStackLocked(int stackId) { + mRemoveStackStackId = stackId; + mWindowManager.inSurfaceTransaction(this::removeStackInnerLocked); + } + + /** * Removes the task with the specified task id. * * @param taskId Identifier of the task to be removed. diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java index e3941b9a2b18..16edd35137fb 100644 --- a/services/core/java/com/android/server/wm/AppWindowAnimator.java +++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java @@ -161,11 +161,6 @@ public class AppWindowAnimator { } else { mClearProlongedAnimation = true; } - - // Since we are finally starting our animation, we don't need the logic anymore to prevent - // the app from showing again if we just moved between stacks. - // See {@link WindowState#notifyMovedInStack}. - mAppToken.resetJustMovedInStack(); } public void setDummyAnimation() { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index c20ee973bac5..a474316a7b3b 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -55,6 +55,7 @@ import android.os.IBinder; import android.os.SystemClock; import android.util.Slog; import android.view.IApplicationToken; +import android.view.SurfaceControl; import android.view.WindowManager; import android.view.WindowManagerPolicy.StartingSurface; @@ -365,6 +366,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mEnteringAnimation = true; mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token); } + if (hidden && !delayed) { + SurfaceControl.openTransaction(); + for (int i = mChildren.size() - 1; i >= 0; i--) { + mChildren.get(i).mWinAnimator.hide("immediately hidden"); + } + SurfaceControl.closeTransaction(); + } if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) { // The token is not closing nor opening, so even if there is an animation set, that @@ -967,19 +975,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mService.mWindowPlacerLocked.performSurfacePlacement(); } - void resetJustMovedInStack() { - for (int i = mChildren.size() - 1; i >= 0; i--) { - (mChildren.get(i)).resetJustMovedInStack(); - } - } - - void notifyMovedInStack() { - for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) { - final WindowState win = mChildren.get(winNdx); - win.notifyMovedInStack(); - } - } - void setAppLayoutChanges(int changes, String reason) { if (!mChildren.isEmpty()) { final DisplayContent dc = getDisplayContent(); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 99c085ffe19f..9e4d60ac2f97 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -208,10 +208,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU void positionAt(int position, Rect bounds, Configuration overrideConfig) { mStack.positionChildAt(position, this, false /* includingParents */); resizeLocked(bounds, overrideConfig, false /* force */); - - for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) { - mChildren.get(activityNdx).notifyMovedInStack(); - } } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 5844b0b6f583..3fc7d8312417 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7306,4 +7306,49 @@ public class WindowManagerService extends IWindowManager.Stub mAppFreezeListeners.remove(listener); } + /** + * WARNING: This interrupts surface updates, be careful! Don't + * execute within the transaction for longer than you would + * execute on an animation thread. + * WARNING: This holds the WindowManager lock, so if exec will acquire + * the ActivityManager lock, you should hold it BEFORE calling this + * otherwise there is a risk of deadlock if another thread holding the AM + * lock waits on the WM lock. + * WARNING: This method contains locks known to the State of California + * to cause Deadlocks and other conditions. + * + * + * Begins a surface transaction with which the AM can batch operations. + * All Surface updates performed by the WindowManager following this + * will not appear on screen until after the call to + * closeSurfaceTransaction. + * + * ActivityManager can use this to ensure multiple 'commands' will all + * be reflected in a single frame. For example when reparenting a window + * which was previously hidden due to it's parent properties, we may + * need to ensure it is hidden in the same frame that the properties + * from the new parent are inherited, otherwise it could be revealed + * mistakenly. + * + * + * TODO(b/36393204): We can investigate totally replacing #deferSurfaceLayout + * with something like this but it seems that some existing cases of + * deferSurfaceLayout may be a little too broad, in particular the total + * enclosure of startActivityUnchecked which could run for quite some time. + */ + public void inSurfaceTransaction(Runnable exec) { + // We hold the WindowManger lock to ensure relayoutWindow + // does not return while a Surface transaction is opening. + // The client depends on us to have resized the surface + // by that point (b/36462635) + + synchronized (mWindowMap) { + SurfaceControl.openTransaction(); + try { + exec.run(); + } finally { + SurfaceControl.closeTransaction(); + } + } + } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ca5d551e8e0d..d4c8b1f850ad 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -517,11 +517,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final private Rect mTmpRect = new Rect(); /** - * See {@link #notifyMovedInStack}. - */ - private boolean mJustMovedInStack; - - /** * Whether the window was resized by us while it was gone for layout. */ boolean mResizedWhileGone = false; @@ -1998,49 +1993,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - /** - * Notifies this window that the corresponding task has just moved in the stack. - * <p> - * This is used to fix the following: If we moved in the stack, and if the last clip rect was - * empty, meaning that our task was completely offscreen, we need to keep it invisible because - * the actual app transition that updates the visibility is delayed by a few transactions. - * Instead of messing around with the ordering and timing how transitions and transactions are - * executed, we introduce this little hack which prevents this window of getting visible again - * with the wrong bounds until the app transitions has started. - * <p> - * This method notifies the window about that we just moved in the stack so we can apply this - * logic in {@link WindowStateAnimator#updateSurfaceWindowCrop} - */ - void notifyMovedInStack() { - mJustMovedInStack = true; - - for (int i = mChildren.size() - 1; i >= 0; --i) { - final WindowState c = mChildren.get(i); - c.notifyMovedInStack(); - } - } - - /** - * See {@link #notifyMovedInStack}. - * - * @return Whether we just got moved in the corresponding stack. - */ - boolean hasJustMovedInStack() { - return mJustMovedInStack; - } - - /** - * Resets that we just moved in the corresponding stack. See {@link #notifyMovedInStack}. - */ - void resetJustMovedInStack() { - mJustMovedInStack = false; - - for (int i = mChildren.size() - 1; i >= 0; i--) { - final WindowState c = mChildren.get(i); - c.resetJustMovedInStack(); - } - } - private final class DeadWindowEventReceiver extends InputEventReceiver { DeadWindowEventReceiver(InputChannel inputChannel) { super(inputChannel, mService.mH.getLooper()); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 4b7133836db8..48de7e401925 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1177,10 +1177,6 @@ class WindowStateAnimator { w.transformClipRectFromScreenToSurfaceSpace(clipRect); - // See {@link WindowState#notifyMovedInStack} for why this is necessary. - if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) { - clipRect.setEmpty(); - } return true; } |