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

Commit 8b1e40a1 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Add ability to disable launch-adjacent for a specific root task" into main

parents a85ddc54 faff9bd1
Loading
Loading
Loading
Loading
+51 −3
Original line number Diff line number Diff line
@@ -524,6 +524,22 @@ public final class WindowContainerTransaction implements Parcelable {
        return this;
    }

    /**
     * Disables or enables activities to be started in adjacent tasks (see
     * {@link FLAG_ACTIVITY_LAUNCH_ADJACENT}) for the specified root of any child tasks.  This
     * differs from {@link #setLaunchAdjacentFlagRoot(WindowContainerToken)} which controls the
     * preferred launch-adjacent target and allows for selectively setting which root tasks can
     * support launch-adjacent.
     * @hide
     */
    @NonNull
    public WindowContainerTransaction setDisableLaunchAdjacent(
            @NonNull WindowContainerToken container, boolean disabled) {
        mHierarchyOps.add(HierarchyOp.createForSetDisableLaunchAdjacent(container.asBinder(),
                disabled));
        return this;
    }

    /**
     * Starts a task by id. The task is expected to already exist (eg. as a recent task).
     * @param taskId Id of task to start.
@@ -1488,6 +1504,7 @@ public final class WindowContainerTransaction implements Parcelable {
        public static final int HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION = 20;
        public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21;
        public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22;
        public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23;

        // The following key(s) are for use with mLaunchOptions:
        // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1556,6 +1573,8 @@ public final class WindowContainerTransaction implements Parcelable {

        private @InsetsType int mExcludeInsetsTypes;

        private boolean mLaunchAdjacentDisabled;

        public static HierarchyOp createForReparent(
                @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
@@ -1644,6 +1663,15 @@ public final class WindowContainerTransaction implements Parcelable {
                    .build();
        }

        /** Create a hierarchy op for disabling launch adjacent. */
        public static HierarchyOp createForSetDisableLaunchAdjacent(IBinder container,
                boolean disabled) {
            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT)
                    .setContainer(container)
                    .setLaunchAdjacentDisabled(disabled)
                    .build();
        }

        /** create a hierarchy op for deleting a task **/
        public static HierarchyOp createForRemoveTask(@NonNull IBinder container) {
            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK)
