Merge changes Ib5ad3250,Iff58afdb into sc-v2-dev

* changes:
  Flag whether a RemoteAnimationTarget has parent in animation
  Use TaskFragment bounds instead of TaskBounds for Activity animation
This commit is contained in:
Chris Li
2021-09-21 05:18:46 +00:00
committed by Android (Google) Code Review
7 changed files with 62 additions and 96 deletions

View File

@@ -208,6 +208,15 @@ public class RemoteAnimationTarget implements Parcelable {
*/ */
public final @WindowManager.LayoutParams.WindowType int windowType; public final @WindowManager.LayoutParams.WindowType int windowType;
/**
* {@code true} if its parent is also a {@link RemoteAnimationTarget} in the same transition.
*
* For example, when a TaskFragment is resizing while one of its children is open/close, both
* windows will be animation targets. This value will be {@code true} for the child, so that
* the handler can choose to handle it differently.
*/
public boolean hasAnimatingParent;
public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent, public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position, Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
Rect localBounds, Rect screenSpaceBounds, Rect localBounds, Rect screenSpaceBounds,
@@ -265,6 +274,7 @@ public class RemoteAnimationTarget implements Parcelable {
taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR); taskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
allowEnterPip = in.readBoolean(); allowEnterPip = in.readBoolean();
windowType = in.readInt(); windowType = in.readInt();
hasAnimatingParent = in.readBoolean();
} }
@Override @Override
@@ -292,6 +302,7 @@ public class RemoteAnimationTarget implements Parcelable {
dest.writeTypedObject(taskInfo, 0 /* flags */); dest.writeTypedObject(taskInfo, 0 /* flags */);
dest.writeBoolean(allowEnterPip); dest.writeBoolean(allowEnterPip);
dest.writeInt(windowType); dest.writeInt(windowType);
dest.writeBoolean(hasAnimatingParent);
} }
public void dump(PrintWriter pw, String prefix) { public void dump(PrintWriter pw, String prefix) {
@@ -311,6 +322,7 @@ public class RemoteAnimationTarget implements Parcelable {
pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo); pw.print(prefix); pw.print("taskInfo="); pw.println(taskInfo);
pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip); pw.print(prefix); pw.print("allowEnterPip="); pw.println(allowEnterPip);
pw.print(prefix); pw.print("windowType="); pw.print(windowType); pw.print(prefix); pw.print("windowType="); pw.print(windowType);
pw.print(prefix); pw.print("hasAnimatingParent="); pw.print(hasAnimatingParent);
} }
public void dumpDebug(ProtoOutputStream proto, long fieldId) { public void dumpDebug(ProtoOutputStream proto, long fieldId) {

View File

@@ -223,7 +223,6 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY; import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -8041,13 +8040,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@VisibleForTesting @VisibleForTesting
@Override @Override
Rect getAnimationBounds(int appRootTaskClipMode) { Rect getAnimationBounds(int appRootTaskClipMode) {
if (appRootTaskClipMode == ROOT_TASK_CLIP_BEFORE_ANIM && getRootTask() != null) { // Use TaskFragment-bounds if available so that activity-level letterbox (maxAspectRatio) is
// Using the root task bounds here effectively applies the clipping before animation.
return getRootTask().getBounds();
}
// Use task-bounds if available so that activity-level letterbox (maxAspectRatio) is
// included in the animation. // included in the animation.
return task != null ? task.getBounds() : getBounds(); final TaskFragment taskFragment = getTaskFragment();
return taskFragment != null ? taskFragment.getBounds() : getBounds();
} }
@Override @Override
@@ -9269,14 +9265,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect(); task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, getLetterboxInsets()); InsetUtils.addInsets(insets, getLetterboxInsets());
return new RemoteAnimationTarget(task.mTaskId, record.getMode(), final RemoteAnimationTarget target = new RemoteAnimationTarget(task.mTaskId,
record.mAdapter.mCapturedLeash, !fillsParent(), record.getMode(), record.mAdapter.mCapturedLeash, !fillsParent(),
new Rect(), insets, new Rect(), insets,
getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds, getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(), record.mAdapter.mRootTaskBounds, task.getWindowConfiguration(),
false /*isNotInRecents*/, false /*isNotInRecents*/,
record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null, record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState()); record.mStartBounds, task.getTaskInfo(), checkEnterPictureInPictureAppOpsState());
target.hasAnimatingParent = record.hasAnimatingParent();
return target;
} }
@Override @Override

