Loading core/java/android/window/WindowContainerTransaction.java +51 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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) Loading Loading @@ -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) Loading Loading @@ -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) { Loading @@ -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() { Loading Loading @@ -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; } Loading @@ -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) { Loading @@ -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"; Loading Loading @@ -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); Loading Loading @@ -1971,6 +2010,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeBoolean(mReparentLeafTaskIfRelaunch); dest.writeBoolean(mIsTrimmableFromRecents); dest.writeInt(mExcludeInsetsTypes); dest.writeBoolean(mLaunchAdjacentDisabled); } @Override Loading Loading @@ -2047,6 +2087,8 @@ public final class WindowContainerTransaction implements Parcelable { private @InsetsType int mExcludeInsetsTypes; private boolean mLaunchAdjacentDisabled; Builder(int type) { mType = type; } Loading Loading @@ -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; Loading @@ -2179,6 +2226,7 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch; hierarchyOp.mIsTrimmableFromRecents = mIsTrimmableFromRecents; hierarchyOp.mExcludeInsetsTypes = mExcludeInsetsTypes; hierarchyOp.mLaunchAdjacentDisabled = mLaunchAdjacentDisabled; return hierarchyOp; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +26 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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, Loading @@ -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( Loading services/core/java/com/android/server/wm/ActivityStarter.java +17 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } } } /** Loading services/core/java/com/android/server/wm/Task.java +30 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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. */ Loading services/core/java/com/android/server/wm/TaskDisplayArea.java +12 −4 Original line number Diff line number Diff line Loading @@ -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; } } Loading @@ -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 Loading
core/java/android/window/WindowContainerTransaction.java +51 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. Loading Loading @@ -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) Loading Loading @@ -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) Loading Loading @@ -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) { Loading @@ -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() { Loading Loading @@ -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; } Loading @@ -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) { Loading @@ -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"; Loading Loading @@ -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); Loading Loading @@ -1971,6 +2010,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeBoolean(mReparentLeafTaskIfRelaunch); dest.writeBoolean(mIsTrimmableFromRecents); dest.writeInt(mExcludeInsetsTypes); dest.writeBoolean(mLaunchAdjacentDisabled); } @Override Loading Loading @@ -2047,6 +2087,8 @@ public final class WindowContainerTransaction implements Parcelable { private @InsetsType int mExcludeInsetsTypes; private boolean mLaunchAdjacentDisabled; Builder(int type) { mType = type; } Loading Loading @@ -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; Loading @@ -2179,6 +2226,7 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch; hierarchyOp.mIsTrimmableFromRecents = mIsTrimmableFromRecents; hierarchyOp.mExcludeInsetsTypes = mExcludeInsetsTypes; hierarchyOp.mLaunchAdjacentDisabled = mLaunchAdjacentDisabled; return hierarchyOp; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +26 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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, Loading @@ -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( Loading
services/core/java/com/android/server/wm/ActivityStarter.java +17 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } } } /** Loading
services/core/java/com/android/server/wm/Task.java +30 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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. */ Loading
services/core/java/com/android/server/wm/TaskDisplayArea.java +12 −4 Original line number Diff line number Diff line Loading @@ -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; } } Loading @@ -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