Loading data/etc/services.core.protolog.json +6 −0 Original line number Diff line number Diff line Loading @@ -3505,6 +3505,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, "1805116444": { "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.", "level": "ERROR", "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, "1810019902": { "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", "level": "DEBUG", Loading services/core/java/com/android/server/wm/AppTransitionController.java +56 −15 Original line number Diff line number Diff line Loading @@ -533,40 +533,81 @@ public class AppTransitionController { * * @return {@code true} if the transition is overridden. */ @VisibleForTesting boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, ArraySet<Integer> activityTypes) { final ArrayList<WindowContainer> allWindows = new ArrayList<>(); allWindows.addAll(mDisplayContent.mClosingApps); allWindows.addAll(mDisplayContent.mOpeningApps); allWindows.addAll(mDisplayContent.mChangingContainers); // Find the common TaskFragmentOrganizer of all windows. ITaskFragmentOrganizer organizer = null; // It should only animated by the organizer if all windows are below the same leaf Task. Task leafTask = null; for (int i = allWindows.size() - 1; i >= 0; i--) { final ActivityRecord r = getAppFromContainer(allWindows.get(i)); if (r == null) { return false; } // The activity may be a child of embedded Task, but we want to find the owner Task. // As a result, find the organized TaskFragment first. final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null ? organizedTaskFragment.getTaskFragmentOrganizer() : null; if (curOrganizer == null) { // All windows must below an organized TaskFragment. // There are also cases where the Task contains non-embedded activity, such as launching // split TaskFragments from a non-embedded activity. // The hierarchy may looks like this: // - Task // - Activity // - TaskFragment // - Activity // - TaskFragment // - Activity // We also want to have the organizer handle the transition for such case. final Task task = organizedTaskFragment != null ? organizedTaskFragment.getTask() : r.getTask(); if (task == null) { return false; } if (organizer == null) { organizer = curOrganizer; } else if (!organizer.asBinder().equals(curOrganizer.asBinder())) { // They must be controlled by the same organizer. // We don't want the organizer to handle transition of other non-embedded Task. if (leafTask != null && leafTask != task) { return false; } final ActivityRecord rootActivity = task.getRootActivity(); // We don't want the organizer to handle transition when the whole app is closing. if (rootActivity == null) { return false; } // We don't want the organizer to handle transition of non-embedded activity of other // app. if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) { return false; } leafTask = task; } if (leafTask == null) { return false; } // We don't support remote animation for Task with multiple TaskFragmentOrganizers. final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1]; final boolean hasMultipleOrganizers = leafTask.forAllLeafTaskFragments(taskFragment -> { final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer(); if (tfOrganizer == null) { return false; } if (organizer[0] != null && !organizer[0].asBinder().equals(tfOrganizer.asBinder())) { return true; } organizer[0] = tfOrganizer; return false; }); if (hasMultipleOrganizers) { ProtoLog.e(WM_DEBUG_APP_TRANSITIONS, "We don't support remote animation for" + " Task with multiple TaskFragmentOrganizers."); return false; } final RemoteAnimationDefinition definition = organizer != null final RemoteAnimationDefinition definition = organizer[0] != null ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController .getRemoteAnimationDefinition(organizer) .getRemoteAnimationDefinition(organizer[0]) : null; final RemoteAnimationAdapter adapter = definition != null ? definition.getAdapter(transit, activityTypes) Loading services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +149 −27 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 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.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading @@ -44,6 +46,7 @@ import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.Nullable; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; Loading Loading @@ -763,59 +766,148 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() { // TaskFragmentOrganizer registers remote animation. public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final ITaskFragmentOrganizer iOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); setupTaskFragmentRemoteAnimation(organizer, adapter); // Create a TaskFragment with embedded activity. final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(createTask(mDisplayContent)) .createActivityCount(1) .setOrganizer(organizer) .build(); final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity( createTask(mDisplayContent), organizer); final ActivityRecord activity = taskFragment.getTopMostActivity(); activity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition for TaskFragment. mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); mDisplayContent.mOpeningApps.add(activity); mDisplayContent.mChangingContainers.add(taskFragment); mDisplayContent.mAppTransitionController.handleAppTransitionReady(); // Prepare a transition. prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); // Check if the transition has been overridden. final Task task = createTask(mDisplayContent); // Closing non-embedded activity. final ActivityRecord closingActivity = createActivityRecord(task); closingActivity.allDrawn = true; // Opening TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); final Task task = createTask(mDisplayContent); // Closing TaskFragment with embedded activity. final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord closingActivity = taskFragment1.getTopMostActivity(); closingActivity.allDrawn = true; closingActivity.info.applicationInfo.uid = 12345; // Opening TaskFragment with embedded activity with different UID. final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord openingActivity = taskFragment2.getTopMostActivity(); openingActivity.info.applicationInfo.uid = 54321; openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1); // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); // Closing activity in Task1. final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); closingActivity.allDrawn = true; // Opening TaskFragment with embedded activity in Task2. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity( createTask(mDisplayContent), organizer); final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition for TaskFragment. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); // Should not be overridden. verify(mDisplayContent.mAppTransition, never()) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); final Task task = createTask(mDisplayContent); // Closing TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord closingActivity = taskFragment.getTopMostActivity(); closingActivity.allDrawn = true; closingActivity.info.applicationInfo.uid = 12345; // Opening non-embedded activity with different UID. final ActivityRecord openingActivity = createActivityRecord(task); openingActivity.info.applicationInfo.uid = 54321; openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); // Should not be overridden verify(mDisplayContent.mAppTransition, never()) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testTransitionGoodToGoForTaskFragments() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final Task task = createTask(mDisplayContent); final TaskFragment changeTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) .createActivityCount(1) .setOrganizer(organizer) .build(); final TaskFragment changeTaskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) .setOrganizer(organizer) .build(); changeTaskFragment.getTopMostActivity().allDrawn = true; mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); mDisplayContent.mChangingContainers.add(changeTaskFragment); spyOn(mDisplayContent.mAppTransition); spyOn(emptyTaskFragment); mDisplayContent.mAppTransitionController.handleAppTransitionReady(); prepareAndTriggerAppTransition( null /* openingActivity */, null /* closingActivity*/, changeTaskFragment); // Transition not ready because there is an empty non-finishing TaskFragment. verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); Loading @@ -829,4 +921,34 @@ public class AppTransitionControllerTest extends WindowTestsBase { // removed. verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); } /** Registers remote animation for the organizer. */ private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, RemoteAnimationAdapter adapter) { final ITaskFragmentOrganizer iOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); } private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity, @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) { if (openingActivity != null) { mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); mDisplayContent.mOpeningApps.add(openingActivity); } if (closingActivity != null) { mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CLOSE, 0); mDisplayContent.mClosingApps.add(closingActivity); } if (changingTaskFragment != null) { mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); mDisplayContent.mChangingContainers.add(changingTaskFragment); } mDisplayContent.mAppTransitionController.handleAppTransitionReady(); } } No newline at end of file services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +9 −0 Original line number Diff line number Diff line Loading @@ -699,6 +699,15 @@ class WindowTestsBase extends SystemServiceTestsBase { return builder.build(); } static TaskFragment createTaskFragmentWithEmbeddedActivity(@NonNull Task parentTask, TaskFragmentOrganizer organizer) { return new TaskFragmentBuilder(parentTask.mAtmService) .setParentTask(parentTask) .createActivityCount(1) .setOrganizer(organizer) .build(); } /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL); Loading Loading
data/etc/services.core.protolog.json +6 −0 Original line number Diff line number Diff line Loading @@ -3505,6 +3505,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, "1805116444": { "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.", "level": "ERROR", "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, "1810019902": { "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", "level": "DEBUG", Loading
services/core/java/com/android/server/wm/AppTransitionController.java +56 −15 Original line number Diff line number Diff line Loading @@ -533,40 +533,81 @@ public class AppTransitionController { * * @return {@code true} if the transition is overridden. */ @VisibleForTesting boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit, ArraySet<Integer> activityTypes) { final ArrayList<WindowContainer> allWindows = new ArrayList<>(); allWindows.addAll(mDisplayContent.mClosingApps); allWindows.addAll(mDisplayContent.mOpeningApps); allWindows.addAll(mDisplayContent.mChangingContainers); // Find the common TaskFragmentOrganizer of all windows. ITaskFragmentOrganizer organizer = null; // It should only animated by the organizer if all windows are below the same leaf Task. Task leafTask = null; for (int i = allWindows.size() - 1; i >= 0; i--) { final ActivityRecord r = getAppFromContainer(allWindows.get(i)); if (r == null) { return false; } // The activity may be a child of embedded Task, but we want to find the owner Task. // As a result, find the organized TaskFragment first. final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null ? organizedTaskFragment.getTaskFragmentOrganizer() : null; if (curOrganizer == null) { // All windows must below an organized TaskFragment. // There are also cases where the Task contains non-embedded activity, such as launching // split TaskFragments from a non-embedded activity. // The hierarchy may looks like this: // - Task // - Activity // - TaskFragment // - Activity // - TaskFragment // - Activity // We also want to have the organizer handle the transition for such case. final Task task = organizedTaskFragment != null ? organizedTaskFragment.getTask() : r.getTask(); if (task == null) { return false; } if (organizer == null) { organizer = curOrganizer; } else if (!organizer.asBinder().equals(curOrganizer.asBinder())) { // They must be controlled by the same organizer. // We don't want the organizer to handle transition of other non-embedded Task. if (leafTask != null && leafTask != task) { return false; } final ActivityRecord rootActivity = task.getRootActivity(); // We don't want the organizer to handle transition when the whole app is closing. if (rootActivity == null) { return false; } // We don't want the organizer to handle transition of non-embedded activity of other // app. if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) { return false; } leafTask = task; } if (leafTask == null) { return false; } // We don't support remote animation for Task with multiple TaskFragmentOrganizers. final ITaskFragmentOrganizer[] organizer = new ITaskFragmentOrganizer[1]; final boolean hasMultipleOrganizers = leafTask.forAllLeafTaskFragments(taskFragment -> { final ITaskFragmentOrganizer tfOrganizer = taskFragment.getTaskFragmentOrganizer(); if (tfOrganizer == null) { return false; } if (organizer[0] != null && !organizer[0].asBinder().equals(tfOrganizer.asBinder())) { return true; } organizer[0] = tfOrganizer; return false; }); if (hasMultipleOrganizers) { ProtoLog.e(WM_DEBUG_APP_TRANSITIONS, "We don't support remote animation for" + " Task with multiple TaskFragmentOrganizers."); return false; } final RemoteAnimationDefinition definition = organizer != null final RemoteAnimationDefinition definition = organizer[0] != null ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController .getRemoteAnimationDefinition(organizer) .getRemoteAnimationDefinition(organizer[0]) : null; final RemoteAnimationAdapter adapter = definition != null ? definition.getAdapter(transit, activityTypes) Loading
services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +149 −27 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 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.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; Loading @@ -44,6 +46,7 @@ import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.annotation.Nullable; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; Loading Loading @@ -763,59 +766,148 @@ public class AppTransitionControllerTest extends WindowTestsBase { } @Test public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() { // TaskFragmentOrganizer registers remote animation. public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final ITaskFragmentOrganizer iOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); setupTaskFragmentRemoteAnimation(organizer, adapter); // Create a TaskFragment with embedded activity. final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(createTask(mDisplayContent)) .createActivityCount(1) .setOrganizer(organizer) .build(); final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity( createTask(mDisplayContent), organizer); final ActivityRecord activity = taskFragment.getTopMostActivity(); activity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition for TaskFragment. mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); mDisplayContent.mOpeningApps.add(activity); mDisplayContent.mChangingContainers.add(taskFragment); mDisplayContent.mAppTransitionController.handleAppTransitionReady(); // Prepare a transition. prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment); // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); // Check if the transition has been overridden. final Task task = createTask(mDisplayContent); // Closing non-embedded activity. final ActivityRecord closingActivity = createActivityRecord(task); closingActivity.allDrawn = true; // Opening TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); final Task task = createTask(mDisplayContent); // Closing TaskFragment with embedded activity. final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord closingActivity = taskFragment1.getTopMostActivity(); closingActivity.allDrawn = true; closingActivity.info.applicationInfo.uid = 12345; // Opening TaskFragment with embedded activity with different UID. final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord openingActivity = taskFragment2.getTopMostActivity(); openingActivity.info.applicationInfo.uid = 54321; openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1); // Should be overridden. verify(mDisplayContent.mAppTransition) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); // Closing activity in Task1. final ActivityRecord closingActivity = createActivityRecord(mDisplayContent); closingActivity.allDrawn = true; // Opening TaskFragment with embedded activity in Task2. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity( createTask(mDisplayContent), organizer); final ActivityRecord openingActivity = taskFragment.getTopMostActivity(); openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition for TaskFragment. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); // Should not be overridden. verify(mDisplayContent.mAppTransition, never()) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( new TestRemoteAnimationRunner(), 10, 1); setupTaskFragmentRemoteAnimation(organizer, adapter); final Task task = createTask(mDisplayContent); // Closing TaskFragment with embedded activity. final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final ActivityRecord closingActivity = taskFragment.getTopMostActivity(); closingActivity.allDrawn = true; closingActivity.info.applicationInfo.uid = 12345; // Opening non-embedded activity with different UID. final ActivityRecord openingActivity = createActivityRecord(task); openingActivity.info.applicationInfo.uid = 54321; openingActivity.allDrawn = true; spyOn(mDisplayContent.mAppTransition); // Prepare a transition. prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment); // Should not be overridden verify(mDisplayContent.mAppTransition, never()) .overridePendingAppTransitionRemote(adapter, false /* sync */); } @Test public void testTransitionGoodToGoForTaskFragments() { final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final Task task = createTask(mDisplayContent); final TaskFragment changeTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) .createActivityCount(1) .setOrganizer(organizer) .build(); final TaskFragment changeTaskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer); final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) .setParentTask(task) .setOrganizer(organizer) .build(); changeTaskFragment.getTopMostActivity().allDrawn = true; mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); mDisplayContent.mChangingContainers.add(changeTaskFragment); spyOn(mDisplayContent.mAppTransition); spyOn(emptyTaskFragment); mDisplayContent.mAppTransitionController.handleAppTransitionReady(); prepareAndTriggerAppTransition( null /* openingActivity */, null /* closingActivity*/, changeTaskFragment); // Transition not ready because there is an empty non-finishing TaskFragment. verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); Loading @@ -829,4 +921,34 @@ public class AppTransitionControllerTest extends WindowTestsBase { // removed. verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); } /** Registers remote animation for the organizer. */ private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, RemoteAnimationAdapter adapter) { final ITaskFragmentOrganizer iOrganizer = ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder()); final RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter); definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter); mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer); mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition); } private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity, @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) { if (openingActivity != null) { mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0); mDisplayContent.mOpeningApps.add(openingActivity); } if (closingActivity != null) { mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CLOSE, 0); mDisplayContent.mClosingApps.add(closingActivity); } if (changingTaskFragment != null) { mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); mDisplayContent.mChangingContainers.add(changingTaskFragment); } mDisplayContent.mAppTransitionController.handleAppTransitionReady(); } } No newline at end of file
services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +9 −0 Original line number Diff line number Diff line Loading @@ -699,6 +699,15 @@ class WindowTestsBase extends SystemServiceTestsBase { return builder.build(); } static TaskFragment createTaskFragmentWithEmbeddedActivity(@NonNull Task parentTask, TaskFragmentOrganizer organizer) { return new TaskFragmentBuilder(parentTask.mAtmService) .setParentTask(parentTask) .createActivityCount(1) .setOrganizer(organizer) .build(); } /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL); Loading