@@ -1695,6 +1723,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch;
            mIsTrimmableFromRecents = copy.mIsTrimmableFromRecents;
            mExcludeInsetsTypes = copy.mExcludeInsetsTypes;
            mLaunchAdjacentDisabled = copy.mLaunchAdjacentDisabled;
        }

        protected HierarchyOp(Parcel in) {
@@ -1719,6 +1748,7 @@ public final class WindowContainerTransaction implements Parcelable {
            mReparentLeafTaskIfRelaunch = in.readBoolean();
            mIsTrimmableFromRecents = in.readBoolean();
            mExcludeInsetsTypes = in.readInt();
            mLaunchAdjacentDisabled = in.readBoolean();
        }

        public int getType() {
@@ -1814,13 +1844,11 @@ public final class WindowContainerTransaction implements Parcelable {
        }

        /** Denotes whether the parents should also be included in the op. */
        @NonNull
        public boolean includingParents() {
            return mIncludingParents;
        }

        /** Set the task to be trimmable */
        @NonNull
        /** Denotes whether the task can be trimmable from recents */
        public boolean isTrimmableFromRecents() {
            return mIsTrimmableFromRecents;
        }
@@ -1829,6 +1857,11 @@ public final class WindowContainerTransaction implements Parcelable {
            return mExcludeInsetsTypes;
        }

        /** Denotes whether launch-adjacent flag is respected from this task or its children */
        public boolean isLaunchAdjacentDisabled() {
            return mLaunchAdjacentDisabled;
        }

        /** Gets a string representation of a hierarchy-op type. */
        public static String hopToString(int type) {
            switch (type) {
@@ -1839,6 +1872,8 @@ public final class WindowContainerTransaction implements Parcelable {
                case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: return "SetAdjacentRoot";
                case HIERARCHY_OP_TYPE_LAUNCH_TASK: return "LaunchTask";
                case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: return "SetAdjacentFlagRoot";
                case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
                    return "SetDisableLaunchAdjacent";
                case HIERARCHY_OP_TYPE_PENDING_INTENT: return "PendingIntent";
                case HIERARCHY_OP_TYPE_START_SHORTCUT: return "StartShortcut";
                case HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER: return "addInsetsFrameProvider";
@@ -1891,6 +1926,10 @@ public final class WindowContainerTransaction implements Parcelable {
                case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT:
                    sb.append("container=").append(mContainer).append(" clearRoot=").append(mToTop);
                    break;
                case HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT:
                    sb.append("container=").append(mContainer).append(" disabled=")
                            .append(mLaunchAdjacentDisabled);
                    break;
                case HIERARCHY_OP_TYPE_START_SHORTCUT:
                    sb.append("options=").append(mLaunchOptions)
                            .append(" info=").append(mShortcutInfo);
@@ -1971,6 +2010,7 @@ public final class WindowContainerTransaction implements Parcelable {
            dest.writeBoolean(mReparentLeafTaskIfRelaunch);
            dest.writeBoolean(mIsTrimmableFromRecents);
            dest.writeInt(mExcludeInsetsTypes);
            dest.writeBoolean(mLaunchAdjacentDisabled);
        }

        @Override
@@ -2047,6 +2087,8 @@ public final class WindowContainerTransaction implements Parcelable {

            private @InsetsType int mExcludeInsetsTypes;

            private boolean mLaunchAdjacentDisabled;

            Builder(int type) {
                mType = type;
            }
@@ -2153,6 +2195,11 @@ public final class WindowContainerTransaction implements Parcelable {
                return this;
            }

            Builder setLaunchAdjacentDisabled(boolean disabled) {
                mLaunchAdjacentDisabled = disabled;
                return this;
            }

            HierarchyOp build() {
                final HierarchyOp hierarchyOp = new HierarchyOp(mType);
                hierarchyOp.mContainer = mContainer;
@@ -2179,6 +2226,7 @@ public final class WindowContainerTransaction implements Parcelable {
                hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
                hierarchyOp.mIsTrimmableFromRecents = mIsTrimmableFromRecents;
                hierarchyOp.mExcludeInsetsTypes = mExcludeInsetsTypes;
                hierarchyOp.mLaunchAdjacentDisabled = mLaunchAdjacentDisabled;

                return hierarchyOp;
            }
+26 −0
Original line number Diff line number Diff line
@@ -169,6 +169,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

    private static final String TAG = StageCoordinator.class.getSimpleName();

    // The duration in ms to prevent launch-adjacent from working after split screen is first
    // entered
    private static final int DISABLE_LAUNCH_ADJACENT_AFTER_ENTER_TIMEOUT_MS = 1000;

    private final StageTaskListener mMainStage;
    private final StageListenerImpl mMainStageListener = new StageListenerImpl();
    private final StageTaskListener mSideStage;
@@ -235,6 +239,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    private SplitScreen.SplitInvocationListener mSplitInvocationListener;
    private Executor mSplitInvocationListenerExecutor;

    // Re-enables launch-adjacent handling on the split root task.  This needs to be a member
    // because we will be posting and removing it from the handler.
    private final Runnable mReEnableLaunchAdjacentOnRoot = () -> setLaunchAdjacentDisabled(false);

    /**
     * Since StageCoordinator only coordinates MainStage and SideStage, it shouldn't support
     * CompatUI layouts. CompatUI is handled separately by MainStage and SideStage.
@@ -2662,6 +2670,16 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
    }

    /**
     * Sets whether launch-adjacent is disabled or enabled.
     */
    private void setLaunchAdjacentDisabled(boolean disabled) {
        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "setLaunchAdjacentDisabled: disabled=%b", disabled);
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        wct.setDisableLaunchAdjacent(mRootTaskInfo.token, disabled);
        mTaskOrganizer.applyTransaction(wct);
    }

    /** Starts the pending transition animation. */
    public boolean startPendingAnimation(@NonNull IBinder transition,
            @NonNull TransitionInfo info,
@@ -2674,6 +2692,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        if (mSplitTransitions.isPendingEnter(transition)) {
            shouldAnimate = startPendingEnterAnimation(transition,
                    mSplitTransitions.mPendingEnter, info, startTransaction, finishTransaction);

            // Disable launch adjacent after an enter animation to prevent cases where apps are
            // incorrectly trampolining and incorrectly triggering a double launch-adjacent task
            // launch (ie. main -> split -> main). See b/344216031
            setLaunchAdjacentDisabled(true);
            mMainHandler.removeCallbacks(mReEnableLaunchAdjacentOnRoot);
            mMainHandler.postDelayed(mReEnableLaunchAdjacentOnRoot,
                    DISABLE_LAUNCH_ADJACENT_AFTER_ENTER_TIMEOUT_MS);
        } else if (mSplitTransitions.isPendingDismiss(transition)) {
            final SplitScreenTransitions.DismissSession dismiss = mSplitTransitions.mPendingDismiss;
            shouldAnimate = startPendingDismissAnimation(
+17 −4
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENS
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.window.flags.Flags.balDontBringExistingBackgroundTaskStackToFg;

import android.annotation.IntDef;
@@ -2786,11 +2787,23 @@ class ActivityStarter {
            }
        }

        if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
                && ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 || mSourceRecord == null)) {
        if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
            final boolean hasNewTaskFlag = (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0;
            if (!hasNewTaskFlag || mSourceRecord == null) {
                // ignore the flag if there is no the sourceRecord or without new_task flag
                Slog.w(TAG_WM, !hasNewTaskFlag
                        ? "Launch adjacent ignored due to missing NEW_TASK"
                        : "Launch adjacent ignored due to missing source activity");
                mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT;
            }
            // Ensure that the source task or its parents has not disabled launch-adjacent
            if (mSourceRecord != null && mSourceRecord.getTask() != null &&
                    mSourceRecord.getTask().isLaunchAdjacentDisabled()) {
                Slog.w(TAG_WM, "Launch adjacent blocked by source task or ancestor");
                mLaunchFlags &= ~FLAG_ACTIVITY_LAUNCH_ADJACENT;
            }

        }
    }

    /**
+30 −0
Original line number Diff line number Diff line
@@ -502,6 +502,11 @@ class Task extends TaskFragment {
     */
    boolean mIsTrimmableFromRecents;

    /**
     * Sets whether the launch-adjacent flag is respected or not for this task or its child tasks.
     */
    private boolean mLaunchAdjacentDisabled;

    /**
     * Bounds offset should be applied when calculating compatible configuration for apps targeting
     * SDK level 34 or before.
@@ -3802,6 +3807,9 @@ class Task extends TaskFragment {
        pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
        pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
        pw.print(prefix); pw.println(" isTrimmable=" + mIsTrimmableFromRecents);
        if (mLaunchAdjacentDisabled) {
            pw.println(prefix + "mLaunchAdjacentDisabled=true");
        }
    }

    @Override
@@ -6273,6 +6281,28 @@ class Task extends TaskFragment {
        mIsTrimmableFromRecents = isTrimmable;
    }

    /**
     * Sets this task and its children to disable respecting launch-adjacent.
     */
    void setLaunchAdjacentDisabled(boolean disabled) {
        mLaunchAdjacentDisabled = disabled;
    }

    /**
     * Returns whether this task or any of its ancestors have disabled respecting the
     * launch-adjacent flag.
     */
    boolean isLaunchAdjacentDisabled() {
        Task t = this;
        while (t != null) {
            if (t.mLaunchAdjacentDisabled) {
                return true;
            }
            t = t.getParent().asTask();
        }
        return false;
    }

    /**
     * Return true if the activityInfo has the same requiredDisplayCategory as this task.
     */
+12 −4
Original line number Diff line number Diff line
@@ -1074,6 +1074,8 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
            final Task launchRootTask = Task.fromWindowContainerToken(options.getLaunchRootTask());
            // We only allow this for created by organizer tasks.
            if (launchRootTask != null && launchRootTask.mCreatedByOrganizer) {
                Slog.i(TAG_WM, "Using launch root task from activity options: taskId="
                        + launchRootTask.mTaskId);
                return launchRootTask;
            }
        }
@@ -1081,19 +1083,25 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
        // Use launch-adjacent-flag-root if launching with launch-adjacent flag.
        if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0
                && mLaunchAdjacentFlagRootTask != null) {
            final Task launchAdjacentRootAdjacentTask =
                    mLaunchAdjacentFlagRootTask.getAdjacentTask();
            if (sourceTask != null && (sourceTask == candidateTask
                    || sourceTask.topRunningActivity() == null)) {
                // Do nothing when task that is getting opened is same as the source or when
                // the source is no-longer valid.
                Slog.w(TAG_WM, "Ignoring LAUNCH_ADJACENT because adjacent source is gone.");
            } else if (sourceTask != null
                    && mLaunchAdjacentFlagRootTask.getAdjacentTask() != null
                    && launchAdjacentRootAdjacentTask != null
                    && (sourceTask == mLaunchAdjacentFlagRootTask
                    || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) {
                // If the adjacent launch is coming from the same root, launch to
                // adjacent root instead.
                return mLaunchAdjacentFlagRootTask.getAdjacentTask();
                // If the adjacent launch is coming from the same root that was specified as the
                // launch-adjacent task, so instead we launch to its adjacent root instead.
                Slog.i(TAG_WM, "Using adjacent-to specified launch-adjacent task: taskId="
                        + launchAdjacentRootAdjacentTask.mTaskId);
                return launchAdjacentRootAdjacentTask;
            } else {
                Slog.i(TAG_WM, "Using specified launch-adjacent task: taskId="
                        + mLaunchAdjacentFlagRootTask.mTaskId);
                return mLaunchAdjacentFlagRootTask;
            }
        }
Loading