Merge "Replace SurfaceViews across resize trigerred relaunches."
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a7d3669..93122dd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4325,6 +4325,21 @@
r.activity.mChangingConfigurations = true;
+ // If we are preserving the main window across relaunches we would also like to preserve
+ // the children. However the client side view system does not support preserving
+ // the child views so we notify the window manager to expect these windows to
+ // 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.
+ try {
+ if (r.mPreserveWindow) {
+ WindowManagerGlobal.getWindowSession().prepareToReplaceChildren(r.token);
+ }
+ } catch (RemoteException e) {
+ // If the system process has died, it's game over for everyone.
+ }
+
+
// Need to ensure state is saved.
if (!r.paused) {
performPauseActivity(r.token, false, r.isPreHoneycomb());
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index bea36c0..1a5de7e 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -123,6 +123,14 @@
void repositionChild(IWindow childWindow, int left, int top, int right, int bottom,
long deferTransactionUntilFrame, out Rect outFrame);
+ /*
+ * Notify the window manager that an application is relaunching and
+ * child windows should be prepared for replacement.
+ *
+ * @param appToken The application
+ */
+ void prepareToReplaceChildren(IBinder appToken);
+
/**
* If a call to relayout() asked to have the surface destroy deferred,
* it must call this once it is okay to destroy that surface.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 46240783..785f166 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -405,6 +405,17 @@
}
}
+ void setReplacingChildren() {
+ if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
+ + " with replacing child windows.");
+ for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+ final WindowState w = allAppWindows.get(i);
+ if (w.isChildWindow()) {
+ w.setReplacing(false /* animate */);
+ }
+ }
+ }
+
void resetReplacingWindows() {
if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
+ " of replacing window marks.");
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index ac38424..8aaf430 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -200,6 +200,11 @@
deferTransactionUntilFrame, outFrame);
}
+ @Override
+ public void prepareToReplaceChildren(IBinder appToken) {
+ mService.setReplacingChildren(appToken);
+ }
+
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d05a61a..4b0015e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2693,7 +2693,14 @@
final boolean notExitingOrAnimating =
!win.mExiting && !win.isAnimatingWithSavedSurface();
result |= notExitingOrAnimating ? RELAYOUT_RES_SURFACE_CHANGED : 0;
- if (notExitingOrAnimating) {
+ // We don't want to animate visibility of windows which are pending
+ // replacement. In the case of activity relaunch child windows
+ // could request visibility changes as they are detached from the main
+ // application window during the tear down process. If we satisfied
+ // these visibility changes though, we would cause a visual glitch
+ // hiding the window before it's replacement was available.
+ // So we just do nothing on our side.
+ if (notExitingOrAnimating && win.mWillReplaceWindow == false) {
focusMayChange = tryStartingAnimation(win, winAnimator, isDefaultDisplay,
focusMayChange);
@@ -2893,9 +2900,10 @@
try {
synchronized (mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
- if (win == null) {
+ if (win == null || win.mWillReplaceWindow) {
return;
}
+
win.mWinAnimator.destroyDeferredSurfaceLocked();
}
} finally {
@@ -10184,6 +10192,27 @@
}
/**
+ * Hint to a token that its children will be replaced across activity relaunch.
+ * The children would otherwise be removed shortly following this as the
+ * activity is torn down.
+ * @param token Application token for which the activity will be relaunched.
+ */
+ public void setReplacingChildren(IBinder token) {
+ AppWindowToken appWindowToken = null;
+ synchronized (mWindowMap) {
+ 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.setReplacingChildren();
+ scheduleClearReplacingWindowIfNeeded(token, true /* replacing */);
+ }
+ }
+
+ /**
* If we're replacing the window, schedule a timer to clear the replaced window
* after a timeout, in case the replacing window is not coming.
*
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 aae5ac4..769285f 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
@@ -231,4 +231,9 @@
public void pokeDrawLock(IBinder window) {
// pass for now.
}
+
+ @Override
+ public void prepareToReplaceChildren(IBinder appToken) {
+ // pass for now.
+ }
}