View File

@@ -436,6 +436,19 @@ class RemoteAnimationController implements DeathRecipient {
int getMode() { int getMode() {
return mMode; return mMode;
} }
/** Whether its parent is also an animation target in the same transition. */
boolean hasAnimatingParent() {
// mOpeningApps and mClosingApps are only activities, so only need to check
// mChangingContainers.
for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) {
if (mWindowContainer.isDescendantOf(
mDisplayContent.mChangingContainers.valueAt(i))) {
return true;
}
}
return false;
}
} }
class RemoteAnimationAdapterWrapper implements AnimationAdapter { class RemoteAnimationAdapterWrapper implements AnimationAdapter {

View File

@@ -130,7 +130,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.dipToPixel; import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
import static java.lang.Integer.MAX_VALUE; import static java.lang.Integer.MAX_VALUE;
@@ -2984,16 +2983,6 @@ class Task extends TaskFragment {
super.resetSurfacePositionForAnimationLeash(t); super.resetSurfacePositionForAnimationLeash(t);
} }
@Override
Rect getAnimationBounds(int appRootTaskClipMode) {
// TODO(b/131661052): we should remove appRootTaskClipMode with hierarchical animations.
if (appRootTaskClipMode == ROOT_TASK_CLIP_BEFORE_ANIM && getRootTask() != null) {
// Using the root task bounds here effectively applies the clipping before animation.
return getRootTask().getBounds();
}
return super.getAnimationBounds(appRootTaskClipMode);
}
boolean shouldAnimate() { boolean shouldAnimate() {
/** /**
* Animations are handled by the TaskOrganizer implementation. * Animations are handled by the TaskOrganizer implementation.

View File

@@ -79,17 +79,11 @@ class WindowStateAnimator {
*/ */
static final int ROOT_TASK_CLIP_AFTER_ANIM = 0; static final int ROOT_TASK_CLIP_AFTER_ANIM = 0;
/**
* Mode how the window gets clipped by the root task bounds: The clipping should be applied
* before applying the animation transformation, i.e. the root task bounds move with the window.
*/
static final int ROOT_TASK_CLIP_BEFORE_ANIM = 1;
/** /**
* Mode how window gets clipped by the root task bounds during an animation: Don't clip the * Mode how window gets clipped by the root task bounds during an animation: Don't clip the
* window by the root task bounds. * window by the root task bounds.
*/ */
static final int ROOT_TASK_CLIP_NONE = 2; static final int ROOT_TASK_CLIP_NONE = 1;
// Unchanging local convenience fields. // Unchanging local convenience fields.
final WindowManagerService mService; final WindowManagerService mService;

View File

@@ -19,7 +19,6 @@ package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
@@ -83,7 +82,6 @@ import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBL
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE; import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@@ -2779,10 +2777,36 @@ public class ActivityRecordTests extends WindowTestsBase {
assertEquals(taskBounds, activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM)); assertEquals(taskBounds, activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
assertEquals(new Point(0, 0), animationPosition); assertEquals(new Point(0, 0), animationPosition);
}
// ROOT_TASK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later. @Test
task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); public void testTransitionAnimationBounds_returnTaskFragment() {
assertEquals(rootTask.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_BEFORE_ANIM)); removeGlobalMinSizeRestriction();
final Task task = new TaskBuilder(mSupervisor).setCreateParentTask(true).build();
final Task rootTask = task.getRootTask();
final TaskFragment taskFragment = createTaskFragmentWithParentTask(task,
false /* createEmbeddedTask */);
final ActivityRecord activity = taskFragment.getTopNonFinishingActivity();
final Rect stackBounds = new Rect(0, 0, 1000, 600);
final Rect taskBounds = new Rect(100, 400, 600, 800);
final Rect taskFragmentBounds = new Rect(100, 400, 300, 800);
final Rect activityBounds = new Rect(100, 400, 300, 600);
// Set the bounds and windowing mode to window configuration directly, otherwise the
// testing setups may be discarded by configuration resolving.
rootTask.getWindowConfiguration().setBounds(stackBounds);
task.getWindowConfiguration().setBounds(taskBounds);
taskFragment.getWindowConfiguration().setBounds(taskFragmentBounds);
activity.getWindowConfiguration().setBounds(activityBounds);
// Check that anim bounds for freeform window match task fragment bounds
task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
assertEquals(taskFragment.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE));
// ROOT_TASK_CLIP_AFTER_ANIM should use task fragment bounds since they will be clipped by
// bounds animation layer.
task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
assertEquals(taskFragment.getBounds(),
activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
} }
@Test @Test

