From 7735d350a95fecab1ec6c8cadc4928984e122b1f Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Mon, 18 Mar 2019 17:27:27 -0700 Subject: [PATCH] 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 --- .../server/wm/AppTransitionController.java | 34 +++++++++++++++++++ .../com/android/server/wm/AppWindowToken.java | 19 +++++++---- .../wm/AppTransitionControllerTest.java | 24 +++++++++++++ 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index f63269571fc02..75e34fb0d453b 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -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 apps) { for (int i = apps.size() - 1; i >= 0; i--) { if (apps.valueAt(i).windowsCanBeWallpaperTarget()) { diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index ea3a7d5ca3b23..3f29181f0215e 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -2705,16 +2705,21 @@ 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) { - final TaskStack stack = getStack(); - if (stack == null) { - return; + mTmpRect.setEmpty(); + final Task task = getTask(); + if (getDisplayContent().mAppTransitionController.isTransitWithinTask( + getTransit(), task)) { + task.getBounds(mTmpRect); + } else { + final TaskStack stack = getStack(); + if (stack == null) { + return; + } + // Set clip rect to stack bounds. + stack.getBounds(mTmpRect); } mAnimationBoundsLayer = createAnimationBoundsLayer(t); - // Set clip rect to stack bounds. - mTmpRect.setEmpty(); - stack.getBounds(mTmpRect); - // Crop to stack bounds. t.setWindowCrop(mAnimationBoundsLayer, mTmpRect); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 81133d1052ec7..9bd993070939d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -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)); + } + } }