diff options
8 files changed, 125 insertions, 13 deletions
diff --git a/core/java/android/window/TaskFragmentOperation.java b/core/java/android/window/TaskFragmentOperation.java index e153bb70a7ca..43fa0be6c1b7 100644 --- a/core/java/android/window/TaskFragmentOperation.java +++ b/core/java/android/window/TaskFragmentOperation.java @@ -80,6 +80,14 @@ public final class TaskFragmentOperation implements Parcelable { */ public static final int OP_TYPE_REORDER_TO_FRONT = 10; + /** + * Sets the activity navigation to be isolated, where the activity navigation on the + * TaskFragment is separated from the rest activities in the Task. Activities cannot be + * started on an isolated TaskFragment unless the activities are launched from the same + * TaskFragment or explicitly requested to. + */ + public static final int OP_TYPE_SET_ISOLATED_NAVIGATION = 11; + @IntDef(prefix = { "OP_TYPE_" }, value = { OP_TYPE_UNKNOWN, OP_TYPE_CREATE_TASK_FRAGMENT, @@ -92,7 +100,8 @@ public final class TaskFragmentOperation implements Parcelable { OP_TYPE_SET_COMPANION_TASK_FRAGMENT, OP_TYPE_SET_ANIMATION_PARAMS, OP_TYPE_SET_RELATIVE_BOUNDS, - OP_TYPE_REORDER_TO_FRONT + OP_TYPE_REORDER_TO_FRONT, + OP_TYPE_SET_ISOLATED_NAVIGATION }) @Retention(RetentionPolicy.SOURCE) public @interface OperationType {} @@ -118,11 +127,14 @@ public final class TaskFragmentOperation implements Parcelable { @Nullable private final TaskFragmentAnimationParams mAnimationParams; + private final boolean mIsolatedNav; + private TaskFragmentOperation(@OperationType int opType, @Nullable TaskFragmentCreationParams taskFragmentCreationParams, @Nullable IBinder activityToken, @Nullable Intent activityIntent, @Nullable Bundle bundle, @Nullable IBinder secondaryFragmentToken, - @Nullable TaskFragmentAnimationParams animationParams) { + @Nullable TaskFragmentAnimationParams animationParams, + boolean isolatedNav) { mOpType = opType; mTaskFragmentCreationParams = taskFragmentCreationParams; mActivityToken = activityToken; @@ -130,6 +142,7 @@ public final class TaskFragmentOperation implements Parcelable { mBundle = bundle; mSecondaryFragmentToken = secondaryFragmentToken; mAnimationParams = animationParams; + mIsolatedNav = isolatedNav; } private TaskFragmentOperation(Parcel in) { @@ -140,6 +153,7 @@ public final class TaskFragmentOperation implements Parcelable { mBundle = in.readBundle(getClass().getClassLoader()); mSecondaryFragmentToken = in.readStrongBinder(); mAnimationParams = in.readTypedObject(TaskFragmentAnimationParams.CREATOR); + mIsolatedNav = in.readBoolean(); } @Override @@ -151,6 +165,7 @@ public final class TaskFragmentOperation implements Parcelable { dest.writeBundle(mBundle); dest.writeStrongBinder(mSecondaryFragmentToken); dest.writeTypedObject(mAnimationParams, flags); + dest.writeBoolean(mIsolatedNav); } @NonNull @@ -223,6 +238,14 @@ public final class TaskFragmentOperation implements Parcelable { return mAnimationParams; } + /** + * Returns whether the activity navigation on this TaskFragment is isolated. This is only + * useful when the op type is {@link OP_TYPE_SET_ISOLATED_NAVIGATION}. + */ + public boolean isIsolatedNav() { + return mIsolatedNav; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder(); @@ -245,6 +268,7 @@ public final class TaskFragmentOperation implements Parcelable { if (mAnimationParams != null) { sb.append(", animationParams=").append(mAnimationParams); } + sb.append(", isolatedNav=").append(mIsolatedNav); sb.append('}'); return sb.toString(); @@ -253,7 +277,7 @@ public final class TaskFragmentOperation implements Parcelable { @Override public int hashCode() { return Objects.hash(mOpType, mTaskFragmentCreationParams, mActivityToken, mActivityIntent, - mBundle, mSecondaryFragmentToken, mAnimationParams); + mBundle, mSecondaryFragmentToken, mAnimationParams, mIsolatedNav); } @Override @@ -268,7 +292,8 @@ public final class TaskFragmentOperation implements Parcelable { && Objects.equals(mActivityIntent, other.mActivityIntent) && Objects.equals(mBundle, other.mBundle) && Objects.equals(mSecondaryFragmentToken, other.mSecondaryFragmentToken) - && Objects.equals(mAnimationParams, other.mAnimationParams); + && Objects.equals(mAnimationParams, other.mAnimationParams) + && mIsolatedNav == other.mIsolatedNav; } @Override @@ -300,6 +325,8 @@ public final class TaskFragmentOperation implements Parcelable { @Nullable private TaskFragmentAnimationParams mAnimationParams; + private boolean mIsolatedNav; + /** * @param opType the {@link OperationType} of this {@link TaskFragmentOperation}. */ @@ -363,12 +390,22 @@ public final class TaskFragmentOperation implements Parcelable { } /** + * Sets the activity navigation of this TaskFragment to be isolated. + */ + @NonNull + public Builder setIsolatedNav(boolean isolatedNav) { + mIsolatedNav = isolatedNav; + return this; + } + + /** * Constructs the {@link TaskFragmentOperation}. */ @NonNull public TaskFragmentOperation build() { return new TaskFragmentOperation(mOpType, mTaskFragmentCreationParams, mActivityToken, - mActivityIntent, mBundle, mSecondaryFragmentToken, mAnimationParams); + mActivityIntent, mBundle, mSecondaryFragmentToken, mAnimationParams, + mIsolatedNav); } } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index d94e8e426c4b..4d73c20fe39f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -17,7 +17,9 @@ package androidx.window.extensions.embedding; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_ISOLATED_NAVIGATION; import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior; import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior; @@ -340,6 +342,20 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { wct.deleteTaskFragment(fragmentToken); } + void reorderTaskFragmentToFront(@NonNull WindowContainerTransaction wct, + @NonNull IBinder fragmentToken) { + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_REORDER_TO_FRONT).build(); + wct.addTaskFragmentOperation(fragmentToken, operation); + } + + void setTaskFragmentIsolatedNavigation(@NonNull WindowContainerTransaction wct, + @NonNull IBinder fragmentToken, boolean isolatedNav) { + final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( + OP_TYPE_SET_ISOLATED_NAVIGATION).setIsolatedNav(isolatedNav).build(); + wct.addTaskFragmentOperation(fragmentToken, operation); + } + void updateTaskFragmentInfo(@NonNull TaskFragmentInfo taskFragmentInfo) { mFragmentInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo); } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index a2f75e099465..f95f3ffb4df3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -250,6 +250,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // Updates the Split final TransactionRecord transactionRecord = mTransactionManager.startNewTransaction(); final WindowContainerTransaction wct = transactionRecord.getTransaction(); + + mPresenter.setTaskFragmentIsolatedNavigation(wct, + splitPinContainer.getSecondaryContainer().getTaskFragmentToken(), + true /* isolatedNav */); mPresenter.updateSplitContainer(splitPinContainer, wct); transactionRecord.apply(false /* shouldApplyIndependently */); updateCallbackIfNecessary(); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index 4dafbd17f379..5de6acfcc9db 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -17,7 +17,6 @@ package androidx.window.extensions.embedding; import static android.content.pm.PackageManager.MATCH_ALL; -import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT; import android.app.Activity; import android.app.ActivityThread; @@ -40,7 +39,6 @@ import android.view.WindowInsets; import android.view.WindowMetrics; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentCreationParams; -import android.window.TaskFragmentOperation; import android.window.WindowContainerTransaction; import androidx.annotation.IntDef; @@ -427,10 +425,8 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { final SplitPinContainer pinnedContainer = container.getTaskContainer().getSplitPinContainer(); if (pinnedContainer != null) { - final TaskFragmentOperation operation = new TaskFragmentOperation.Builder( - OP_TYPE_REORDER_TO_FRONT).build(); - wct.addTaskFragmentOperation( - pinnedContainer.getSecondaryContainer().getTaskFragmentToken(), operation); + reorderTaskFragmentToFront(wct, + pinnedContainer.getSecondaryContainer().getTaskFragmentToken()); } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 0a62c881e251..0c1c1d428766 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -3110,7 +3110,18 @@ class ActivityStarter { } else { TaskFragment candidateTf = mAddingToTaskFragment != null ? mAddingToTaskFragment : null; if (candidateTf == null) { - final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */); + // Puts the activity on the top-most non-isolated navigation TF, unless the + // activity is launched from the same TF. + final TaskFragment sourceTaskFragment = + mSourceRecord != null ? mSourceRecord.getTaskFragment() : null; + final ActivityRecord top = task.getActivity(r -> { + if (!r.canBeTopRunning()) { + return false; + } + final TaskFragment taskFragment = r.getTaskFragment(); + return !taskFragment.isIsolatedNav() || (sourceTaskFragment != null + && sourceTaskFragment == taskFragment); + }); if (top != null) { candidateTf = top.getTaskFragment(); } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 92c0987d5636..57ce368aae87 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -329,6 +329,15 @@ class TaskFragment extends WindowContainer<WindowContainer> { */ private boolean mDelayLastActivityRemoval; + /** + * Whether the activity navigation should be isolated. That is, Activities cannot be launched + * on an isolated TaskFragment, unless the activity is launched from an Activity in the same + * isolated TaskFragment, or explicitly requested to be launched to. + * <p> + * Note that only an embedded TaskFragment can be isolated. + */ + private boolean mIsolatedNav; + final Point mLastSurfaceSize = new Point(); private final Rect mTmpBounds = new Rect(); @@ -481,6 +490,19 @@ class TaskFragment extends WindowContainer<WindowContainer> { return mAnimationParams; } + /** @see #mIsolatedNav */ + void setIsolatedNav(boolean isolatedNav) { + if (!isEmbedded()) { + return; + } + mIsolatedNav = isolatedNav; + } + + /** @see #mIsolatedNav */ + boolean isIsolatedNav() { + return isEmbedded() && mIsolatedNav; + } + TaskFragment getAdjacentTaskFragment() { return mAdjacentTaskFragment; } @@ -3034,7 +3056,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); - pw.println(prefix + "bounds=" + getBounds().toShortString()); + pw.println(prefix + "bounds=" + getBounds().toShortString() + + (mIsolatedNav ? ", isolatedNav" : "")); final String doublePrefix = prefix + " "; for (int i = mChildren.size() - 1; i >= 0; i--) { final WindowContainer<?> child = mChildren.get(i); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 164c8b013c84..a84749aa6643 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -30,6 +30,7 @@ import static android.window.TaskFragmentOperation.OP_TYPE_REQUEST_FOCUS_ON_TASK import static android.window.TaskFragmentOperation.OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS; import static android.window.TaskFragmentOperation.OP_TYPE_SET_COMPANION_TASK_FRAGMENT; +import static android.window.TaskFragmentOperation.OP_TYPE_SET_ISOLATED_NAVIGATION; import static android.window.TaskFragmentOperation.OP_TYPE_SET_RELATIVE_BOUNDS; import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static android.window.TaskFragmentOperation.OP_TYPE_UNKNOWN; @@ -1356,6 +1357,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } break; } + case OP_TYPE_SET_ISOLATED_NAVIGATION: { + final boolean isolatedNav = operation.isIsolatedNav(); + taskFragment.setIsolatedNav(isolatedNav); + break; + } } return effects; } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 9d597b11120d..6a9bb6c85c70 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -653,4 +653,23 @@ public class TaskFragmentTest extends WindowTestsBase { assertEquals(mDisplayContent.getImeContainer().getParent().getSurfaceControl(), mDisplayContent.computeImeParent()); } + + @Test + public void testIsolatedNavigation() { + final Task task = createTask(mDisplayContent); + final TaskFragment tf0 = new TaskFragmentBuilder(mAtm) + .setParentTask(task) + .createActivityCount(1) + .setOrganizer(mOrganizer) + .setFragmentToken(new Binder()) + .build(); + + // Cannot be isolated if not embedded. + task.setIsolatedNav(true); + assertFalse(task.isIsolatedNav()); + + // Ensure the TaskFragment is isolated once set. + tf0.setIsolatedNav(true); + assertTrue(tf0.isIsolatedNav()); + } } |