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

Commit 9e8e731f authored by Louis Chang's avatar Louis Chang
Browse files

Avoid resolving split for activities that requested launching TF

The launching activity is resolved to the existing split rules
before invokes #startActivity and also when the activity is created.

However, this is not necessary if the app has requested the activity
to be launched into a specific TaskFragment in the first place.

Bug: 267955577
Test: verified on demo app
Test: SplitControllerTest
Change-Id: If61ad7bc5309a7adffff580d87a7d38aae65b0c6
parent 1a078491
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3733,6 +3733,7 @@ package android.window {
  public final class TaskFragmentInfo implements android.os.Parcelable {
    method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo);
    method @NonNull public java.util.List<android.os.IBinder> getActivities();
    method @NonNull public java.util.List<android.os.IBinder> getActivitiesRequestedInTaskFragment();
    method @NonNull public android.content.res.Configuration getConfiguration();
    method @NonNull public android.os.IBinder getFragmentToken();
    method @NonNull public android.graphics.Point getPositionInParent();
+17 −0
Original line number Diff line number Diff line
@@ -597,6 +597,23 @@ public class ActivityClient {
        }
    }

    /**
     * Returns {@code true} if the activity was explicitly requested to be launched in the
     * TaskFragment.
     *
     * @param activityToken The token of the Activity.
     * @param taskFragmentToken The token of the TaskFragment.
     */
    public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken,
            IBinder taskFragmentToken) {
        try {
            return getActivityClientController().isRequestedToLaunchInTaskFragment(activityToken,
                    taskFragmentToken);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Shows or hides a Camera app compat toggle for stretched issues with the requested state.
     *
+10 −0
Original line number Diff line number Diff line
@@ -181,4 +181,14 @@ interface IActivityClientController {
     * that started the task.
     */
    void enableTaskLocaleOverride(in IBinder token);

    /**
     * Return {@code true} if the activity was explicitly requested to be launched in the
     * TaskFragment.
     *
     * @param activityToken The token of the Activity.
     * @param taskFragmentToken The token of the TaskFragment.
     */
    boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken,
            in IBinder taskFragmentToken);
}
+23 −3
Original line number Diff line number Diff line
@@ -66,6 +66,13 @@ public final class TaskFragmentInfo implements Parcelable {
    @NonNull
    private final List<IBinder> mActivities = new ArrayList<>();

    /**
     * List of Activity tokens that were explicitly requested to be launched in this TaskFragment.
     * It only contains Activities that belong to the organizer process for security.
     */
    @NonNull
    private final List<IBinder> mInRequestedTaskFragmentActivities = new ArrayList<>();

    /** Relative position of the fragment's top left corner in the parent container. */
    private final Point mPositionInParent = new Point();

@@ -99,15 +106,18 @@ public final class TaskFragmentInfo implements Parcelable {
    public TaskFragmentInfo(
            @NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
            @NonNull Configuration configuration, int runningActivityCount,
            boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
            boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
            boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions) {
            boolean isVisible, @NonNull List<IBinder> activities,
            @NonNull List<IBinder> inRequestedTaskFragmentActivities,
            @NonNull Point positionInParent, boolean isTaskClearedForReuse,
            boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront,
            @NonNull Point minimumDimensions) {
        mFragmentToken = requireNonNull(fragmentToken);
        mToken = requireNonNull(token);
        mConfiguration.setTo(configuration);
        mRunningActivityCount = runningActivityCount;
        mIsVisible = isVisible;
        mActivities.addAll(activities);
        mInRequestedTaskFragmentActivities.addAll(inRequestedTaskFragmentActivities);
        mPositionInParent.set(positionInParent);
        mIsTaskClearedForReuse = isTaskClearedForReuse;
        mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
@@ -151,6 +161,11 @@ public final class TaskFragmentInfo implements Parcelable {
        return mActivities;
    }

    @NonNull
    public List<IBinder> getActivitiesRequestedInTaskFragment() {
        return mInRequestedTaskFragmentActivities;
    }

    /** Returns the relative position of the fragment's top left corner in the parent container. */
    @NonNull
    public Point getPositionInParent() {
@@ -215,6 +230,8 @@ public final class TaskFragmentInfo implements Parcelable {
                && mIsVisible == that.mIsVisible
                && getWindowingMode() == that.getWindowingMode()
                && mActivities.equals(that.mActivities)
                && mInRequestedTaskFragmentActivities.equals(
                        that.mInRequestedTaskFragmentActivities)
                && mPositionInParent.equals(that.mPositionInParent)
                && mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
                && mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
@@ -229,6 +246,7 @@ public final class TaskFragmentInfo implements Parcelable {
        mRunningActivityCount = in.readInt();
        mIsVisible = in.readBoolean();
        in.readBinderList(mActivities);
        in.readBinderList(mInRequestedTaskFragmentActivities);
        mPositionInParent.readFromParcel(in);
        mIsTaskClearedForReuse = in.readBoolean();
        mIsTaskFragmentClearedForPip = in.readBoolean();
@@ -245,6 +263,7 @@ public final class TaskFragmentInfo implements Parcelable {
        dest.writeInt(mRunningActivityCount);
        dest.writeBoolean(mIsVisible);
        dest.writeBinderList(mActivities);
        dest.writeBinderList(mInRequestedTaskFragmentActivities);
        mPositionInParent.writeToParcel(dest, flags);
        dest.writeBoolean(mIsTaskClearedForReuse);
        dest.writeBoolean(mIsTaskFragmentClearedForPip);
@@ -274,6 +293,7 @@ public final class TaskFragmentInfo implements Parcelable {
                + " runningActivityCount=" + mRunningActivityCount
                + " isVisible=" + mIsVisible
                + " activities=" + mActivities
                + " inRequestedTaskFragmentActivities" + mInRequestedTaskFragmentActivities
                + " positionInParent=" + mPositionInParent
                + " isTaskClearedForReuse=" + mIsTaskClearedForReuse
                + " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip
+28 −2
Original line number Diff line number Diff line
@@ -748,8 +748,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    @GuardedBy("mLock")
    void onActivityCreated(@NonNull WindowContainerTransaction wct,
            @NonNull Activity launchedActivity) {
        // TODO(b/229680885): we don't support launching into primary yet because we want to always
        // launch the new activity on top.
        resolveActivityToContainer(wct, launchedActivity, false /* isOnReparent */);
        updateCallbackIfNecessary();
    }
@@ -785,6 +783,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return true;
        }

        final TaskFragmentContainer container = getContainerWithActivity(activity);
        if (!isOnReparent && container != null
                && container.getTaskContainer().getTopTaskFragmentContainer() != container) {
            // Do not resolve if the launched activity is not the top-most container in the Task.
            return true;
        }

        /*
         * We will check the following to see if there is any embedding rule matched:
         * 1. Whether the new launched activity should always expand.
@@ -807,6 +812,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            return true;
        }

        // Skip resolving the following split-rules if the launched activity has been requested
        // to be launched into its current container.
        if (container != null && container.isActivityInRequestedTaskFragment(
                activity.getActivityToken())) {
            return true;
        }

        // 3. Whether the new launched activity has already been in a split with a rule matched.
        if (isNewActivityInSplitWithRuleMatched(activity)) {
            return true;
@@ -2060,6 +2072,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                        if (!container.hasActivity(activityToken)
                                && container.getTaskFragmentToken()
                                .equals(initialTaskFragmentToken)) {
                            if (ActivityClient.getInstance().isRequestedToLaunchInTaskFragment(
                                    activityToken, initialTaskFragmentToken)) {
                                container.addPendingAppearedInRequestedTaskFragmentActivity(
                                        activity);
                            }

                            // The onTaskFragmentInfoChanged callback containing this activity has
                            // not reached the client yet, so add the activity to the pending
                            // appeared activities.
@@ -2151,6 +2169,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
            // TODO(b/232042367): Consolidate the activity create handling so that we can handle
            // cross-process the same as normal.

            // Early return if the launching taskfragment is already been set.
            if (options.getBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN) != null) {
                synchronized (mLock) {
                    mCurrentIntent = intent;
                }
                return super.onStartActivity(who, intent, options);
            }

            final Activity launchingActivity;
            if (who instanceof Activity) {
                // We will check if the new activity should be split with the activity that launched
Loading