Merge "Replace SurfaceViews across resize trigerred relaunches."

This commit is contained in:
Rob Carr
2016-01-19 22:59:10 +00:00
committed by Android (Google) Code Review
6 changed files with 75 additions and 2 deletions

View File

@@ -4325,6 +4325,21 @@ public final class ActivityThread {
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());

View File

@@ -123,6 +123,14 @@ interface IWindowSession {
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.

View File

@@ -405,6 +405,17 @@ class AppWindowToken extends WindowToken {
}
}
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.");

View File

@@ -200,6 +200,11 @@ final class Session extends IWindowSession.Stub
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,

View File

@@ -2693,7 +2693,14 @@ public class WindowManagerService extends IWindowManager.Stub
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 @@ public class WindowManagerService extends IWindowManager.Stub
try {
synchronized (mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
if (win == null || win.mWillReplaceWindow) {
return;
}
win.mWinAnimator.destroyDeferredSurfaceLocked();
}
} finally {
@@ -10183,6 +10191,27 @@ 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
* 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.

View File

@@ -231,4 +231,9 @@ public final class BridgeWindowSession implements IWindowSession {
public void pokeDrawLock(IBinder window) {
// pass for now.
}
@Override
public void prepareToReplaceChildren(IBinder appToken) {
// pass for now.
}
}