Merge "[5/n] Pin ActivityStack" into udc-qpr-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user