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

Commit 88967a1f authored by Automerger Merge Worker's avatar Automerger Merge Worker Committed by Android (Google) Code Review
Browse files

Merge "Merge "Add pendingAppearedIntent to TaskFragmentContainer" into tm-dev...

Merge "Merge "Add pendingAppearedIntent to TaskFragmentContainer" into tm-dev am: 3f75b048 am: 7c720649"
parents d0916103 93ab6e73
Loading
Loading
Loading
Loading
+40 −19
Original line number Diff line number Diff line
@@ -530,11 +530,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen

        if (container == splitContainer.getPrimaryContainer()) {
            // The new launched can be in the primary container when it is starting a new activity
            // onCreate, thus the secondary may still be empty.
            // onCreate.
            final TaskFragmentContainer secondaryContainer = splitContainer.getSecondaryContainer();
            final Intent secondaryIntent = secondaryContainer.getPendingAppearedIntent();
            if (secondaryIntent != null) {
                // Check with the pending Intent before it is started on the server side.
                // This can happen if the launched Activity start a new Intent to secondary during
                // #onCreated().
                return getSplitRule(launchedActivity, secondaryIntent) != null;
            }
            final Activity secondaryActivity = secondaryContainer.getTopNonFinishingActivity();
            return secondaryActivity == null
                    || getSplitRule(launchedActivity, secondaryActivity) != null;
            return secondaryActivity != null
                    && getSplitRule(launchedActivity, secondaryActivity) != null;
        }

        // Check if the new launched activity is a placeholder.
@@ -573,7 +580,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        Activity activityBelow = null;
        final TaskFragmentContainer container = getContainerWithActivity(activity);
        if (container != null) {
            final List<Activity> containerActivities = container.collectActivities();
            final List<Activity> containerActivities = container.collectNonFinishingActivities();
            final int index = containerActivities.indexOf(activity);
            if (index > 0) {
                activityBelow = containerActivities.get(index - 1);
@@ -691,7 +698,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen

        // 1. Whether the new activity intent should always expand.
        if (shouldExpand(null /* activity */, intent)) {
            return createEmptyExpandedContainer(wct, taskId, launchingActivity);
            return createEmptyExpandedContainer(wct, intent, taskId, launchingActivity);
        }

        // 2. Whether the launching activity (if set) should be split with the new activity intent.
@@ -742,7 +749,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     */
    @Nullable
    private TaskFragmentContainer createEmptyExpandedContainer(
            @NonNull WindowContainerTransaction wct, int taskId,
            @NonNull WindowContainerTransaction wct, @NonNull Intent intent, int taskId,
            @Nullable Activity launchingActivity) {
        // We need an activity in the organizer process in the same Task to use as the owner
        // activity, as well as to get the Task window info.
@@ -759,8 +766,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            // Can't find any activity in the Task that we can use as the owner activity.
            return null;
        }
        final TaskFragmentContainer expandedContainer = newContainer(null /* activity */,
                activityInTask, taskId);
        final TaskFragmentContainer expandedContainer = newContainer(intent, activityInTask,
                taskId);
        mPresenter.createTaskFragment(wct, expandedContainer.getTaskFragmentToken(),
                activityInTask.getActivityToken(), new Rect(), WINDOWING_MODE_UNDEFINED);
        return expandedContainer;
@@ -789,7 +796,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return splitContainer.getSecondaryContainer();
        }
        // Create a new TaskFragment to split with the primary activity for the new activity.
        return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, splitRule);
        return mPresenter.createNewSplitWithEmptySideContainer(wct, primaryActivity, intent,
                splitRule);
    }

    /**
@@ -813,21 +821,34 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        return null;
    }

    TaskFragmentContainer newContainer(@NonNull Activity activity, int taskId) {
        return newContainer(activity, activity, taskId);
    TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity, int taskId) {
        return newContainer(pendingAppearedActivity, pendingAppearedActivity, taskId);
    }

    TaskFragmentContainer newContainer(@NonNull Activity pendingAppearedActivity,
            @NonNull Activity activityInTask, int taskId) {
        return newContainer(pendingAppearedActivity, null /* pendingAppearedIntent */,
                activityInTask, taskId);
    }

    TaskFragmentContainer newContainer(@NonNull Intent pendingAppearedIntent,
            @NonNull Activity activityInTask, int taskId) {
        return newContainer(null /* pendingAppearedActivity */, pendingAppearedIntent,
                activityInTask, taskId);
    }

    /**
     * Creates and registers a new organized container with an optional activity that will be
     * re-parented to it in a WCT.
     *
     * @param activity          the activity that will be reparented to the TaskFragment.
     * @param activityInTask    activity in the same Task so that we can get the Task bounds if
     *                          needed.
     * @param pendingAppearedActivity   the activity that will be reparented to the TaskFragment.
     * @param pendingAppearedIntent     the Intent that will be started in the TaskFragment.
     * @param activityInTask            activity in the same Task so that we can get the Task bounds
     *                                  if needed.
     * @param taskId                    parent Task of the new TaskFragment.
     */
    TaskFragmentContainer newContainer(@Nullable Activity activity,
            @NonNull Activity activityInTask, int taskId) {
    TaskFragmentContainer newContainer(@Nullable Activity pendingAppearedActivity,
            @Nullable Intent pendingAppearedIntent, @NonNull Activity activityInTask, int taskId) {
        if (activityInTask == null) {
            throw new IllegalArgumentException("activityInTask must not be null,");
        }
@@ -835,8 +856,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            mTaskContainers.put(taskId, new TaskContainer(taskId));
        }
        final TaskContainer taskContainer = mTaskContainers.get(taskId);
        final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskContainer,
                this);
        final TaskFragmentContainer container = new TaskFragmentContainer(pendingAppearedActivity,
                pendingAppearedIntent, taskContainer, this);
        if (!taskContainer.isTaskBoundsInitialized()) {
            // Get the initial bounds before the TaskFragment has appeared.
            final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask);
