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

Commit 7735d350 authored by Evan Rosky's avatar Evan Rosky
Browse files

Clip transition animations within a task to the task

Freeform windows have task bounds. Activity transitions within
that task were poking out of the task bounds which looks weird.

This identifies when transitions are completely constrained to
a task and then will clip to the task instead of the stack.

Bug: 126751759
Test: atest AppTransitionControllerTest
      manual test: run settings and gmail in desktop.

Change-Id: I6b7ca74058cdf620b04c1c55f10fe645006c5139
parent b4264999
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
@@ -638,6 +639,39 @@ public class AppTransitionController {
        return transit;
    }

    /**
     * Identifies whether the current transition occurs within a single task or not. This is used
     * to determine whether animations should be clipped to the task bounds instead of stack bounds.
     */
    @VisibleForTesting
    boolean isTransitWithinTask(int transit, Task task) {
        if (task == null
                || !mDisplayContent.mChangingApps.isEmpty()) {
            // if there is no task, then we can't constrain to the task.
            // if anything is changing, it can animate outside its task.
            return false;
        }
        if (!(transit == TRANSIT_ACTIVITY_OPEN
                || transit == TRANSIT_ACTIVITY_CLOSE
                || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
            // only activity-level transitions will be within-task.
            return false;
        }
        // check that all components are in the task.
        for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
            Task activityTask = activity.getTask();
            if (activityTask != task) {
                return false;
            }
        }
        for (AppWindowToken activity : mDisplayContent.mClosingApps) {
            if (activity.getTask() != task) {
                return false;
            }
        }
        return true;
    }

    private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
        for (int i = apps.size() - 1; i >= 0; i--) {
            if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
+12 −7
Original line number Diff line number Diff line
@@ -2705,15 +2705,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        // If the animation needs to be cropped then an animation bounds layer is created as a child
        // of the pinned stack or animation layer. The leash is then reparented to this new layer.
        if (mNeedsAnimationBoundsLayer) {
            mTmpRect.setEmpty();
            final Task task = getTask();
            if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
                    getTransit(), task)) {
                task.getBounds(mTmpRect);
            } else {
                final TaskStack stack = getStack();
                if (stack == null) {
                    return;
                }
            mAnimationBoundsLayer = createAnimationBoundsLayer(t);

                // Set clip rect to stack bounds.
            mTmpRect.setEmpty();
                stack.getBounds(mTmpRect);
            }
            mAnimationBoundsLayer = createAnimationBoundsLayer(t);

            // Crop to stack bounds.
            t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
+24 −0
Original line number Diff line number Diff line
@@ -17,12 +17,16 @@
package com.android.server.wm;

import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import android.platform.test.annotations.Presubmit;
import android.view.WindowManager;
@@ -95,4 +99,24 @@ public class AppTransitionControllerTest extends WindowTestsBase {
                            TRANSIT_TASK_CHANGE_WINDOWING_MODE));
        }
    }

    @Test
    public void testTransitWithinTask() {
        synchronized (mWm.mGlobalLock) {
            final AppWindowToken opening = createAppWindowToken(mDisplayContent,
                    WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
            opening.setFillsParent(false);
            final AppWindowToken closing = createAppWindowToken(mDisplayContent,
                    WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
            closing.setFillsParent(false);
            Task task = opening.getTask();
            mDisplayContent.mOpeningApps.add(opening);
            mDisplayContent.mClosingApps.add(closing);
            assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
            closing.getTask().removeChild(closing);
            task.addChild(closing, 0);
            assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
            assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_TASK_OPEN, task));
        }
    }
}