Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e045dd6e authored by Chris Li's avatar Chris Li
Browse files

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
parent 211d6cf7
Loading
Loading
Loading
Loading
+3 −7
Original line number Diff line number Diff line
@@ -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
+0 −11
Original line number Diff line number Diff line
@@ -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.
+1 −7
Original line number Diff line number Diff line
@@ -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;
+29 −5
Original line number Diff line number Diff line
@@ -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
+0 −64
Original line number Diff line number Diff line
@@ -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);