diff options
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 f63269571fc0..75e34fb0d453 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<AppWindowToken> 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 ea3a7d5ca3b2..3f29181f0215 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 81133d1052ec..9bd993070939 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)); + } + } } |