From d7725b52723ca07eab159cbe5667a06389b62340 Mon Sep 17 00:00:00 2001 From: Chris Li Date: Tue, 15 Nov 2022 17:23:56 +0800 Subject: [PATCH] Only override ActivityEmbedding animation for embedded activities Before, we check if there is any split rule meeting the bounds requirement for the given Task bounds in order to determine whether or not to override the animation. This can cause issue when the apps later unregister the split rules while there is existing split. Also, this is hard to determine as we now have SplitAttributesCalculator which can change the split state for the same bounds. To fix these problem, we now check if the app transition contains any embedded activity (embedded TaskFragment that is not filling Task), to determine if the animation should be played by the organizer. Fix: 242051445 Test: atest WmTests:AppTransitionControllerTest Change-Id: Ie90ba085cab3d4072f47cc3599d0494324fa39a9 --- .../ITaskFragmentOrganizerController.aidl | 4 +- .../android/window/TaskFragmentOrganizer.java | 13 +-- .../JetpackTaskFragmentOrganizer.java | 19 ++-- .../extensions/embedding/SplitController.java | 44 +-------- .../extensions/embedding/SplitPresenter.java | 5 + .../TaskFragmentAnimationController.java | 31 ++----- .../TaskFragmentAnimationRunner.java | 4 - .../JetpackTaskFragmentOrganizerTest.java | 28 +----- .../TaskFragmentAnimationControllerTest.java | 35 +++---- .../server/wm/AppTransitionController.java | 35 ++++++- .../com/android/server/wm/TaskFragment.java | 26 ++++-- .../wm/TaskFragmentOrganizerController.java | 40 +++----- .../wm/AppTransitionControllerTest.java | 93 ++++++++++++++++--- .../TaskFragmentOrganizerControllerTest.java | 8 +- 14 files changed, 194 insertions(+), 191 deletions(-) diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl index 3250dd8f7308f..d25c8a834c7bc 100644 --- a/core/java/android/window/ITaskFragmentOrganizerController.aidl +++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl @@ -39,13 +39,13 @@ interface ITaskFragmentOrganizerController { * animations if the transition only contains windows that belong to the organized * TaskFragments in the given Task. */ - void registerRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId, + void registerRemoteAnimations(in ITaskFragmentOrganizer organizer, in RemoteAnimationDefinition definition); /** * Unregisters remote animations per transition type for the organizer. */ - void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer, int taskId); + void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer); /** * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 648541bf62c79..ab7d616f038c9 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -140,16 +140,13 @@ public class TaskFragmentOrganizer extends WindowOrganizer { /** * Registers remote animations per transition type for the organizer. It will override the * animations if the transition only contains windows that belong to the organized - * TaskFragments in the given Task. - * - * @param taskId overrides if the transition only contains windows belonging to this Task. + * TaskFragments, and at least one of the transition window is embedded (not filling the Task). * @hide */ @CallSuper - public void registerRemoteAnimations(int taskId, - @NonNull RemoteAnimationDefinition definition) { + public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) { try { - getController().registerRemoteAnimations(mInterface, taskId, definition); + getController().registerRemoteAnimations(mInterface, definition); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -160,9 +157,9 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * @hide */ @CallSuper - public void unregisterRemoteAnimations(int taskId) { + public void unregisterRemoteAnimations() { try { - getController().unregisterRemoteAnimations(mInterface, taskId); + getController().unregisterRemoteAnimations(mInterface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index 74303e2fab7ce..4fe4b0af070fc 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -31,7 +31,6 @@ import android.window.TaskFragmentOrganizer; import android.window.TaskFragmentTransaction; import android.window.WindowContainerTransaction; -import androidx.annotation.GuardedBy; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -79,26 +78,20 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { @Override public void unregisterOrganizer() { if (mAnimationController != null) { - mAnimationController.unregisterAllRemoteAnimations(); + mAnimationController.unregisterRemoteAnimations(); mAnimationController = null; } super.unregisterOrganizer(); } - /** Overrides the animation if the transition is on the given Task. */ - void startOverrideSplitAnimation(int taskId) { + /** + * Overrides the animation for transitions of embedded activities organized by this organizer. + */ + void overrideSplitAnimation() { if (mAnimationController == null) { mAnimationController = new TaskFragmentAnimationController(this); } - mAnimationController.registerRemoteAnimations(taskId); - } - - /** No longer overrides the animation if the transition is on the given Task. */ - @GuardedBy("mLock") - void stopOverrideSplitAnimation(int taskId) { - if (mAnimationController != null) { - mAnimationController.unregisterRemoteAnimations(taskId); - } + mAnimationController.registerRemoteAnimations(); } /** diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index 16760e26b3f1a..e8ecf2a7e77e6 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -193,7 +193,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen continue; } updateContainersInTask(wct, taskContainer); - updateAnimationOverride(taskContainer); } // The WCT should be applied and merged to the device state change transition if // there is one. @@ -208,9 +207,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen synchronized (mLock) { mSplitRules.clear(); mSplitRules.addAll(rules); - for (int i = mTaskContainers.size() - 1; i >= 0; i--) { - updateAnimationOverride(mTaskContainers.valueAt(i)); - } } } @@ -608,7 +604,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } if (taskContainer.isEmpty()) { // Cleanup the TaskContainer if it becomes empty. - mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId()); mTaskContainers.remove(taskContainer.getTaskId()); } return; @@ -618,43 +613,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @GuardedBy("mLock") private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer, @NonNull Configuration config) { - final boolean wasInPip = taskContainer.isInPictureInPicture(); - final boolean isInPIp = isInPictureInPicture(config); - - // We need to check the animation override when enter/exit PIP or has bounds changed. - boolean shouldUpdateAnimationOverride = wasInPip != isInPIp; - if (taskContainer.setTaskBounds(config.windowConfiguration.getBounds()) - && !isInPIp) { - // We don't care the bounds change when it has already entered PIP. - shouldUpdateAnimationOverride = true; - } - if (shouldUpdateAnimationOverride) { - updateAnimationOverride(taskContainer); - } - } - - /** - * Updates if we should override transition animation. We only want to override if the Task - * bounds is large enough for at least one split rule. - */ - @GuardedBy("mLock") - private void updateAnimationOverride(@NonNull TaskContainer taskContainer) { - if (ENABLE_SHELL_TRANSITIONS) { - // TODO(b/207070762): cleanup with legacy app transition - // Animation will be handled by WM Shell with Shell transition enabled. - return; - } - if (!taskContainer.isTaskBoundsInitialized()) { - // We don't know about the Task bounds/windowingMode yet. - return; - } - - // We only want to override if the TaskContainer may show split. - if (mayShowSplit(taskContainer)) { - mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId()); - } else { - mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId()); - } + taskContainer.setTaskBounds(config.windowConfiguration.getBounds()); } /** Returns whether the given {@link TaskContainer} may show in split. */ @@ -1279,7 +1238,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen Log.w(TAG, "Can't find bounds from activity=" + activityInTask); } } - updateAnimationOverride(taskContainer); return container; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index 362f1fa096cce..3b2a8627add9f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -139,6 +139,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { super(executor, controller); mController = controller; registerOrganizer(); + if (!SplitController.ENABLE_SHELL_TRANSITIONS) { + // TODO(b/207070762): cleanup with legacy app transition + // Animation will be handled by WM Shell when Shell transition is enabled. + overrideSplitAnimation(); + } } /** diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java index ee2e139bb0b2b..d7eb9a01f57cb 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationController.java @@ -18,13 +18,10 @@ package androidx.window.extensions.embedding; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; -import android.util.ArraySet; import android.util.Log; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; @@ -44,8 +41,7 @@ class TaskFragmentAnimationController { private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner(); @VisibleForTesting final RemoteAnimationDefinition mDefinition; - /** Task Ids that we have registered for remote animation. */ - private final ArraySet mRegisterTasks = new ArraySet<>(); + private boolean mIsRegistered; TaskFragmentAnimationController(@NonNull TaskFragmentOrganizer organizer) { mOrganizer = organizer; @@ -54,39 +50,30 @@ class TaskFragmentAnimationController { new RemoteAnimationAdapter(mRemoteRunner, 0, 0, true /* changeNeedsSnapshot */); mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter); - mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_OPEN, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter); - mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_CLOSE, animationAdapter); mDefinition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter); } - void registerRemoteAnimations(int taskId) { + void registerRemoteAnimations() { if (DEBUG) { Log.v(TAG, "registerRemoteAnimations"); } - if (mRegisterTasks.contains(taskId)) { + if (mIsRegistered) { return; } - mOrganizer.registerRemoteAnimations(taskId, mDefinition); - mRegisterTasks.add(taskId); + mOrganizer.registerRemoteAnimations(mDefinition); + mIsRegistered = true; } - void unregisterRemoteAnimations(int taskId) { + void unregisterRemoteAnimations() { if (DEBUG) { Log.v(TAG, "unregisterRemoteAnimations"); } - if (!mRegisterTasks.contains(taskId)) { + if (!mIsRegistered) { return; } - mOrganizer.unregisterRemoteAnimations(taskId); - mRegisterTasks.remove(taskId); - } - - void unregisterAllRemoteAnimations() { - final ArraySet tasks = new ArraySet<>(mRegisterTasks); - for (int taskId : tasks) { - unregisterRemoteAnimations(taskId); - } + mOrganizer.unregisterRemoteAnimations(); + mIsRegistered = false; } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java index 8c416e881059c..0e13c59e593c8 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java @@ -20,11 +20,9 @@ import static android.os.Process.THREAD_PRIORITY_DISPLAY; import static android.view.RemoteAnimationTarget.MODE_CLOSING; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; import android.animation.Animator; @@ -169,11 +167,9 @@ class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub { switch (transit) { case TRANSIT_OLD_ACTIVITY_OPEN: case TRANSIT_OLD_TASK_FRAGMENT_OPEN: - case TRANSIT_OLD_TASK_OPEN: return createOpenAnimationAdapters(targets); case TRANSIT_OLD_ACTIVITY_CLOSE: case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: - case TRANSIT_OLD_TASK_CLOSE: return createCloseAnimationAdapters(targets); case TRANSIT_OLD_TASK_FRAGMENT_CHANGE: return createChangeAnimationAdapters(targets); diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java index 957a24873998b..48659a7f37978 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java @@ -18,7 +18,6 @@ package androidx.window.extensions.embedding; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID; import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -26,10 +25,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import android.content.Intent; import android.content.res.Configuration; @@ -85,35 +82,20 @@ public class JetpackTaskFragmentOrganizerTest { @Test public void testUnregisterOrganizer() { - mOrganizer.startOverrideSplitAnimation(TASK_ID); - mOrganizer.startOverrideSplitAnimation(TASK_ID + 1); + mOrganizer.overrideSplitAnimation(); mOrganizer.unregisterOrganizer(); - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID + 1); + verify(mOrganizer).unregisterRemoteAnimations(); } @Test - public void testStartOverrideSplitAnimation() { + public void testOverrideSplitAnimation() { assertNull(mOrganizer.mAnimationController); - mOrganizer.startOverrideSplitAnimation(TASK_ID); + mOrganizer.overrideSplitAnimation(); assertNotNull(mOrganizer.mAnimationController); - verify(mOrganizer).registerRemoteAnimations(TASK_ID, - mOrganizer.mAnimationController.mDefinition); - } - - @Test - public void testStopOverrideSplitAnimation() { - mOrganizer.stopOverrideSplitAnimation(TASK_ID); - - verify(mOrganizer, never()).unregisterRemoteAnimations(anyInt()); - - mOrganizer.startOverrideSplitAnimation(TASK_ID); - mOrganizer.stopOverrideSplitAnimation(TASK_ID); - - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); + verify(mOrganizer).registerRemoteAnimations(mOrganizer.mAnimationController.mDefinition); } @Test diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java index d31342bfb3097..379ea0c534ba7 100644 --- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java +++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentAnimationControllerTest.java @@ -16,11 +16,8 @@ package androidx.window.extensions.embedding; -import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; import android.platform.test.annotations.Presubmit; @@ -57,41 +54,31 @@ public class TaskFragmentAnimationControllerTest { @Test public void testRegisterRemoteAnimations() { - mAnimationController.registerRemoteAnimations(TASK_ID); + mAnimationController.registerRemoteAnimations(); - verify(mOrganizer).registerRemoteAnimations(TASK_ID, mAnimationController.mDefinition); + verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition); - mAnimationController.registerRemoteAnimations(TASK_ID); + mAnimationController.registerRemoteAnimations(); // No extra call if it has been registered. - verify(mOrganizer).registerRemoteAnimations(TASK_ID, mAnimationController.mDefinition); + verify(mOrganizer).registerRemoteAnimations(mAnimationController.mDefinition); } @Test public void testUnregisterRemoteAnimations() { - mAnimationController.unregisterRemoteAnimations(TASK_ID); + mAnimationController.unregisterRemoteAnimations(); // No call if it is not registered. - verify(mOrganizer, never()).unregisterRemoteAnimations(anyInt()); + verify(mOrganizer, never()).unregisterRemoteAnimations(); - mAnimationController.registerRemoteAnimations(TASK_ID); - mAnimationController.unregisterRemoteAnimations(TASK_ID); + mAnimationController.registerRemoteAnimations(); + mAnimationController.unregisterRemoteAnimations(); - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); + verify(mOrganizer).unregisterRemoteAnimations(); - mAnimationController.unregisterRemoteAnimations(TASK_ID); + mAnimationController.unregisterRemoteAnimations(); // No extra call if it has been unregistered. - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); - } - - @Test - public void testUnregisterAllRemoteAnimations() { - mAnimationController.registerRemoteAnimations(TASK_ID); - mAnimationController.registerRemoteAnimations(TASK_ID + 1); - mAnimationController.unregisterAllRemoteAnimations(); - - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID); - verify(mOrganizer).unregisterRemoteAnimations(TASK_ID + 1); + verify(mOrganizer).unregisterRemoteAnimations(); } } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 12133bc06df8c..d5c9e66204d88 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -561,6 +561,34 @@ public class AppTransitionController { || shouldStartWallpaperAnimation(mDisplayContent); } + /** + * Whether the transition contains any embedded {@link TaskFragment} that does not fill the + * parent {@link Task} before or after the transition. + */ + private boolean transitionContainsTaskFragmentWithBoundsOverride() { + for (int i = mDisplayContent.mChangingContainers.size() - 1; i >= 0; i--) { + final WindowContainer wc = mDisplayContent.mChangingContainers.valueAt(i); + if (wc.isEmbedded()) { + // Contains embedded TaskFragment with bounds changed. + return true; + } + } + mTempTransitionWindows.clear(); + mTempTransitionWindows.addAll(mDisplayContent.mClosingApps); + mTempTransitionWindows.addAll(mDisplayContent.mOpeningApps); + boolean containsTaskFragmentWithBoundsOverride = false; + for (int i = mTempTransitionWindows.size() - 1; i >= 0; i--) { + final ActivityRecord r = mTempTransitionWindows.get(i).asActivityRecord(); + final TaskFragment tf = r.getTaskFragment(); + if (tf != null && tf.isEmbeddedWithBoundsOverride()) { + containsTaskFragmentWithBoundsOverride = true; + break; + } + } + mTempTransitionWindows.clear(); + return containsTaskFragmentWithBoundsOverride; + } + /** * Finds the common parent {@link Task} that is parent of all embedded app windows in the * current transition. @@ -664,12 +692,17 @@ public class AppTransitionController { if (transitionMayContainNonAppWindows(transit)) { return false; } + if (!transitionContainsTaskFragmentWithBoundsOverride()) { + // No need to play TaskFragment remote animation if all embedded TaskFragment in the + // transition fill the Task. + return false; + } final Task task = findParentTaskForAllEmbeddedWindows(); final ITaskFragmentOrganizer organizer = findTaskFragmentOrganizer(task); final RemoteAnimationDefinition definition = organizer != null ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController - .getRemoteAnimationDefinition(organizer, task.mTaskId) + .getRemoteAnimationDefinition(organizer) : null; final RemoteAnimationAdapter adapter = definition != null ? definition.getAdapter(transit, activityTypes) diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 93fcc202368c7..b8eba3d294a59 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -559,15 +559,7 @@ class TaskFragment extends WindowContainer { @Override boolean isEmbedded() { - if (mIsEmbedded) { - return true; - } - final WindowContainer parent = getParent(); - if (parent != null) { - final TaskFragment taskFragment = parent.asTaskFragment(); - return taskFragment != null && taskFragment.isEmbedded(); - } - return false; + return mIsEmbedded; } @EmbeddingCheckResult @@ -2495,6 +2487,22 @@ class TaskFragment extends WindowContainer { return mTaskFragmentOrganizer != null; } + /** + * Whether this is an embedded {@link TaskFragment} that does not fill the parent {@link Task}. + */ + boolean isEmbeddedWithBoundsOverride() { + if (!mIsEmbedded) { + return false; + } + final Task task = getTask(); + if (task == null) { + return false; + } + final Rect taskBounds = task.getBounds(); + final Rect taskFragBounds = getBounds(); + return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds); + } + /** Whether the Task should be visible. */ boolean isTaskVisibleRequested() { final Task task = getTask(); diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 509b1e6f41ca6..dbe2ba6d6c806 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -35,7 +35,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.Configuration; -import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -132,12 +131,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr new WeakHashMap<>(); /** - * Map from Task Id to {@link RemoteAnimationDefinition}. - * @see android.window.TaskFragmentOrganizer#registerRemoteAnimations(int, - * RemoteAnimationDefinition) ) + * {@link RemoteAnimationDefinition} for embedded activities transition animation that is + * organized by this organizer. */ - private final SparseArray mRemoteAnimationDefinitions = - new SparseArray<>(); + @Nullable + private RemoteAnimationDefinition mRemoteAnimationDefinition; /** * Map from {@link TaskFragmentTransaction#getTransactionToken()} to the @@ -453,7 +451,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } @Override - public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId, + public void registerRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, @NonNull RemoteAnimationDefinition definition) { final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); @@ -466,20 +464,19 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr if (organizerState == null) { throw new IllegalStateException("The organizer hasn't been registered."); } - if (organizerState.mRemoteAnimationDefinitions.contains(taskId)) { + if (organizerState.mRemoteAnimationDefinition != null) { throw new IllegalStateException( "The organizer has already registered remote animations=" - + organizerState.mRemoteAnimationDefinitions.get(taskId) - + " for TaskId=" + taskId); + + organizerState.mRemoteAnimationDefinition); } definition.setCallingPidUid(pid, uid); - organizerState.mRemoteAnimationDefinitions.put(taskId, definition); + organizerState.mRemoteAnimationDefinition = definition; } } @Override - public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer, int taskId) { + public void unregisterRemoteAnimations(@NonNull ITaskFragmentOrganizer organizer) { final int pid = Binder.getCallingPid(); final long uid = Binder.getCallingUid(); synchronized (mGlobalLock) { @@ -493,7 +490,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return; } - organizerState.mRemoteAnimationDefinitions.remove(taskId); + organizerState.mRemoteAnimationDefinition = null; } } @@ -525,16 +522,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr /** * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns - * {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode. + * {@code null} if it doesn't. */ @Nullable public RemoteAnimationDefinition getRemoteAnimationDefinition( - @NonNull ITaskFragmentOrganizer organizer, int taskId) { + @NonNull ITaskFragmentOrganizer organizer) { synchronized (mGlobalLock) { final TaskFragmentOrganizerState organizerState = mTaskFragmentOrganizerState.get(organizer.asBinder()); return organizerState != null - ? organizerState.mRemoteAnimationDefinitions.get(taskId) + ? organizerState.mRemoteAnimationDefinition : null; } } @@ -1083,16 +1080,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return false; } final TaskFragment taskFragment = activity.getOrganizedTaskFragment(); - if (taskFragment == null) { - return false; - } - final Task parentTask = taskFragment.getTask(); - if (parentTask != null) { - final Rect taskBounds = parentTask.getBounds(); - final Rect taskFragBounds = taskFragment.getBounds(); - return !taskBounds.equals(taskFragBounds) && taskBounds.contains(taskFragBounds); - } - return false; + return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride(); } } } 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 0332c4b4597b7..43e79f9cbb15c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN; @@ -56,6 +57,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.Nullable; +import android.graphics.Rect; import android.gui.DropInputMode; import android.os.Binder; import android.os.IBinder; @@ -918,7 +920,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Create a TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); @@ -934,12 +936,78 @@ public class AppTransitionControllerTest extends WindowTestsBase { assertTrue(remoteAnimationRunner.isAnimationStarted()); } + @Test + public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() { + final Task task = createTask(mDisplayContent); + final ActivityRecord closingActivity = createActivityRecord(task); + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); + + // Create a TaskFragment with embedded activity. + final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); + + // Make sure the TaskFragment is not embedded. + assertFalse(taskFragment.isEmbeddedWithBoundsOverride()); + final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); + prepareActivityForAppTransition(closingActivity); + prepareActivityForAppTransition(openingActivity); + final int uid = 12345; + closingActivity.info.applicationInfo.uid = uid; + openingActivity.info.applicationInfo.uid = uid; + task.effectiveUid = uid; + spyOn(mDisplayContent.mAppTransition); + + // Prepare and start transition. + prepareAndTriggerAppTransition(openingActivity, closingActivity, + null /* changingTaskFragment */); + mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); + + // Animation is not run by the remote handler because the activity is filling the Task. + assertFalse(remoteAnimationRunner.isAnimationStarted()); + } + + @Test + public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() { + final Task task = createTask(mDisplayContent); + final ActivityRecord closingActivity = createActivityRecord(task); + final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); + final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); + + // Create a TaskFragment with embedded activity. + final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); + + // Make sure the TaskFragment is embedded. + taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + final Rect embeddedBounds = new Rect(task.getBounds()); + embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2; + taskFragment.setBounds(embeddedBounds); + assertTrue(taskFragment.isEmbeddedWithBoundsOverride()); + final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); + prepareActivityForAppTransition(closingActivity); + prepareActivityForAppTransition(openingActivity); + final int uid = 12345; + closingActivity.info.applicationInfo.uid = uid; + openingActivity.info.applicationInfo.uid = uid; + task.effectiveUid = uid; + spyOn(mDisplayContent.mAppTransition); + + // Prepare and start transition. + prepareAndTriggerAppTransition(openingActivity, closingActivity, + null /* changingTaskFragment */); + mWm.mAnimator.executeAfterPrepareSurfacesRunnables(); + + // Animation run by the remote handler. + assertTrue(remoteAnimationRunner.isAnimationStarted()); + } + @Test public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Closing non-embedded activity. final ActivityRecord closingActivity = createActivityRecord(task); @@ -964,7 +1032,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Closing TaskFragment with embedded activity. final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); @@ -991,7 +1059,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Closing activity in Task1. final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); @@ -1015,7 +1083,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Closing TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); @@ -1043,7 +1111,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Create a TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); @@ -1069,7 +1137,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Create a TaskFragment with embedded activities, one is trusted embedded, and the other // one is untrusted embedded. @@ -1128,7 +1196,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Create a TaskFragment with only trusted embedded activity final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) @@ -1168,7 +1236,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task task = createTask(mDisplayContent); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner(); - setupTaskFragmentRemoteAnimation(organizer, task.mTaskId, remoteAnimationRunner); + setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner); // Create a TaskFragment with only trusted embedded activity final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) @@ -1259,7 +1327,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { } /** Registers remote animation for the organizer. */ - private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, int taskId, + private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, TestRemoteAnimationRunner remoteAnimationRunner) { final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( remoteAnimationRunner, 10, 1); @@ -1268,9 +1336,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); + definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter); + definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter); mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); - mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, taskId, - definition); + mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); } private static ITaskFragmentOrganizer getITaskFragmentOrganizer( diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index 4202f46c188c6..503c43623feb0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -416,13 +416,13 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { @Test public void testRegisterRemoteAnimations() { - mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition); + mController.registerRemoteAnimations(mIOrganizer, mDefinition); - assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID)); + assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer)); - mController.unregisterRemoteAnimations(mIOrganizer, TASK_ID); + mController.unregisterRemoteAnimations(mIOrganizer); - assertNull(mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID)); + assertNull(mController.getRemoteAnimationDefinition(mIOrganizer)); } @Test