summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Filip Gruszczynski <gruszczy@google.com> 2016-01-25 16:28:49 -0800
committer Filip Gruszczynski <gruszczy@google.com> 2016-01-28 08:47:54 -0800
commit84fa3351a21b37d02fafd634a8de65cf6cd04c4d (patch)
tree16cffa00cd4166998dbed47ac66a8a65d0b3b93f
parente97bce53df66ae4d3084d8f530f20a95ceac044a (diff)
Animate pinned stack resizing.
This introduces animating of stack bounds within window manager module. It also uses this type of animation when moving an activity from fullscreen stack to pinned stack. Bug: 25672053 Change-Id: I75914a685d10021f8a7535b47ef12b6920b3fd5e
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java30
-rw-r--r--core/java/android/app/ActivityManager.java11
-rw-r--r--core/java/android/app/ActivityManagerNative.java11
-rw-r--r--core/java/android/app/IActivityManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java3
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java18
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java11
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java2
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java142
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java32
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java41
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java16
12 files changed, 285 insertions, 36 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 72e8c3b61027..d45bc5dc8789 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -47,7 +47,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -79,7 +78,6 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.List;
public class Am extends BaseCommand {
@@ -159,6 +157,7 @@ public class Am extends BaseCommand {
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
" am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
" am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
@@ -1688,6 +1687,9 @@ public class Am extends BaseCommand {
case "resize":
runStackResize();
break;
+ case "resize-animated":
+ runStackResizeAnimated();
+ break;
case "resize-docked-stack":
runStackResizeDocked();
break;
@@ -1756,7 +1758,18 @@ public class Am extends BaseCommand {
System.err.println("Error: invalid input bounds");
return;
}
- resizeStack(stackId, bounds, 0);
+ resizeStack(stackId, bounds, 0, false);
+ }
+
+ private void runStackResizeAnimated() throws Exception {
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ final Rect bounds = getBounds();
+ if (bounds == null) {
+ System.err.println("Error: invalid input bounds");
+ return;
+ }
+ resizeStack(stackId, bounds, 0, true);
}
private void runStackResizeDocked() throws Exception {
@@ -1773,14 +1786,15 @@ public class Am extends BaseCommand {
}
}
- private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
+ private void resizeStack(int stackId, Rect bounds, int delayMs, boolean animate)
+ throws Exception {
if (bounds == null) {
showError("Error: invalid input bounds");
return;
}
try {
- mAm.resizeStack(stackId, bounds, false);
+ mAm.resizeStack(stackId, bounds, false, false, animate);
Thread.sleep(delayMs);
} catch (RemoteException e) {
showError("Error: resizing stack " + e);
@@ -1894,7 +1908,7 @@ public class Am extends BaseCommand {
maxChange = Math.min(stepSize, currentPoint - minPoint);
currentPoint -= maxChange;
setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
}
System.out.println("Growing docked stack side=" + side);
@@ -1902,7 +1916,7 @@ public class Am extends BaseCommand {
maxChange = Math.min(stepSize, maxPoint - currentPoint);
currentPoint += maxChange;
setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
}
System.out.println("Back to Original size side=" + side);
@@ -1910,7 +1924,7 @@ public class Am extends BaseCommand {
maxChange = Math.min(stepSize, currentPoint - startPoint);
currentPoint -= maxChange;
setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ resizeStack(DOCKED_STACK_ID, bounds, delayMs, false);
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 420bf31a189d..90feab4327b7 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -564,8 +564,7 @@ public class ActivityManager {
* there isn't a display gap.
*/
public static boolean preserveWindowOnTaskMove(int stackId) {
- return stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID;
+ return stackId == FULLSCREEN_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
}
/**
@@ -616,6 +615,14 @@ public class ActivityManager {
public static boolean keepVisibleDeadAppWindowOnScreen(int stackId) {
return stackId != PINNED_STACK_ID;
}
+
+ /**
+ * Returns true if the backdrop on the client side should match the frame of the window.
+ * Returns false, if the backdrop should be fullscreen.
+ */
+ public static boolean useWindowFrameForBackdrop(int stackId) {
+ return stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == PINNED_STACK_ID;
+ }
}
/**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 42ff8e83862d..cd5797ecb286 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -816,7 +816,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
r = Rect.CREATOR.createFromParcel(data);
}
final boolean allowResizeInDockedMode = data.readInt() == 1;
- resizeStack(stackId, r, allowResizeInDockedMode);
+ final boolean preserveWindows = data.readInt() == 1;
+ final boolean animate = data.readInt() == 1;
+ resizeStack(stackId, r, allowResizeInDockedMode, preserveWindows, animate);
reply.writeNoException();
return true;
}
@@ -3815,9 +3817,8 @@ class ActivityManagerProxy implements IActivityManager
return res;
}
@Override
- public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
- throws RemoteException
- {
+ public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode,
+ boolean preserveWindows, boolean animate) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3829,6 +3830,8 @@ class ActivityManagerProxy implements IActivityManager
data.writeInt(0);
}
data.writeInt(allowResizeInDockedMode ? 1 : 0);
+ data.writeInt(preserveWindows ? 1 : 0);
+ data.writeInt(animate ? 1 : 0);
mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 22de2ff7bc6e..5b3ffe05451a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -146,8 +146,8 @@ public interface IActivityManager extends IInterface {
public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) throws RemoteException;
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode)
- throws RemoteException;
+ public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+ boolean preserveWindows, boolean animate) throws RemoteException;
/**
* Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 67bb58ae8fc9..24ab5063d94e 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -97,7 +97,8 @@ public class WindowManagerProxy {
@Override
public void run() {
try {
- ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true);
+ ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false,
+ false);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2c55ee26cf8f..76fbebfd14b5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9411,14 +9411,24 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
+ public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+ boolean preserveWindows, boolean animate) {
enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
- mStackSupervisor.resizeStackLocked(
- stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- !PRESERVE_WINDOWS, allowResizeInDockedMode);
+ if (animate) {
+ if (stackId == PINNED_STACK_ID) {
+ mWindowManager.animateResizePinnedStack(bounds);
+ } else {
+ throw new IllegalArgumentException("Stack: " + stackId
+ + " doesn't support animated resize.");
+ }
+ } else {
+ mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, preserveWindows,
+ allowResizeInDockedMode);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8db2f8ff50f3..11dd8a38cdbf 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -98,6 +98,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import static android.Manifest.permission.START_ANY_ACTIVITY;
@@ -2019,7 +2020,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// If this is a forced resize, let it go through even if the bounds is not changing,
// as we might need a relayout due to surface size change (to/from fullscreen).
final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
- if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
+ if (Objects.equals(task.mBounds, bounds) && !forced) {
// Nothing to do here...
return true;
}
@@ -2257,10 +2258,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
// If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
// window), we need to clear the replace window settings. Otherwise, we schedule a
// timeout to remove the old window if the replacing window is not coming in time.
- // In case of the pinned stack we don't resize the task during the move, but we will
- // resize the stack soon after so we want to retain the replacing window.
- mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken,
- !kept || stackId == PINNED_STACK_ID);
+ mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
}
// The task might have already been running and its visibility needs to be synchronized with
@@ -2294,7 +2292,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
return false;
}
- moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", bounds);
+ moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", null);
+ mWindowManager.animateResizePinnedStack(bounds);
return true;
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 552af03173a7..43a17c98fcc4 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -134,7 +134,7 @@ public class AppTransition implements Dump {
/** Fraction of animation at which the recents thumbnail becomes completely transparent */
private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.5f;
- private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+ static final int DEFAULT_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
new file mode 100644
index 000000000000..5f974785b667
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.animation.LinearInterpolator;
+
+/**
+ * Enables animating bounds of objects.
+ *
+ * In multi-window world bounds of both stack and tasks can change. When we need these bounds to
+ * change smoothly and not require the app to relaunch (e.g. because it handles resizes and
+ * relaunching it would cause poorer experience), these class provides a way to directly animate
+ * the bounds of the resized object.
+ *
+ * The object that is resized needs to implement {@link AnimateBoundsUser} interface.
+ */
+public class BoundsAnimationController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BoundsAnimationController" : TAG_WM;
+
+ // Only acccessed on UI thread.
+ private ArrayMap<AnimateBoundsUser, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
+
+ private final class BoundsAnimator extends ValueAnimator
+ implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+ private final AnimateBoundsUser mTarget;
+ private final Rect mFrom;
+ private final Rect mTo;
+ private final Rect mTmpRect;
+
+ BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to) {
+ super();
+ mTarget = target;
+ mFrom = from;
+ mTo = to;
+ mTmpRect = new Rect();
+ addUpdateListener(this);
+ addListener(this);
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float value = (Float) animation.getAnimatedValue();
+ final float remains = 1 - value;
+ mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value);
+ mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value);
+ mTmpRect.right = (int) (mFrom.right * remains + mTo.right * value);
+ mTmpRect.bottom = (int) (mFrom.bottom * remains + mTo.bottom * value);
+ if (DEBUG_ANIM) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + ", mBounds="
+ + mTmpRect + ", from=" + mFrom + ", mTo=" + mTo + ", value=" + value
+ + ", remains=" + remains);
+ if (!mTarget.setSize(mTmpRect)) {
+ // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
+ // any further animation.
+ animation.cancel();
+ }
+ }
+
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finishAnimation();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ finishAnimation();
+ }
+
+ private void finishAnimation() {
+ mTarget.finishBoundsAnimation();
+ removeListener(this);
+ removeUpdateListener(this);
+ mRunningAnimations.remove(mTarget);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ }
+
+ public interface AnimateBoundsUser {
+ /**
+ * Asks the target to directly (without any intermediate steps, like scheduling animation)
+ * resize its bounds.
+ *
+ * @return Whether the target still wants to be animated and successfully finished the
+ * operation. If it returns false, the animation will immediately be cancelled. The target
+ * should return false when something abnormal happened, e.g. it was completely removed
+ * from the hierarchy and is not valid anymore.
+ */
+ boolean setSize(Rect bounds);
+
+ /**
+ * Callback for the target to inform it that the animation is finished, so it can do some
+ * necessary cleanup.
+ */
+ void finishBoundsAnimation();
+ }
+
+ void animateBounds(AnimateBoundsUser target, Rect from, Rect to) {
+ final BoundsAnimator existing = mRunningAnimations.get(target);
+ if (existing != null) {
+ existing.cancel();
+ }
+ BoundsAnimator animator = new BoundsAnimator(target, from, to);
+ mRunningAnimations.put(target, animator);
+ animator.setFloatValues(0f, 1f);
+ animator.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+ animator.setInterpolator(new LinearInterpolator());
+ animator.start();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index f02e49e21977..e0880ad3ae92 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -20,6 +20,7 @@ import android.app.ActivityManager.StackId;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.RemoteException;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -47,7 +48,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT
import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-public class TaskStack implements DimLayer.DimLayerUser {
+public class TaskStack implements DimLayer.DimLayerUser,
+ BoundsAnimationController.AnimateBoundsUser {
// If the stack should be resized to fullscreen.
private static final boolean FULLSCREEN = true;
@@ -804,4 +806,32 @@ public class TaskStack implements DimLayer.DimLayerUser {
}
return false;
}
+
+ @Override // AnimatesBounds
+ public boolean setSize(Rect bounds) {
+ synchronized (mService.mWindowMap) {
+ if (mDisplayContent == null) {
+ return false;
+ }
+ }
+ try {
+ mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
+ } catch (RemoteException e) {
+ }
+ return true;
+ }
+
+ @Override // AnimatesBounds
+ public void finishBoundsAnimation() {
+ synchronized (mService.mWindowMap) {
+ if (mTasks.isEmpty()) {
+ return;
+ }
+ final Task task = mTasks.get(mTasks.size() - 1);
+ if (task != null) {
+ task.setDragResizing(false);
+ mService.requestTraversal();
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 93a10156414a..2b88af414b4a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -157,6 +157,7 @@ import java.util.List;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -643,6 +644,9 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowAnimator mAnimator;
+ private final BoundsAnimationController mBoundsAnimationController =
+ new BoundsAnimationController();
+
SparseArray<Task> mTaskIdToTask = new SparseArray<>();
/** All of the TaskStacks in the window manager, unordered. For an ordered list call
@@ -2848,11 +2852,12 @@ public class WindowManagerService extends IWindowManager.Stub
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
win.prepareWindowToDisplayDuringRelayout(outConfig);
}
- if ((attrChanges& LayoutParams.FORMAT_CHANGED) != 0) {
- // If the format can be changed in place yaay!
- // If not, fall back to a surface re-build
+ if ((attrChanges & LayoutParams.FORMAT_CHANGED) != 0) {
+ // If the format can't be changed in place, preserve the old surface until the app draws
+ // on the new one. This prevents blinking when we change elevation of freeform and
+ // pinned windows.
if (!winAnimator.tryChangeFormatInPlaceLocked()) {
- winAnimator.destroySurfaceLocked();
+ winAnimator.preserveSurfaceLocked();
result |= RELAYOUT_RES_SURFACE_CHANGED
| WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
}
@@ -8085,7 +8090,8 @@ public class WindowManagerService extends IWindowManager.Stub
break;
case RESIZE_STACK: {
try {
- mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1);
+ mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false,
+ false);
} catch (RemoteException e) {
// This will not happen since we are in the same process.
}
@@ -10273,6 +10279,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ public void animateResizePinnedStack(final Rect bounds) {
+ synchronized (mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
+ if (stack == null) {
+ Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found.");
+ return;
+ }
+ final ArrayList<Task> tasks = stack.getTasks();
+ if (tasks.isEmpty()) {
+ Slog.w(TAG, "animateResizePinnedStack: pinned stack doesn't have any tasks.");
+ return;
+ }
+ final Task task = tasks.get(tasks.size() - 1);
+ task.setDragResizing(true);
+ final Rect originalBounds = new Rect();
+ stack.getBounds(originalBounds);
+ UiThread.getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ mBoundsAnimationController.animateBounds(stack, originalBounds, bounds);
+ }
+ });
+ }
+ }
+
public void setTaskResizeable(int taskId, boolean resizeable) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c541b3f6f56b..1214948911e1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -57,6 +57,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -2051,10 +2052,21 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// until the window to small size, otherwise the multithread renderer will shift last
// one or more frame to wrong offset. So here we send fullscreen backdrop if either
// isDragResizing() or isDragResizeChanged() is true.
+ boolean resizing = isDragResizing() || isDragResizeChanged();
+ if (StackId.useWindowFrameForBackdrop(getStackId()) || !resizing) {
+ return frame;
+ }
DisplayInfo displayInfo = getDisplayInfo();
mTmpRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
- boolean resizing = isDragResizing() || isDragResizeChanged();
- return (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
+ return mTmpRect;
+ }
+
+ private int getStackId() {
+ final TaskStack stack = getStack();
+ if (stack == null) {
+ return INVALID_STACK_ID;
+ }
+ return stack.mStackId;
}
private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,