Loading core/java/android/window/TransitionInfo.java +12 −1 Original line number Diff line number Diff line Loading @@ -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 = { Loading @@ -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 {} Loading Loading @@ -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"); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +11 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java +17 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); } } services/core/java/com/android/server/wm/Transition.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1073,6 +1074,39 @@ public class TransitionTests extends WindowTestsBase { assertTrue(openTransition.allReady()); } @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); Loading Loading
core/java/android/window/TransitionInfo.java +12 −1 Original line number Diff line number Diff line Loading @@ -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 = { Loading @@ -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 {} Loading Loading @@ -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"); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +11 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunnerTests.java +17 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); } }
services/core/java/com/android/server/wm/Transition.java +5 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading
services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +34 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -1073,6 +1074,39 @@ public class TransitionTests extends WindowTestsBase { assertTrue(openTransition.allReady()); } @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); Loading