OSDN Git Service

Freeze task bounds when relaunching
authorJorim Jaggi <jjaggi@google.com>
Tue, 22 Dec 2015 15:29:16 +0000 (16:29 +0100)
committerJorim Jaggi <jjaggi@google.com>
Tue, 5 Jan 2016 12:49:23 +0000 (13:49 +0100)
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

services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/wm/AppWindowToken.java
services/core/java/com/android/server/wm/Task.java
services/core/java/com/android/server/wm/TaskStack.java
services/core/java/com/android/server/wm/WindowManagerService.java
services/core/java/com/android/server/wm/WindowState.java

index 0b22bd4..80a75ce 100644 (file)
@@ -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);
index 9b9f14b..573aaec 100644 (file)
@@ -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
index 6e65ac1..223e03a 100644 (file)
@@ -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);
     }
 }
index e481d11..67debe6 100644 (file)
@@ -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;
index ccde606..be75335 100644 (file)
@@ -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);
index 0eb1c6e..e51080e 100644 (file)
@@ -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();
     }