Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53c6e51e authored by Chris Li's avatar Chris Li Committed by Automerger Merge Worker
Browse files

Merge "Allow organizer to handle transition for non-embedded activity" into...

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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15897563

Change-Id: Ief6e9a51f7d5d9671e6f1c0ca25a369aa674ed5b
parents 68c4642b fe71e802
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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",
+56 −15
Original line number Diff line number Diff line
@@ -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)
+149 −27
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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());
@@ -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
+9 −0
Original line number Diff line number Diff line
@@ -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);