diff options
| author | 2015-12-22 16:29:16 +0100 | |
|---|---|---|
| committer | 2016-01-05 13:49:23 +0100 | |
| commit | 0429f3522bca5bb86378dd3f013f995484ddbed6 (patch) | |
| tree | 9687b4e71d961b0975873d031132b295bd0c2b79 | |
| parent | fe89d122e5b6b129b25d5d5316f690bd4ab93fbb (diff) | |
Freeze task bounds when relaunching
To make sure that task is only laid out with the size
that matches the current configuration, we have to "freeze"
the task bounds when we send a configuration change. Without this
change, it could happen that the app already laid out with the new
task bounds, but still had the old configuration, leading to
wrong layouts.
Bug: 26311778
Bug: 25015474
Change-Id: I8d3a3fdf3735f446a4affbbdb4986dafc97623a5
6 files changed, 83 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 0b22bd4edadc..80a75ce74312 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1868,6 +1868,9 @@ public final class ActivityStackSupervisor implements DisplayListener { mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds); } } + + // We might trigger a configuration change. Save the current task bounds for freezing. + mWindowManager.prepareFreezingTaskBounds(stack.mStackId); stack.mFullscreen = mWindowManager.resizeStack(stack.mStackId, bounds, mTmpConfigs, mTmpBounds, mTmpInsetBounds); stack.setBounds(bounds); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 9b9f14bee982..573aaec034cf 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -31,6 +31,7 @@ import com.android.server.wm.WindowManagerService.H; import android.annotation.NonNull; import android.content.pm.ActivityInfo; +import android.graphics.Rect; import android.os.Message; import android.os.RemoteException; import android.util.Slog; @@ -39,6 +40,7 @@ import android.view.View; import android.view.WindowManager; import java.io.PrintWriter; +import java.util.ArrayDeque; import java.util.ArrayList; class AppTokenList extends ArrayList<AppWindowToken> { @@ -126,6 +128,8 @@ class AppWindowToken extends WindowToken { boolean mAlwaysFocusable; + ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); + AppWindowToken(WindowManagerService _service, IApplicationToken _token, boolean _voiceInteraction) { super(_service, _token.asBinder(), @@ -437,6 +441,23 @@ class AppWindowToken extends WindowToken { } } + /** + * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds + * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even + * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen + * with a queue. + */ + void freezeBounds() { + mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds)); + } + + /** + * Unfreezes the previously frozen bounds. See {@link #freezeBounds}. + */ + void unfreezeBounds() { + mFrozenBounds.remove(); + } + @Override void dump(PrintWriter pw, String prefix) { super.dump(pw, prefix); @@ -483,6 +504,9 @@ class AppWindowToken extends WindowToken { pw.print(" startingDisplayed="); pw.print(startingDisplayed); pw.print(" startingMoved"); pw.println(startingMoved); } + if (!mFrozenBounds.isEmpty()) { + pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds); + } } @Override diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6e65ac19589c..223e03ad4cc4 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -61,6 +61,7 @@ class Task implements DimLayer.DimLayerUser { // Content limits relative to the DisplayContent this sits in. private Rect mBounds = new Rect(); + final Rect mPreparedFrozenBounds = new Rect(); // Bounds used to calculate the insets. private final Rect mTempInsetBounds = new Rect(); @@ -200,8 +201,7 @@ class Task implements DimLayer.DimLayerUser { boolean removeAppToken(AppWindowToken wtoken) { boolean removed = mAppTokens.remove(wtoken); if (mAppTokens.size() == 0) { - EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, - "removeAppToken: last token"); + EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token"); if (mDeferRemoval) { removeLocked(); } @@ -314,6 +314,14 @@ class Task implements DimLayer.DimLayerUser { return true; } + /** + * Prepares the task bounds to be frozen with the current size. See + * {@link AppWindowToken#freezeBounds}. + */ + void prepareFreezingBounds() { + mPreparedFrozenBounds.set(mBounds); + } + boolean scrollLocked(Rect bounds) { // shift the task bound if it doesn't fully cover the stack area mStack.getDimBounds(mTmpRect); @@ -601,5 +609,6 @@ class Task implements DimLayer.DimLayerUser { pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString()); pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval); pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens); + pw.print(prefix + prefix); pw.print("mTempInsetBounds="); pw.println(mTempInsetBounds); } } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index e481d116a69f..67debe6e3773 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -148,6 +148,13 @@ public class TaskStack implements DimLayer.DimLayerUser { return true; } + void prepareFreezingTaskBounds() { + for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) { + final Task task = mTasks.get(taskNdx); + task.prepareFreezingBounds(); + } + } + boolean isFullscreenBounds(Rect bounds) { if (mDisplayContent == null || bounds == null) { return true; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ccde6061d6d6..be753354a6f8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -203,7 +203,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE; @@ -4843,6 +4842,17 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void prepareFreezingTaskBounds(int stackId) { + synchronized (mWindowMap) { + final TaskStack stack = mStackIdToStack.get(stackId); + if (stack == null) { + throw new IllegalArgumentException("prepareFreezingTaskBounds: stackId " + stackId + + " not found."); + } + stack.prepareFreezingTaskBounds(); + } + } + public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds, Configuration config) { synchronized (mWindowMap) { @@ -9472,8 +9482,8 @@ public class WindowManagerService extends IWindowManager.Stub public void notifyAppRelaunching(IBinder token) { synchronized (mWindowMap) { AppWindowToken appWindow = findAppWindowToken(token); - if (appWindow != null) { - // TODO: Do something useful + if (canFreezeBounds(appWindow)) { + appWindow.freezeBounds(); } } } @@ -9481,12 +9491,20 @@ public class WindowManagerService extends IWindowManager.Stub public void notifyAppRelaunchingFinished(IBinder token) { synchronized (mWindowMap) { AppWindowToken appWindow = findAppWindowToken(token); - if (appWindow != null) { - // TODO: Do something useful + if (canFreezeBounds(appWindow)) { + appWindow.unfreezeBounds(); } } } + private boolean canFreezeBounds(AppWindowToken appWindow) { + + // For freeform windows, we can't freeze the bounds at the moment because this would make + // the resizing unresponsive. + return appWindow != null && appWindow.mTask != null + && !appWindow.mTask.inFreeformWorkspace(); + } + void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) { pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)"); mPolicy.dump(" ", pw, args); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 0eb1c6e7d9d9..e51080e7f230 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -624,6 +624,14 @@ final class WindowState implements WindowManagerPolicy.WindowState { } else { task.getBounds(mContainingFrame); task.getTempInsetBounds(mInsetFrame); + if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) { + + // If the bounds are frozen, we still want to translate the window freely and only + // freeze the size. + Rect frozen = mAppToken.mFrozenBounds.peek(); + mContainingFrame.right = mContainingFrame.left + frozen.width(); + mContainingFrame.bottom = mContainingFrame.top + frozen.height(); + } final WindowState imeWin = mService.mInputMethodWindow; if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this && mContainingFrame.bottom > cf.bottom) { @@ -2029,7 +2037,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (task.isDragResizing()) { return true; } - return mDisplayContent.mDividerControllerLocked.isResizing() && + + // If the bounds are currently frozen, it means that the layout size that the app sees + // and the bounds we clip this window to might be different. In order to avoid holes, we + // simulate that we are still resizing so the app fills the hole with the resizing + // background. + return (mDisplayContent.mDividerControllerLocked.isResizing() + || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) && !task.inFreeformWorkspace() && !task.isFullscreen(); } |