Merge "Allow organizer to handle transition for non-embedded activity" into sc-v2-dev

This commit is contained in:
Chris Li
2021-09-30 23:07:40 +00:00
committed by Android (Google) Code Review
4 changed files with 220 additions and 42 deletions

View File

@@ -3505,6 +3505,12 @@
"group": "WM_ERROR", "group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java" "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": { "1810019902": {
"message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps",
"level": "DEBUG", "level": "DEBUG",

View File

@@ -533,40 +533,81 @@ public class AppTransitionController {
* *
* @return {@code true} if the transition is overridden. * @return {@code true} if the transition is overridden.
*/ */
@VisibleForTesting private boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
ArraySet<Integer> activityTypes) { ArraySet<Integer> activityTypes) {
final ArrayList<WindowContainer> allWindows = new ArrayList<>(); final ArrayList<WindowContainer> allWindows = new ArrayList<>();
allWindows.addAll(mDisplayContent.mClosingApps); allWindows.addAll(mDisplayContent.mClosingApps);
allWindows.addAll(mDisplayContent.mOpeningApps); allWindows.addAll(mDisplayContent.mOpeningApps);
allWindows.addAll(mDisplayContent.mChangingContainers); allWindows.addAll(mDisplayContent.mChangingContainers);
// Find the common TaskFragmentOrganizer of all windows. // It should only animated by the organizer if all windows are below the same leaf Task.
ITaskFragmentOrganizer organizer = null; Task leafTask = null;
for (int i = allWindows.size() - 1; i >= 0; i--) { for (int i = allWindows.size() - 1; i >= 0; i--) {
final ActivityRecord r = getAppFromContainer(allWindows.get(i)); final ActivityRecord r = getAppFromContainer(allWindows.get(i));
if (r == null) { if (r == null) {
return false; 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 TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null // There are also cases where the Task contains non-embedded activity, such as launching
? organizedTaskFragment.getTaskFragmentOrganizer() // split TaskFragments from a non-embedded activity.
: null; // The hierarchy may looks like this:
if (curOrganizer == null) { // - Task
// All windows must below an organized TaskFragment. // - 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; return false;
} }
if (organizer == null) { // We don't want the organizer to handle transition of other non-embedded Task.
organizer = curOrganizer; if (leafTask != null && leafTask != task) {
} else if (!organizer.asBinder().equals(curOrganizer.asBinder())) {
// They must be controlled by the same organizer.
return false; 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;
} }
final RemoteAnimationDefinition definition = organizer != null // 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[0] != null
? mDisplayContent.mAtmService.mTaskFragmentOrganizerController ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
.getRemoteAnimationDefinition(organizer) .getRemoteAnimationDefinition(organizer[0])
: null; : null;
final RemoteAnimationAdapter adapter = definition != null final RemoteAnimationAdapter adapter = definition != null
? definition.getAdapter(transit, activityTypes) ? definition.getAdapter(transit, activityTypes)

View File

@@ -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_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; 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_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_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -44,6 +46,7 @@ import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.annotation.Nullable;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@@ -763,59 +766,148 @@ public class AppTransitionControllerTest extends WindowTestsBase {
} }
@Test @Test
public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() { public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
// TaskFragmentOrganizer registers remote animation.
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); 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( final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
new TestRemoteAnimationRunner(), 10, 1); new TestRemoteAnimationRunner(), 10, 1);
definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter); setupTaskFragmentRemoteAnimation(organizer, adapter);
mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
// Create a TaskFragment with embedded activity. // Create a TaskFragment with embedded activity.
final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm) final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(
.setParentTask(createTask(mDisplayContent)) createTask(mDisplayContent), organizer);
.createActivityCount(1)
.setOrganizer(organizer)
.build();
final ActivityRecord activity = taskFragment.getTopMostActivity(); final ActivityRecord activity = taskFragment.getTopMostActivity();
activity.allDrawn = true; activity.allDrawn = true;
spyOn(mDisplayContent.mAppTransition); spyOn(mDisplayContent.mAppTransition);
// Prepare a transition for TaskFragment. // Prepare a transition.
mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0); prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
mDisplayContent.mOpeningApps.add(activity);
mDisplayContent.mChangingContainers.add(taskFragment);
mDisplayContent.mAppTransitionController.handleAppTransitionReady();
// Check if the transition has been overridden. // Should be overridden.
verify(mDisplayContent.mAppTransition) verify(mDisplayContent.mAppTransition)
.overridePendingAppTransitionRemote(adapter, false /* sync */); .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);
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 @Test
public void testTransitionGoodToGoForTaskFragments() { public void testTransitionGoodToGoForTaskFragments() {
final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run); final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
final Task task = createTask(mDisplayContent); final Task task = createTask(mDisplayContent);
final TaskFragment changeTaskFragment = new TaskFragmentBuilder(mAtm) final TaskFragment changeTaskFragment =
.setParentTask(task) createTaskFragmentWithEmbeddedActivity(task, organizer);
.createActivityCount(1)
.setOrganizer(organizer)
.build();
final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm) final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm)
.setParentTask(task) .setParentTask(task)
.setOrganizer(organizer) .setOrganizer(organizer)
.build(); .build();
changeTaskFragment.getTopMostActivity().allDrawn = true; changeTaskFragment.getTopMostActivity().allDrawn = true;
mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0);
mDisplayContent.mChangingContainers.add(changeTaskFragment);
spyOn(mDisplayContent.mAppTransition); spyOn(mDisplayContent.mAppTransition);
spyOn(emptyTaskFragment); spyOn(emptyTaskFragment);
mDisplayContent.mAppTransitionController.handleAppTransitionReady(); prepareAndTriggerAppTransition(
null /* openingActivity */, null /* closingActivity*/, changeTaskFragment);
// Transition not ready because there is an empty non-finishing TaskFragment. // Transition not ready because there is an empty non-finishing TaskFragment.
verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any()); verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any());
@@ -829,4 +921,34 @@ public class AppTransitionControllerTest extends WindowTestsBase {
// removed. // removed.
verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any()); 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();
}
} }

View File

@@ -699,6 +699,15 @@ class WindowTestsBase extends SystemServiceTestsBase {
return builder.build(); 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. */ /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay() { DisplayContent createNewDisplay() {
return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL); return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL);