diff options
5 files changed, 79 insertions, 3 deletions
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 33ea2e4af473..641d1a189711 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -125,8 +125,15 @@ public final class TransitionInfo implements Parcelable { /** The container attaches work profile thumbnail for cross profile animation. */ public static final int FLAG_CROSS_PROFILE_WORK_THUMBNAIL = 1 << 13; + /** + * Whether the window is covered by an app starting window. This is different from + * {@link #FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT} which is only set on the Activity window + * that contains the starting window. + */ + public static final int FLAG_IS_BEHIND_STARTING_WINDOW = 1 << 14; + /** The first unused bit. This can be used by remotes to attach custom flags to this change. */ - public static final int FLAG_FIRST_CUSTOM = 1 << 14; + public static final int FLAG_FIRST_CUSTOM = 1 << 15; /** @hide */ @IntDef(prefix = { "FLAG_" }, value = { @@ -145,6 +152,7 @@ public final class TransitionInfo implements Parcelable { FLAG_WILL_IME_SHOWN, FLAG_CROSS_PROFILE_OWNER_THUMBNAIL, FLAG_CROSS_PROFILE_WORK_THUMBNAIL, + FLAG_IS_BEHIND_STARTING_WINDOW, FLAG_FIRST_CUSTOM }) public @interface ChangeFlags {} @@ -351,6 +359,9 @@ public final class TransitionInfo implements Parcelable { if ((flags & FLAG_FILLS_TASK) != 0) { sb.append(sb.length() == 0 ? "" : "|").append("FILLS_TASK"); } + if ((flags & FLAG_IS_BEHIND_STARTING_WINDOW) != 0) { + sb.append(sb.length() == 0 ? "" : "|").append("IS_BEHIND_STARTING_WINDOW"); + } if ((flags & FLAG_FIRST_CUSTOM) != 0) { sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM"); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index d88cc007c7b5..d150261b31b8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -18,6 +18,7 @@ package com.android.wm.shell.activityembedding; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; +import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; import android.animation.Animator; import android.animation.ValueAnimator; @@ -129,12 +130,20 @@ class ActivityEmbeddingAnimationRunner { @NonNull private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) { + boolean isChangeTransition = false; for (TransitionInfo.Change change : info.getChanges()) { - if (change.getMode() == TRANSIT_CHANGE + if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) { + // Skip the animation if the windows are behind an app starting window. + return new ArrayList<>(); + } + if (!isChangeTransition && change.getMode() == TRANSIT_CHANGE && !change.getStartAbsBounds().equals(change.getEndAbsBounds())) { - return createChangeAnimationAdapters(info, startTransaction); + isChangeTransition = true; } } + if (isChangeTransition) { + return createChangeAnimationAdapters(info, startTransaction); + } if (Transitions.isClosingType(info.getType())) { return createCloseAnimationAdapters(info); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java index a7234c1d3cb8..98b59126227c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java @@ -18,7 +18,9 @@ package com.android.wm.shell.activityembedding; import static android.view.WindowManager.TRANSIT_OPEN; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; +import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; @@ -27,6 +29,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.animation.Animator; import android.window.TransitionInfo; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -76,4 +79,18 @@ public class ActivityEmbeddingAnimationRunnerTests extends ActivityEmbeddingAnim verify(mController).onAnimationFinished(mTransition); } + + @Test + public void testChangesBehindStartingWindow() { + final TransitionInfo info = new TransitionInfo(TRANSIT_OPEN, 0); + final TransitionInfo.Change embeddingChange = createChange(); + embeddingChange.setFlags(FLAG_IS_BEHIND_STARTING_WINDOW); + info.addChange(embeddingChange); + final Animator animator = mAnimRunner.createAnimator( + info, mStartTransaction, mFinishTransaction, + () -> mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */)); + + // The animation should be empty when it is behind starting window. + assertEquals(0, animator.getDuration()); + } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index ec7a755b5d1f..147c9cb18315 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -48,6 +48,7 @@ import static android.view.WindowManager.transitTypeToString; import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS; import static android.window.TransitionInfo.FLAG_FILLS_TASK; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; +import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD; import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION; @@ -1894,6 +1895,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe // Whether this is in a Task with embedded activity. flags |= FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; } + if (parentTask.forAllActivities(ActivityRecord::hasStartingWindow)) { + // The starting window should cover all windows inside the leaf Task. + flags |= FLAG_IS_BEHIND_STARTING_WINDOW; + } if (isWindowFillingTask(wc, parentTask)) { // Whether the container fills its parent Task bounds. flags |= FLAG_FILLS_TASK; diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 210edae62b56..45d8e226c64f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -34,6 +34,7 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_FILLS_TASK; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; +import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER; import static android.window.TransitionInfo.FLAG_TRANSLUCENT; @@ -1074,6 +1075,39 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testIsBehindStartingWindowChange() { + final Transition transition = createTestTransition(TRANSIT_OPEN); + final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; + final ArraySet<WindowContainer> participants = transition.mParticipants; + + final Task task = createTask(mDisplayContent); + final ActivityRecord activity0 = createActivityRecord(task); + final ActivityRecord activity1 = createActivityRecord(task); + doReturn(true).when(activity1).hasStartingWindow(); + + // Start states. + changes.put(activity0, new Transition.ChangeInfo(true /* vis */, false /* exChg */)); + changes.put(activity1, new Transition.ChangeInfo(false /* vis */, false /* exChg */)); + // End states. + activity0.mVisibleRequested = false; + activity1.mVisibleRequested = true; + + participants.add(activity0); + participants.add(activity1); + final ArrayList<WindowContainer> targets = Transition.calculateTargets( + participants, changes); + final TransitionInfo info = Transition.calculateTransitionInfo( + transition.mType, 0 /* flags */, targets, changes, mMockT); + + // All windows in the Task should have FLAG_IS_BEHIND_STARTING_WINDOW because the starting + // window should cover the whole Task. + assertEquals(2, info.getChanges().size()); + assertTrue(info.getChanges().get(0).hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)); + assertTrue(info.getChanges().get(1).hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)); + + } + + @Test public void testFlagInTaskWithEmbeddedActivity() { final Transition transition = createTestTransition(TRANSIT_OPEN); final ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; |