Merge "Fix ActivityEmbedding issues with REORDER_TO_FRONT" into tm-qpr-dev
This commit is contained in:
@@ -71,20 +71,42 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
*
|
*
|
||||||
* This is needed in case we need to launch a placeholder Activity to split below a transparent
|
* This is needed in case we need to launch a placeholder Activity to split below a transparent
|
||||||
* always-expand Activity.
|
* always-expand Activity.
|
||||||
|
*
|
||||||
|
* This should not be used with {@link #mPairedActivityToken}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private final IBinder mPairedPrimaryFragmentToken;
|
private final IBinder mPairedPrimaryFragmentToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Activity token to place the new TaskFragment on top of.
|
||||||
|
* When it is set, the new TaskFragment will be positioned right above the target Activity.
|
||||||
|
* Otherwise, the new TaskFragment will be positioned on the top of the Task by default.
|
||||||
|
*
|
||||||
|
* This is needed in case we need to place an Activity into TaskFragment to launch placeholder
|
||||||
|
* below a transparent always-expand Activity, or when there is another Intent being started in
|
||||||
|
* a TaskFragment above.
|
||||||
|
*
|
||||||
|
* This should not be used with {@link #mPairedPrimaryFragmentToken}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private final IBinder mPairedActivityToken;
|
||||||
|
|
||||||
private TaskFragmentCreationParams(
|
private TaskFragmentCreationParams(
|
||||||
@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken,
|
@NonNull TaskFragmentOrganizerToken organizer, @NonNull IBinder fragmentToken,
|
||||||
@NonNull IBinder ownerToken, @NonNull Rect initialBounds,
|
@NonNull IBinder ownerToken, @NonNull Rect initialBounds,
|
||||||
@WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken) {
|
@WindowingMode int windowingMode, @Nullable IBinder pairedPrimaryFragmentToken,
|
||||||
|
@Nullable IBinder pairedActivityToken) {
|
||||||
|
if (pairedPrimaryFragmentToken != null && pairedActivityToken != null) {
|
||||||
|
throw new IllegalArgumentException("pairedPrimaryFragmentToken and"
|
||||||
|
+ " pairedActivityToken should not be set at the same time.");
|
||||||
|
}
|
||||||
mOrganizer = organizer;
|
mOrganizer = organizer;
|
||||||
mFragmentToken = fragmentToken;
|
mFragmentToken = fragmentToken;
|
||||||
mOwnerToken = ownerToken;
|
mOwnerToken = ownerToken;
|
||||||
mInitialBounds.set(initialBounds);
|
mInitialBounds.set(initialBounds);
|
||||||
mWindowingMode = windowingMode;
|
mWindowingMode = windowingMode;
|
||||||
mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken;
|
mPairedPrimaryFragmentToken = pairedPrimaryFragmentToken;
|
||||||
|
mPairedActivityToken = pairedActivityToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -121,6 +143,15 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
return mPairedPrimaryFragmentToken;
|
return mPairedPrimaryFragmentToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO(b/232476698): remove the hide with adding CTS for this in next release.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public IBinder getPairedActivityToken() {
|
||||||
|
return mPairedActivityToken;
|
||||||
|
}
|
||||||
|
|
||||||
private TaskFragmentCreationParams(Parcel in) {
|
private TaskFragmentCreationParams(Parcel in) {
|
||||||
mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in);
|
mOrganizer = TaskFragmentOrganizerToken.CREATOR.createFromParcel(in);
|
||||||
mFragmentToken = in.readStrongBinder();
|
mFragmentToken = in.readStrongBinder();
|
||||||
@@ -128,6 +159,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
mInitialBounds.readFromParcel(in);
|
mInitialBounds.readFromParcel(in);
|
||||||
mWindowingMode = in.readInt();
|
mWindowingMode = in.readInt();
|
||||||
mPairedPrimaryFragmentToken = in.readStrongBinder();
|
mPairedPrimaryFragmentToken = in.readStrongBinder();
|
||||||
|
mPairedActivityToken = in.readStrongBinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
@@ -139,6 +171,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
mInitialBounds.writeToParcel(dest, flags);
|
mInitialBounds.writeToParcel(dest, flags);
|
||||||
dest.writeInt(mWindowingMode);
|
dest.writeInt(mWindowingMode);
|
||||||
dest.writeStrongBinder(mPairedPrimaryFragmentToken);
|
dest.writeStrongBinder(mPairedPrimaryFragmentToken);
|
||||||
|
dest.writeStrongBinder(mPairedActivityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -164,6 +197,7 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
+ " initialBounds=" + mInitialBounds
|
+ " initialBounds=" + mInitialBounds
|
||||||
+ " windowingMode=" + mWindowingMode
|
+ " windowingMode=" + mWindowingMode
|
||||||
+ " pairedFragmentToken=" + mPairedPrimaryFragmentToken
|
+ " pairedFragmentToken=" + mPairedPrimaryFragmentToken
|
||||||
|
+ " pairedActivityToken=" + mPairedActivityToken
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,6 +228,9 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private IBinder mPairedPrimaryFragmentToken;
|
private IBinder mPairedPrimaryFragmentToken;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private IBinder mPairedActivityToken;
|
||||||
|
|
||||||
public Builder(@NonNull TaskFragmentOrganizerToken organizer,
|
public Builder(@NonNull TaskFragmentOrganizerToken organizer,
|
||||||
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
|
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken) {
|
||||||
mOrganizer = organizer;
|
mOrganizer = organizer;
|
||||||
@@ -224,6 +261,8 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
* This is needed in case we need to launch a placeholder Activity to split below a
|
* This is needed in case we need to launch a placeholder Activity to split below a
|
||||||
* transparent always-expand Activity.
|
* transparent always-expand Activity.
|
||||||
*
|
*
|
||||||
|
* This should not be used with {@link #setPairedActivityToken}.
|
||||||
|
*
|
||||||
* TODO(b/232476698): remove the hide with adding CTS for this in next release.
|
* TODO(b/232476698): remove the hide with adding CTS for this in next release.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -233,11 +272,32 @@ public final class TaskFragmentCreationParams implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Activity token to place the new TaskFragment on top of.
|
||||||
|
* When it is set, the new TaskFragment will be positioned right above the target Activity.
|
||||||
|
* Otherwise, the new TaskFragment will be positioned on the top of the Task by default.
|
||||||
|
*
|
||||||
|
* This is needed in case we need to place an Activity into TaskFragment to launch
|
||||||
|
* placeholder below a transparent always-expand Activity, or when there is another Intent
|
||||||
|
* being started in a TaskFragment above.
|
||||||
|
*
|
||||||
|
* This should not be used with {@link #setPairedPrimaryFragmentToken}.
|
||||||
|
*
|
||||||
|
* TODO(b/232476698): remove the hide with adding CTS for this in next release.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder setPairedActivityToken(@Nullable IBinder activityToken) {
|
||||||
|
mPairedActivityToken = activityToken;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Constructs the options to create TaskFragment with. */
|
/** Constructs the options to create TaskFragment with. */
|
||||||
@NonNull
|
@NonNull
|
||||||
public TaskFragmentCreationParams build() {
|
public TaskFragmentCreationParams build() {
|
||||||
return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken,
|
return new TaskFragmentCreationParams(mOrganizer, mFragmentToken, mOwnerToken,
|
||||||
mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken);
|
mInitialBounds, mWindowingMode, mPairedPrimaryFragmentToken,
|
||||||
|
mPairedActivityToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,10 +191,25 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
*/
|
*/
|
||||||
void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
|
void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
|
||||||
@NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
|
@NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode) {
|
||||||
|
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode,
|
||||||
|
null /* pairedActivityToken */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ownerToken The token of the activity that creates this task fragment. It does not
|
||||||
|
* have to be a child of this task fragment, but must belong to the same task.
|
||||||
|
* @param pairedActivityToken The token of the activity that will be reparented to this task
|
||||||
|
* fragment. When it is not {@code null}, the task fragment will be
|
||||||
|
* positioned right above it.
|
||||||
|
*/
|
||||||
|
void createTaskFragment(@NonNull WindowContainerTransaction wct, @NonNull IBinder fragmentToken,
|
||||||
|
@NonNull IBinder ownerToken, @NonNull Rect bounds, @WindowingMode int windowingMode,
|
||||||
|
@Nullable IBinder pairedActivityToken) {
|
||||||
final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder(
|
final TaskFragmentCreationParams fragmentOptions = new TaskFragmentCreationParams.Builder(
|
||||||
getOrganizerToken(), fragmentToken, ownerToken)
|
getOrganizerToken(), fragmentToken, ownerToken)
|
||||||
.setInitialBounds(bounds)
|
.setInitialBounds(bounds)
|
||||||
.setWindowingMode(windowingMode)
|
.setWindowingMode(windowingMode)
|
||||||
|
.setPairedActivityToken(pairedActivityToken)
|
||||||
.build();
|
.build();
|
||||||
createTaskFragment(wct, fragmentOptions);
|
createTaskFragment(wct, fragmentOptions);
|
||||||
}
|
}
|
||||||
@@ -216,8 +231,10 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer {
|
|||||||
private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct,
|
private void createTaskFragmentAndReparentActivity(@NonNull WindowContainerTransaction wct,
|
||||||
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds,
|
@NonNull IBinder fragmentToken, @NonNull IBinder ownerToken, @NonNull Rect bounds,
|
||||||
@WindowingMode int windowingMode, @NonNull Activity activity) {
|
@WindowingMode int windowingMode, @NonNull Activity activity) {
|
||||||
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode);
|
final IBinder reparentActivityToken = activity.getActivityToken();
|
||||||
wct.reparentActivityToTaskFragment(fragmentToken, activity.getActivityToken());
|
createTaskFragment(wct, fragmentToken, ownerToken, bounds, windowingMode,
|
||||||
|
reparentActivityToken);
|
||||||
|
wct.reparentActivityToTaskFragment(fragmentToken, reparentActivityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
|
void setAdjacentTaskFragments(@NonNull WindowContainerTransaction wct,
|
||||||
|
|||||||
@@ -1499,7 +1499,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* Returns the active split that has the provided containers as primary and secondary or as
|
* Returns the active split that has the provided containers as primary and secondary or as
|
||||||
* secondary and primary, if available.
|
* secondary and primary, if available.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@GuardedBy("mLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
SplitContainer getActiveSplitForContainers(
|
SplitContainer getActiveSplitForContainers(
|
||||||
@NonNull TaskFragmentContainer firstContainer,
|
@NonNull TaskFragmentContainer firstContainer,
|
||||||
|
|||||||
@@ -268,10 +268,11 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
container = mController.newContainer(activity, taskId);
|
container = mController.newContainer(activity, taskId);
|
||||||
final int windowingMode = mController.getTaskContainer(taskId)
|
final int windowingMode = mController.getTaskContainer(taskId)
|
||||||
.getWindowingModeForSplitTaskFragment(bounds);
|
.getWindowingModeForSplitTaskFragment(bounds);
|
||||||
createTaskFragment(wct, container.getTaskFragmentToken(), activity.getActivityToken(),
|
final IBinder reparentActivityToken = activity.getActivityToken();
|
||||||
bounds, windowingMode);
|
createTaskFragment(wct, container.getTaskFragmentToken(), reparentActivityToken,
|
||||||
|
bounds, windowingMode, reparentActivityToken);
|
||||||
wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
|
wct.reparentActivityToTaskFragment(container.getTaskFragmentToken(),
|
||||||
activity.getActivityToken());
|
reparentActivityToken);
|
||||||
} else {
|
} else {
|
||||||
resizeTaskFragmentIfRegistered(wct, container, bounds);
|
resizeTaskFragmentIfRegistered(wct, container, bounds);
|
||||||
final int windowingMode = mController.getTaskContainer(taskId)
|
final int windowingMode = mController.getTaskContainer(taskId)
|
||||||
|
|||||||
@@ -141,12 +141,26 @@ class TaskFragmentContainer {
|
|||||||
mToken = new Binder("TaskFragmentContainer");
|
mToken = new Binder("TaskFragmentContainer");
|
||||||
mTaskContainer = taskContainer;
|
mTaskContainer = taskContainer;
|
||||||
if (pairedPrimaryContainer != null) {
|
if (pairedPrimaryContainer != null) {
|
||||||
|
// The TaskFragment will be positioned right above the paired container.
|
||||||
if (pairedPrimaryContainer.getTaskContainer() != taskContainer) {
|
if (pairedPrimaryContainer.getTaskContainer() != taskContainer) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"pairedPrimaryContainer must be in the same Task");
|
"pairedPrimaryContainer must be in the same Task");
|
||||||
}
|
}
|
||||||
final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer);
|
final int primaryIndex = taskContainer.mContainers.indexOf(pairedPrimaryContainer);
|
||||||
taskContainer.mContainers.add(primaryIndex + 1, this);
|
taskContainer.mContainers.add(primaryIndex + 1, this);
|
||||||
|
} else if (pendingAppearedActivity != null) {
|
||||||
|
// The TaskFragment will be positioned right above the pending appeared Activity. If any
|
||||||
|
// existing TaskFragment is empty with pending Intent, it is likely that the Activity of
|
||||||
|
// the pending Intent hasn't been created yet, so the new Activity should be below the
|
||||||
|
// empty TaskFragment.
|
||||||
|
int i = taskContainer.mContainers.size() - 1;
|
||||||
|
for (; i >= 0; i--) {
|
||||||
|
final TaskFragmentContainer container = taskContainer.mContainers.get(i);
|
||||||
|
if (!container.isEmpty() || container.getPendingAppearedIntent() == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskContainer.mContainers.add(i + 1, this);
|
||||||
} else {
|
} else {
|
||||||
taskContainer.mContainers.add(this);
|
taskContainer.mContainers.add(this);
|
||||||
}
|
}
|
||||||
@@ -500,6 +514,8 @@ class TaskFragmentContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!shouldFinishDependent) {
|
if (!shouldFinishDependent) {
|
||||||
|
// Always finish the placeholder when the primary is finished.
|
||||||
|
finishPlaceholderIfAny(wct, presenter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,6 +542,28 @@ class TaskFragmentContainer {
|
|||||||
mActivitiesToFinishOnExit.clear();
|
mActivitiesToFinishOnExit.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mController.mLock")
|
||||||
|
private void finishPlaceholderIfAny(@NonNull WindowContainerTransaction wct,
|
||||||
|
@NonNull SplitPresenter presenter) {
|
||||||
|
final List<TaskFragmentContainer> containersToRemove = new ArrayList<>();
|
||||||
|
for (TaskFragmentContainer container : mContainersToFinishOnExit) {
|
||||||
|
if (container.mIsFinished) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final SplitContainer splitContainer = mController.getActiveSplitForContainers(
|
||||||
|
this, container);
|
||||||
|
if (splitContainer != null && splitContainer.isPlaceholderContainer()
|
||||||
|
&& splitContainer.getSecondaryContainer() == container) {
|
||||||
|
// Remove the placeholder secondary TaskFragment.
|
||||||
|
containersToRemove.add(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mContainersToFinishOnExit.removeAll(containersToRemove);
|
||||||
|
for (TaskFragmentContainer container : containersToRemove) {
|
||||||
|
container.finish(false /* shouldFinishDependent */, presenter, wct, mController);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean isFinished() {
|
boolean isFinished() {
|
||||||
return mIsFinished;
|
return mIsFinished;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,16 +154,51 @@ public class TaskFragmentContainerTest {
|
|||||||
null /* pendingAppearedIntent */, taskContainer, mController,
|
null /* pendingAppearedIntent */, taskContainer, mController,
|
||||||
null /* pairedPrimaryContainer */);
|
null /* pairedPrimaryContainer */);
|
||||||
doReturn(container1).when(mController).getContainerWithActivity(mActivity);
|
doReturn(container1).when(mController).getContainerWithActivity(mActivity);
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
|
||||||
|
|
||||||
// The activity is requested to be reparented, so don't finish it.
|
// The activity is requested to be reparented, so don't finish it.
|
||||||
container0.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
|
container0.finish(true /* shouldFinishDependent */, mPresenter, mTransaction, mController);
|
||||||
|
|
||||||
verify(mTransaction, never()).finishActivity(any());
|
verify(mTransaction, never()).finishActivity(any());
|
||||||
verify(mPresenter).deleteTaskFragment(wct, container0.getTaskFragmentToken());
|
verify(mPresenter).deleteTaskFragment(mTransaction, container0.getTaskFragmentToken());
|
||||||
verify(mController).removeContainer(container0);
|
verify(mController).removeContainer(container0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFinish_alwaysFinishPlaceholder() {
|
||||||
|
// Register container1 as a placeholder
|
||||||
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
|
final TaskFragmentContainer container0 = new TaskFragmentContainer(mActivity,
|
||||||
|
null /* pendingAppearedIntent */, taskContainer, mController,
|
||||||
|
null /* pairedPrimaryContainer */);
|
||||||
|
final TaskFragmentInfo info0 = createMockTaskFragmentInfo(container0, mActivity);
|
||||||
|
container0.setInfo(mTransaction, info0);
|
||||||
|
final Activity placeholderActivity = createMockActivity();
|
||||||
|
final TaskFragmentContainer container1 = new TaskFragmentContainer(placeholderActivity,
|
||||||
|
null /* pendingAppearedIntent */, taskContainer, mController,
|
||||||
|
null /* pairedPrimaryContainer */);
|
||||||
|
final TaskFragmentInfo info1 = createMockTaskFragmentInfo(container1, placeholderActivity);
|
||||||
|
container1.setInfo(mTransaction, info1);
|
||||||
|
final SplitAttributes splitAttributes = new SplitAttributes.Builder().build();
|
||||||
|
final SplitPlaceholderRule rule = new SplitPlaceholderRule.Builder(new Intent(),
|
||||||
|
mActivity::equals, (java.util.function.Predicate) i -> false,
|
||||||
|
(java.util.function.Predicate) w -> true)
|
||||||
|
.setDefaultSplitAttributes(splitAttributes)
|
||||||
|
.build();
|
||||||
|
mController.registerSplit(mTransaction, container0, mActivity, container1, rule,
|
||||||
|
splitAttributes);
|
||||||
|
|
||||||
|
// The placeholder TaskFragment should be finished even if the primary is finished with
|
||||||
|
// shouldFinishDependent = false.
|
||||||
|
container0.finish(false /* shouldFinishDependent */, mPresenter, mTransaction, mController);
|
||||||
|
|
||||||
|
assertTrue(container0.isFinished());
|
||||||
|
assertTrue(container1.isFinished());
|
||||||
|
verify(mPresenter).deleteTaskFragment(mTransaction, container0.getTaskFragmentToken());
|
||||||
|
verify(mPresenter).deleteTaskFragment(mTransaction, container1.getTaskFragmentToken());
|
||||||
|
verify(mController).removeContainer(container0);
|
||||||
|
verify(mController).removeContainer(container1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetInfo() {
|
public void testSetInfo() {
|
||||||
final TaskContainer taskContainer = createTestTaskContainer();
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
@@ -493,8 +528,6 @@ public class TaskFragmentContainerTest {
|
|||||||
final TaskFragmentContainer tf1 = new TaskFragmentContainer(
|
final TaskFragmentContainer tf1 = new TaskFragmentContainer(
|
||||||
null /* pendingAppearedActivity */, new Intent(), taskContainer, mController,
|
null /* pendingAppearedActivity */, new Intent(), taskContainer, mController,
|
||||||
null /* pairedPrimaryTaskFragment */);
|
null /* pairedPrimaryTaskFragment */);
|
||||||
taskContainer.mContainers.add(tf0);
|
|
||||||
taskContainer.mContainers.add(tf1);
|
|
||||||
|
|
||||||
// When tf2 is created with using tf0 as pairedPrimaryContainer, tf2 should be inserted
|
// When tf2 is created with using tf0 as pairedPrimaryContainer, tf2 should be inserted
|
||||||
// right above tf0.
|
// right above tf0.
|
||||||
@@ -505,6 +538,26 @@ public class TaskFragmentContainerTest {
|
|||||||
assertEquals(2, taskContainer.indexOf(tf1));
|
assertEquals(2, taskContainer.indexOf(tf1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewContainerWithPairedPendingAppearedActivity() {
|
||||||
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
|
final TaskFragmentContainer tf0 = new TaskFragmentContainer(
|
||||||
|
createMockActivity(), null /* pendingAppearedIntent */, taskContainer, mController,
|
||||||
|
null /* pairedPrimaryTaskFragment */);
|
||||||
|
final TaskFragmentContainer tf1 = new TaskFragmentContainer(
|
||||||
|
null /* pendingAppearedActivity */, new Intent(), taskContainer, mController,
|
||||||
|
null /* pairedPrimaryTaskFragment */);
|
||||||
|
|
||||||
|
// When tf2 is created with pendingAppearedActivity, tf2 should be inserted below any
|
||||||
|
// TaskFragment without any Activity.
|
||||||
|
final TaskFragmentContainer tf2 = new TaskFragmentContainer(
|
||||||
|
createMockActivity(), null /* pendingAppearedIntent */, taskContainer, mController,
|
||||||
|
null /* pairedPrimaryTaskFragment */);
|
||||||
|
assertEquals(0, taskContainer.indexOf(tf0));
|
||||||
|
assertEquals(1, taskContainer.indexOf(tf2));
|
||||||
|
assertEquals(2, taskContainer.indexOf(tf1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsVisible() {
|
public void testIsVisible() {
|
||||||
final TaskContainer taskContainer = createTestTaskContainer();
|
final TaskContainer taskContainer = createTestTaskContainer();
|
||||||
|
|||||||
@@ -1949,6 +1949,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
creationParams.getPairedPrimaryFragmentToken());
|
creationParams.getPairedPrimaryFragmentToken());
|
||||||
final int pairedPosition = ownerTask.mChildren.indexOf(pairedPrimaryTaskFragment);
|
final int pairedPosition = ownerTask.mChildren.indexOf(pairedPrimaryTaskFragment);
|
||||||
position = pairedPosition != -1 ? pairedPosition + 1 : POSITION_TOP;
|
position = pairedPosition != -1 ? pairedPosition + 1 : POSITION_TOP;
|
||||||
|
} else if (creationParams.getPairedActivityToken() != null) {
|
||||||
|
// When there is a paired Activity, we want to place the new TaskFragment right above
|
||||||
|
// the paired Activity to make sure the Activity position is not changed after reparent.
|
||||||
|
final ActivityRecord pairedActivity = ActivityRecord.forTokenLocked(
|
||||||
|
creationParams.getPairedActivityToken());
|
||||||
|
final int pairedPosition = ownerTask.mChildren.indexOf(pairedActivity);
|
||||||
|
position = pairedPosition != -1 ? pairedPosition + 1 : POSITION_TOP;
|
||||||
} else {
|
} else {
|
||||||
position = POSITION_TOP;
|
position = POSITION_TOP;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -795,6 +795,40 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
task.mChildren.indexOf(activityOnTop));
|
task.mChildren.indexOf(activityOnTop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testApplyTransaction_createTaskFragment_withPairedActivityToken() {
|
||||||
|
final Task task = createTask(mDisplayContent);
|
||||||
|
final ActivityRecord activityAtBottom = createActivityRecord(task);
|
||||||
|
final int uid = Binder.getCallingUid();
|
||||||
|
activityAtBottom.info.applicationInfo.uid = uid;
|
||||||
|
activityAtBottom.getTask().effectiveUid = uid;
|
||||||
|
mTaskFragment = new TaskFragmentBuilder(mAtm)
|
||||||
|
.setParentTask(task)
|
||||||
|
.setFragmentToken(mFragmentToken)
|
||||||
|
.createActivityCount(1)
|
||||||
|
.build();
|
||||||
|
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
|
||||||
|
final IBinder fragmentToken1 = new Binder();
|
||||||
|
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||||
|
mOrganizerToken, fragmentToken1, activityAtBottom.token)
|
||||||
|
.setPairedActivityToken(activityAtBottom.token)
|
||||||
|
.build();
|
||||||
|
mTransaction.setTaskFragmentOrganizer(mIOrganizer);
|
||||||
|
mTransaction.createTaskFragment(params);
|
||||||
|
assertApplyTransactionAllowed(mTransaction);
|
||||||
|
|
||||||
|
// Successfully created a TaskFragment.
|
||||||
|
final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(
|
||||||
|
fragmentToken1);
|
||||||
|
assertNotNull(taskFragment);
|
||||||
|
// The new TaskFragment should be positioned right above the paired activity.
|
||||||
|
assertEquals(task.mChildren.indexOf(activityAtBottom) + 1,
|
||||||
|
task.mChildren.indexOf(taskFragment));
|
||||||
|
// The top TaskFragment should remain on top.
|
||||||
|
assertEquals(task.mChildren.indexOf(taskFragment) + 1,
|
||||||
|
task.mChildren.indexOf(mTaskFragment));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceHierarchyChange_reparentChildren() {
|
public void testApplyTransaction_enforceHierarchyChange_reparentChildren() {
|
||||||
doReturn(true).when(mTaskFragment).isAttached();
|
doReturn(true).when(mTaskFragment).isAttached();
|
||||||
|
|||||||
Reference in New Issue
Block a user