From 77bdfb512f963701082c5c78e9a9db00b167fcb6 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 2 May 2016 18:18:31 -0700 Subject: [PATCH] Prepare to replace windows across recreate(). When the activity locally recreates itself, nothing on the server side is able to prepare preserving windows, or replacing windows. The activity was trying to defer removing the old window, but it was just waiting until the new one was created, not until it was drawn, thus resulting in a flicker. It's easy to backpack on the existing replacement infrastructure. Bug: 28221875 Change-Id: I55fc4ca78e9e11809473fedd8b30b6a6350cf852 --- core/java/android/app/ActivityThread.java | 13 +++++++++---- core/java/android/view/IWindowSession.aidl | 6 ++++-- .../java/com/android/server/wm/Session.java | 4 ++-- .../android/server/wm/WindowManagerService.java | 17 +++++++++++++---- .../bridge/android/BridgeWindowSession.java | 2 +- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6d805eda2b384..8e58c380e7e08 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4208,7 +4208,7 @@ public final class ActivityThread { } IBinder wtoken = v.getWindowToken(); if (r.activity.mWindowAdded) { - if (r.onlyLocalRequest || r.mPreserveWindow) { + if (r.mPreserveWindow) { // Hold off on removing this until the new activity's // window is being added. r.mPendingRemoveWindow = r.window; @@ -4443,15 +4443,20 @@ public final class ActivityThread { // be replaced and defer requests to destroy or hide them. This way we can achieve // visual continuity. It's important that we do this here prior to pause and destroy // as that is when we may hide or remove the child views. + // + // There is another scenario, if we have decided locally to relaunch the app from a + // call to recreate, then none of the windows will be prepared for replacement or + // preserved by the server, so we want to notify it that we are preparing to replace + // everything try { - if (r.mPreserveWindow) { - WindowManagerGlobal.getWindowSession().prepareToReplaceChildren(r.token); + if (r.mPreserveWindow || r.onlyLocalRequest) { + WindowManagerGlobal.getWindowSession().prepareToReplaceWindows( + r.token, !r.onlyLocalRequest); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - // Need to ensure state is saved. if (!r.paused) { performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity"); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 8e1609c587a3e..1facc106d6451 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -125,11 +125,13 @@ interface IWindowSession { /* * Notify the window manager that an application is relaunching and - * child windows should be prepared for replacement. + * windows should be prepared for replacement. * * @param appToken The application + * @param childrenOnly Whether to only prepare child windows for replacement + * (for example when main windows are being reused via preservation). */ - void prepareToReplaceChildren(IBinder appToken); + void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly); /** * If a call to relayout() asked to have the surface destroy deferred, diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index daeb860e2ef53..08c0a4b013579 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -201,8 +201,8 @@ final class Session extends IWindowSession.Stub } @Override - public void prepareToReplaceChildren(IBinder appToken) { - mService.setReplacingChildren(appToken); + public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) { + mService.setReplacingWindows(appToken, childrenOnly); } public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 57f551cff098f..a5d9bb2e1df80 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -10677,12 +10677,16 @@ public class WindowManagerService extends IWindowManager.Stub } /** - * Hint to a token that its children will be replaced across activity relaunch. - * The children would otherwise be removed shortly following this as the + * Hint to a token that its windows will be replaced across activity relaunch. + * The windows would otherwise be removed shortly following this as the * activity is torn down. * @param token Application token for which the activity will be relaunched. + * @param childrenOnly Whether to mark only child windows for replacement + * (for the case where main windows are being preserved/ + * reused rather than replaced). + * */ - public void setReplacingChildren(IBinder token) { + public void setReplacingWindows(IBinder token, boolean childrenOnly) { AppWindowToken appWindowToken = null; synchronized (mWindowMap) { appWindowToken = findAppWindowToken(token); @@ -10692,7 +10696,12 @@ public class WindowManagerService extends IWindowManager.Stub return; } - appWindowToken.setReplacingChildren(); + if (childrenOnly) { + appWindowToken.setReplacingChildren(); + } else { + appWindowToken.setReplacingWindows(false /* animate */); + } + scheduleClearReplacingWindowIfNeeded(token, true /* replacing */); } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java index 5a6a00fc3985d..7582fda6a0fbf 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java @@ -233,7 +233,7 @@ public final class BridgeWindowSession implements IWindowSession { } @Override - public void prepareToReplaceChildren(IBinder appToken) { + public void prepareToReplaceWindows(IBinder appToken, boolean childrenOnly) { // pass for now. }