View File

@@ -19,7 +19,6 @@ package com.android.server.wm;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM; import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE; import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@@ -88,43 +87,6 @@ public class WindowAnimationSpecTest {
argThat(rect -> rect.equals(mStackBounds))); argThat(rect -> rect.equals(mStackBounds)));
} }
@Test
public void testApply_clipBeforeNoAnimationBounds() {
// Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 0, 0)
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
mStackBounds, false /* canSkipFirstFrame */, ROOT_TASK_CLIP_BEFORE_ANIM,
true /* isAppAnimation */, 0 /* windowCornerRadius */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(mStackBounds)));
}
@Test
public void testApply_clipBeforeNoStackBounds() {
// Stack bounds is (0, 0, 0, 0) animation clip is (0, 0, 20, 20)
Rect windowCrop = new Rect(0, 0, 20, 20);
Animation a = createClipRectAnimation(windowCrop, windowCrop);
a.initialize(0, 0, 0, 0);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
null, false /* canSkipFirstFrame */, ROOT_TASK_CLIP_BEFORE_ANIM,
true /* isAppAnimation */, 0 /* windowCornerRadius */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
}
@Test
public void testApply_setCornerRadius() {
final float windowCornerRadius = 30f;
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
mStackBounds, false /* canSkipFirstFrame */, ROOT_TASK_CLIP_BEFORE_ANIM,
true /* isAppAnimation */, windowCornerRadius);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction, never()).setCornerRadius(eq(mSurfaceControl), eq(windowCornerRadius));
when(mAnimation.hasRoundedCorners()).thenReturn(true);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setCornerRadius(eq(mSurfaceControl), eq(windowCornerRadius));
}
@Test @Test
public void testApply_setCornerRadius_noClip() { public void testApply_setCornerRadius_noClip() {
final float windowCornerRadius = 30f; final float windowCornerRadius = 30f;
@@ -136,32 +98,6 @@ public class WindowAnimationSpecTest {
verify(mTransaction, never()).setCornerRadius(any(), anyFloat()); verify(mTransaction, never()).setCornerRadius(any(), anyFloat());
} }
@Test
public void testApply_clipBeforeSmallerAnimationClip() {
// Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5)
Rect windowCrop = new Rect(0, 0, 5, 5);
Animation a = createClipRectAnimation(windowCrop, windowCrop);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
mStackBounds, false /* canSkipFirstFrame */, ROOT_TASK_CLIP_BEFORE_ANIM,
true /* isAppAnimation */, 0 /* windowCornerRadius */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(windowCrop)));
}
@Test
public void testApply_clipBeforeSmallerStackClip() {
// Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 20, 20)
Rect windowCrop = new Rect(0, 0, 20, 20);
Animation a = createClipRectAnimation(windowCrop, windowCrop);
WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
mStackBounds, false /* canSkipFirstFrame */, ROOT_TASK_CLIP_BEFORE_ANIM,
true /* isAppAnimation */, 0 /* windowCornerRadius */);
windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
argThat(rect -> rect.equals(mStackBounds)));
}
private Animation createClipRectAnimation(Rect fromClip, Rect toClip) { private Animation createClipRectAnimation(Rect fromClip, Rect toClip) {
Animation a = new ClipRectAnimation(fromClip, toClip); Animation a = new ClipRectAnimation(fromClip, toClip);
a.initialize(0, 0, 0, 0); a.initialize(0, 0, 0, 0);