Merge "[5/n] Pin ActivityStack" into udc-qpr-dev

This commit is contained in:
Louis Chang
2023-07-24 03:30:17 +00:00
committed by Android (Google) Code Review
8 changed files with 125 additions and 13 deletions

View File

@@ -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}.
*/
@@ -362,13 +389,23 @@ public final class TaskFragmentOperation implements Parcelable {
return this;
}
/**
* 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);
}
}
}

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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());
}
}

View File

@@ -3100,7 +3100,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();
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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());
}
}