Use TaskFragment bounds instead of TaskBounds for Activity animation

The animation bounds is used as the RemoteAnimationTarget#localBounds.
It should be the TaskFragment bounds instead of Task bounds because the
Activity may not fill the Task when it is in a TaskFragment.

Also clean up ROOT_TASK_CLIP_BEFORE_ANIM which has no more use case.

Bug: 196173550
Test: test with demo app
Test: atest WmTests:ActivityRecordTests
Change-Id: Iff58afdb0bbae95d3f6a5756de06c0d2dfff7c88
This commit is contained in:
Chris Li
2021-09-16 21:20:01 +08:00
parent 211d6cf754
commit e045dd6e81
5 changed files with 33 additions and 94 deletions

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.WindowState.LEGACY_POLICY_VISIBILITY;
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_TAG;
@@ -8041,13 +8040,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
@VisibleForTesting
@Override
Rect getAnimationBounds(int appRootTaskClipMode) {
if (appRootTaskClipMode == ROOT_TASK_CLIP_BEFORE_ANIM && getRootTask() != null) {
// 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
// Use TaskFragment-bounds if available so that activity-level letterbox (maxAspectRatio) is
// included in the animation.
return task != null ? task.getBounds() : getBounds();
final TaskFragment taskFragment = getTaskFragment();
return taskFragment != null ? taskFragment.getBounds() : getBounds();
}
@Override

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.TAG_WM;
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;
@@ -2984,16 +2983,6 @@ class Task extends TaskFragment {
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() {
/**
* Animations are handled by the TaskOrganizer implementation.

View File

@@ -79,17 +79,11 @@ class WindowStateAnimator {
*/
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
* 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.
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_FULLSCREEN;
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_SCREEN_LAYOUT;
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.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_BEFORE_ANIM;
import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
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(new Point(0, 0), animationPosition);
}
// ROOT_TASK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later.
task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
assertEquals(rootTask.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_BEFORE_ANIM));
@Test
public void testTransitionAnimationBounds_returnTaskFragment() {
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

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.verify;
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 org.mockito.ArgumentMatchers.any;
@@ -88,43 +87,6 @@ public class WindowAnimationSpecTest {
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
public void testApply_setCornerRadius_noClip() {
final float windowCornerRadius = 30f;
@@ -136,32 +98,6 @@ public class WindowAnimationSpecTest {
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) {
Animation a = new ClipRectAnimation(fromClip, toClip);
a.initialize(0, 0, 0, 0);