+3 −3
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
    @NonNull
    TaskFragmentContainer createNewSplitWithEmptySideContainer(
            @NonNull WindowContainerTransaction wct, @NonNull Activity primaryActivity,
            @NonNull SplitPairRule rule) {
            @NonNull Intent secondaryIntent, @NonNull SplitPairRule rule) {
        final Rect parentBounds = getParentContainerBounds(primaryActivity);
        final Rect primaryRectBounds = getBoundsForPosition(POSITION_START, parentBounds, rule,
                isLtr(primaryActivity, rule));
@@ -111,7 +111,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
        // Create new empty task fragment
        final int taskId = primaryContainer.getTaskId();
        final TaskFragmentContainer secondaryContainer = mController.newContainer(
                null /* activity */, primaryActivity, taskId);
                secondaryIntent, primaryActivity, taskId);
        final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
                rule, isLtr(primaryActivity, rule));
        final int windowingMode = mController.getTaskContainer(taskId)
@@ -224,7 +224,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
        }

        final int taskId = primaryContainer.getTaskId();
        TaskFragmentContainer secondaryContainer = mController.newContainer(null /* activity */,
        final TaskFragmentContainer secondaryContainer = mController.newContainer(activityIntent,
                launchingActivity, taskId);
        final int windowingMode = mController.getTaskContainer(taskId)
                .getWindowingModeForSplitTaskFragment(primaryRectBounds);
+45 −21
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
@@ -64,7 +65,16 @@ class TaskFragmentContainer {
     * Activities that are being reparented or being started to this container, but haven't been
     * added to {@link #mInfo} yet.
     */
    private final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
    @VisibleForTesting
    final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();

    /**
     * When this container is created for an {@link Intent} to start within, we store that Intent
     * until the container becomes non-empty on the server side, so that we can use it to check
     * rules associated with this container.
     */
    @Nullable
    private Intent mPendingAppearedIntent;

    /** Containers that are dependent on this one and should be completely destroyed on exit. */
    private final List<TaskFragmentContainer> mContainersToFinishOnExit =
@@ -99,15 +109,22 @@ class TaskFragmentContainer {
     * Creates a container with an existing activity that will be re-parented to it in a window
     * container transaction.
     */
    TaskFragmentContainer(@Nullable Activity activity, @NonNull TaskContainer taskContainer,
    TaskFragmentContainer(@Nullable Activity pendingAppearedActivity,
            @Nullable Intent pendingAppearedIntent, @NonNull TaskContainer taskContainer,
            @NonNull SplitController controller) {
        if ((pendingAppearedActivity == null && pendingAppearedIntent == null)
                || (pendingAppearedActivity != null && pendingAppearedIntent != null)) {
            throw new IllegalArgumentException(
                    "One and only one of pending activity and intent must be non-null");
        }
        mController = controller;
        mToken = new Binder("TaskFragmentContainer");
        mTaskContainer = taskContainer;
        taskContainer.mContainers.add(this);
        if (activity != null) {
            addPendingAppearedActivity(activity);
        if (pendingAppearedActivity != null) {
            addPendingAppearedActivity(pendingAppearedActivity);
        }
        mPendingAppearedIntent = pendingAppearedIntent;
    }

    /**
@@ -118,9 +135,9 @@ class TaskFragmentContainer {
        return mToken;
    }

    /** List of activities that belong to this container and live in this process. */
    /** List of non-finishing activities that belong to this container and live in this process. */
    @NonNull
    List<Activity> collectActivities() {
    List<Activity> collectNonFinishingActivities() {
        final List<Activity> allActivities = new ArrayList<>();
        if (mInfo != null) {
            // Add activities reported from the server.
@@ -154,13 +171,14 @@ class TaskFragmentContainer {
            return false;
        }
        return mPendingAppearedActivities.isEmpty()
                && mInfo.getActivities().size() == collectActivities().size();
                && mInfo.getActivities().size() == collectNonFinishingActivities().size();
    }

    ActivityStack toActivityStack() {
        return new ActivityStack(collectActivities(), isEmpty());
        return new ActivityStack(collectNonFinishingActivities(), isEmpty());
    }

    /** Adds the activity that will be reparented to this container. */
    void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
        if (hasActivity(pendingAppearedActivity.getActivityToken())) {
            return;
@@ -174,6 +192,11 @@ class TaskFragmentContainer {
        mPendingAppearedActivities.remove(pendingAppearedActivity);
    }

    @Nullable
    Intent getPendingAppearedIntent() {
        return mPendingAppearedIntent;
    }

    boolean hasActivity(@NonNull IBinder token) {
        if (mInfo != null && mInfo.getActivities().contains(token)) {
            return true;
@@ -219,7 +242,12 @@ class TaskFragmentContainer {
        }

        mInfo = info;
        if (mInfo == null || mPendingAppearedActivities.isEmpty()) {
        if (mInfo == null || mInfo.isEmpty()) {
            return;
        }
        // Only track the pending Intent when the container is empty.
        mPendingAppearedIntent = null;
        if (mPendingAppearedActivities.isEmpty()) {
            return;
        }
        // Cleanup activities that were being re-parented
@@ -234,20 +262,13 @@ class TaskFragmentContainer {

    @Nullable
    Activity getTopNonFinishingActivity() {
        List<Activity> activities = collectActivities();
        if (activities.isEmpty()) {
            return null;
        }
        int i = activities.size() - 1;
        while (i >= 0 && activities.get(i).isFinishing()) {
            i--;
        }
        return i >= 0 ? activities.get(i) : null;
        final List<Activity> activities = collectNonFinishingActivities();
        return activities.isEmpty() ? null : activities.get(activities.size() - 1);
    }

    @Nullable
    Activity getBottomMostActivity() {
        final List<Activity> activities = collectActivities();
        final List<Activity> activities = collectNonFinishingActivities();
        return activities.isEmpty() ? null : activities.get(0);
    }

@@ -320,8 +341,11 @@ class TaskFragmentContainer {
    private void finishActivities(boolean shouldFinishDependent, @NonNull SplitPresenter presenter,
            @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
        // Finish own activities
        for (Activity activity : collectActivities()) {
            if (!activity.isFinishing()) {
        for (Activity activity : collectNonFinishingActivities()) {
            if (!activity.isFinishing()
                    // In case we have requested to reparent the activity to another container (as
                    // pendingAppeared), we don't want to finish it with this container.
                    && mController.getContainerWithActivity(activity) == this) {
                activity.finish();
            }
        }
+2 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;

import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Handler;
@@ -115,7 +116,7 @@ public class JetpackTaskFragmentOrganizerTest {
    public void testExpandTaskFragment() {
        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
        final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
                taskContainer, mSplitController);
                new Intent(), taskContainer, mSplitController);
        final TaskFragmentInfo info = createMockInfo(container);
        mOrganizer.mFragmentInfos.put(container.getTaskFragmentToken(), info);
        container.setInfo(info);
+34 −8
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ public class SplitControllerTest {
        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
        // tf1 has no running activity so is not active.
        final TaskFragmentContainer tf1 = new TaskFragmentContainer(null /* activity */,
                taskContainer, mSplitController);
                new Intent(), taskContainer, mSplitController);
        // tf2 has running activity so is active.
        final TaskFragmentContainer tf2 = mock(TaskFragmentContainer.class);
        doReturn(1).when(tf2).getRunningActivityCount();
@@ -205,7 +205,8 @@ public class SplitControllerTest {
        assertThrows(IllegalArgumentException.class, () ->
                mSplitController.newContainer(mActivity, null /* launchingActivity */, TASK_ID));

        final TaskFragmentContainer tf = mSplitController.newContainer(null, mActivity, TASK_ID);
        final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, mActivity,
                TASK_ID);
        final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);

        assertNotNull(tf);
@@ -307,7 +308,7 @@ public class SplitControllerTest {
    @Test
    public void testOnActivityReparentToTask_diffProcess() {
        // Create an empty TaskFragment to initialize for the Task.
        mSplitController.newContainer(null, mActivity, TASK_ID);
        mSplitController.newContainer(new Intent(), mActivity, TASK_ID);
        final IBinder activityToken = new Binder();
        final Intent intent = new Intent();

@@ -417,7 +418,7 @@ public class SplitControllerTest {

        verify(mSplitPresenter, never()).applyTransaction(any());

        mSplitController.newContainer(null /* activity */, mActivity, TASK_ID);
        mSplitController.newContainer(new Intent(), mActivity, TASK_ID);
        mSplitController.placeActivityInTopContainer(mActivity);

        verify(mSplitPresenter).applyTransaction(any());
@@ -436,7 +437,7 @@ public class SplitControllerTest {
                false /* isOnReparent */);

        assertFalse(result);
        verify(mSplitController, never()).newContainer(any(), any(), anyInt());
        verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt());
    }

    @Test
@@ -577,7 +578,7 @@ public class SplitControllerTest {
        final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity,
                TASK_ID);
        final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(
                null /* activity */, mActivity, TASK_ID);
                secondaryIntent, mActivity, TASK_ID);
        mSplitController.registerSplit(
                mTransaction,
                primaryContainer,
@@ -589,10 +590,35 @@ public class SplitControllerTest {
                false /* isOnReparent */);

        assertTrue(result);
        verify(mSplitController, never()).newContainer(any(), any(), anyInt());
        verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt());
        verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any());
    }

    @Test
    public void testResolveActivityToContainer_splitRule_inPrimarySplitWithNoRuleMatched() {
        final Intent secondaryIntent = new Intent();
        setupSplitRule(mActivity, secondaryIntent);
        final SplitPairRule splitRule = (SplitPairRule) mSplitController.getSplitRules().get(0);

        // The new launched activity is in primary split, but there is no rule for it to split with
        // the secondary, so return false.
        final TaskFragmentContainer primaryContainer = mSplitController.newContainer(mActivity,
                TASK_ID);
        final TaskFragmentContainer secondaryContainer = mSplitController.newContainer(
                secondaryIntent, mActivity, TASK_ID);
        mSplitController.registerSplit(
                mTransaction,
                primaryContainer,
                mActivity,
                secondaryContainer,
                splitRule);
        final Activity launchedActivity = createMockActivity();
        primaryContainer.addPendingAppearedActivity(launchedActivity);

        assertFalse(mSplitController.resolveActivityToContainer(launchedActivity,
                false /* isOnReparent */));
    }

    @Test
    public void testResolveActivityToContainer_splitRule_inSecondarySplitWithRuleMatched() {
        final Activity primaryActivity = createMockActivity();
@@ -605,7 +631,7 @@ public class SplitControllerTest {
                false /* isOnReparent */);

        assertTrue(result);
        verify(mSplitController, never()).newContainer(any(), any(), anyInt());
        verify(mSplitController, never()).newContainer(any(), any(), any(), anyInt());
        verify(mSplitController, never()).registerSplit(any(), any(), any(), any(), any());
    }

Loading