summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/ActivityClient.java17
-rw-r--r--core/java/android/app/IActivityClientController.aidl10
-rw-r--r--core/java/android/window/TaskFragmentInfo.java26
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java30
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java33
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java1
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java2
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java5
13 files changed, 144 insertions, 11 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c0cd6386aec2..cae2d6d50d2e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3733,6 +3733,7 @@ package android.window {
public final class TaskFragmentInfo implements android.os.Parcelable {
method public boolean equalsForTaskFragmentOrganizer(@Nullable android.window.TaskFragmentInfo);
method @NonNull public java.util.List<android.os.IBinder> getActivities();
+ method @NonNull public java.util.List<android.os.IBinder> getActivitiesRequestedInTaskFragment();
method @NonNull public android.content.res.Configuration getConfiguration();
method @NonNull public android.os.IBinder getFragmentToken();
method @NonNull public android.graphics.Point getPositionInParent();
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 44327af928cb..b35e87b541d3 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -598,6 +598,23 @@ public class ActivityClient {
}
/**
+ * Returns {@code true} if the activity was explicitly requested to be launched in the
+ * TaskFragment.
+ *
+ * @param activityToken The token of the Activity.
+ * @param taskFragmentToken The token of the TaskFragment.
+ */
+ public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken,
+ IBinder taskFragmentToken) {
+ try {
+ return getActivityClientController().isRequestedToLaunchInTaskFragment(activityToken,
+ taskFragmentToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Shows or hides a Camera app compat toggle for stretched issues with the requested state.
*
* @param token The token for the window that needs a control.
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 5136b2033d1c..a3c5e1c67e1b 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -181,4 +181,14 @@ interface IActivityClientController {
* that started the task.
*/
void enableTaskLocaleOverride(in IBinder token);
+
+ /**
+ * Return {@code true} if the activity was explicitly requested to be launched in the
+ * TaskFragment.
+ *
+ * @param activityToken The token of the Activity.
+ * @param taskFragmentToken The token of the TaskFragment.
+ */
+ boolean isRequestedToLaunchInTaskFragment(in IBinder activityToken,
+ in IBinder taskFragmentToken);
}
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index a881a05a1054..fa5195727afe 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -66,6 +66,13 @@ public final class TaskFragmentInfo implements Parcelable {
@NonNull
private final List<IBinder> mActivities = new ArrayList<>();
+ /**
+ * List of Activity tokens that were explicitly requested to be launched in this TaskFragment.
+ * It only contains Activities that belong to the organizer process for security.
+ */
+ @NonNull
+ private final List<IBinder> mInRequestedTaskFragmentActivities = new ArrayList<>();
+
/** Relative position of the fragment's top left corner in the parent container. */
private final Point mPositionInParent = new Point();
@@ -99,15 +106,18 @@ public final class TaskFragmentInfo implements Parcelable {
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
@NonNull Configuration configuration, int runningActivityCount,
- boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent,
- boolean isTaskClearedForReuse, boolean isTaskFragmentClearedForPip,
- boolean isClearedForReorderActivityToFront, @NonNull Point minimumDimensions) {
+ boolean isVisible, @NonNull List<IBinder> activities,
+ @NonNull List<IBinder> inRequestedTaskFragmentActivities,
+ @NonNull Point positionInParent, boolean isTaskClearedForReuse,
+ boolean isTaskFragmentClearedForPip, boolean isClearedForReorderActivityToFront,
+ @NonNull Point minimumDimensions) {
mFragmentToken = requireNonNull(fragmentToken);
mToken = requireNonNull(token);
mConfiguration.setTo(configuration);
mRunningActivityCount = runningActivityCount;
mIsVisible = isVisible;
mActivities.addAll(activities);
+ mInRequestedTaskFragmentActivities.addAll(inRequestedTaskFragmentActivities);
mPositionInParent.set(positionInParent);
mIsTaskClearedForReuse = isTaskClearedForReuse;
mIsTaskFragmentClearedForPip = isTaskFragmentClearedForPip;
@@ -151,6 +161,11 @@ public final class TaskFragmentInfo implements Parcelable {
return mActivities;
}
+ @NonNull
+ public List<IBinder> getActivitiesRequestedInTaskFragment() {
+ return mInRequestedTaskFragmentActivities;
+ }
+
/** Returns the relative position of the fragment's top left corner in the parent container. */
@NonNull
public Point getPositionInParent() {
@@ -215,6 +230,8 @@ public final class TaskFragmentInfo implements Parcelable {
&& mIsVisible == that.mIsVisible
&& getWindowingMode() == that.getWindowingMode()
&& mActivities.equals(that.mActivities)
+ && mInRequestedTaskFragmentActivities.equals(
+ that.mInRequestedTaskFragmentActivities)
&& mPositionInParent.equals(that.mPositionInParent)
&& mIsTaskClearedForReuse == that.mIsTaskClearedForReuse
&& mIsTaskFragmentClearedForPip == that.mIsTaskFragmentClearedForPip
@@ -229,6 +246,7 @@ public final class TaskFragmentInfo implements Parcelable {
mRunningActivityCount = in.readInt();
mIsVisible = in.readBoolean();
in.readBinderList(mActivities);
+ in.readBinderList(mInRequestedTaskFragmentActivities);
mPositionInParent.readFromParcel(in);
mIsTaskClearedForReuse = in.readBoolean();
mIsTaskFragmentClearedForPip = in.readBoolean();
@@ -245,6 +263,7 @@ public final class TaskFragmentInfo implements Parcelable {
dest.writeInt(mRunningActivityCount);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
+ dest.writeBinderList(mInRequestedTaskFragmentActivities);
mPositionInParent.writeToParcel(dest, flags);
dest.writeBoolean(mIsTaskClearedForReuse);
dest.writeBoolean(mIsTaskFragmentClearedForPip);
@@ -274,6 +293,7 @@ public final class TaskFragmentInfo implements Parcelable {
+ " runningActivityCount=" + mRunningActivityCount
+ " isVisible=" + mIsVisible
+ " activities=" + mActivities
+ + " inRequestedTaskFragmentActivities" + mInRequestedTaskFragmentActivities
+ " positionInParent=" + mPositionInParent
+ " isTaskClearedForReuse=" + mIsTaskClearedForReuse
+ " isTaskFragmentClearedForPip=" + mIsTaskFragmentClearedForPip
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 2c1ddf7cfcbe..95823b803522 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -748,8 +748,6 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@GuardedBy("mLock")
void onActivityCreated(@NonNull WindowContainerTransaction wct,
@NonNull Activity launchedActivity) {
- // TODO(b/229680885): we don't support launching into primary yet because we want to always
- // launch the new activity on top.
resolveActivityToContainer(wct, launchedActivity, false /* isOnReparent */);
updateCallbackIfNecessary();
}
@@ -785,6 +783,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return true;
}
+ final TaskFragmentContainer container = getContainerWithActivity(activity);
+ if (!isOnReparent && container != null
+ && container.getTaskContainer().getTopTaskFragmentContainer() != container) {
+ // Do not resolve if the launched activity is not the top-most container in the Task.
+ return true;
+ }
+
/*
* We will check the following to see if there is any embedding rule matched:
* 1. Whether the new launched activity should always expand.
@@ -807,6 +812,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return true;
}
+ // Skip resolving the following split-rules if the launched activity has been requested
+ // to be launched into its current container.
+ if (container != null && container.isActivityInRequestedTaskFragment(
+ activity.getActivityToken())) {
+ return true;
+ }
+
// 3. Whether the new launched activity has already been in a split with a rule matched.
if (isNewActivityInSplitWithRuleMatched(activity)) {
return true;
@@ -2060,6 +2072,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
if (!container.hasActivity(activityToken)
&& container.getTaskFragmentToken()
.equals(initialTaskFragmentToken)) {
+ if (ActivityClient.getInstance().isRequestedToLaunchInTaskFragment(
+ activityToken, initialTaskFragmentToken)) {
+ container.addPendingAppearedInRequestedTaskFragmentActivity(
+ activity);
+ }
+
// The onTaskFragmentInfoChanged callback containing this activity has
// not reached the client yet, so add the activity to the pending
// appeared activities.
@@ -2151,6 +2169,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
// TODO(b/232042367): Consolidate the activity create handling so that we can handle
// cross-process the same as normal.
+ // Early return if the launching taskfragment is already been set.
+ if (options.getBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN) != null) {
+ synchronized (mLock) {
+ mCurrentIntent = intent;
+ }
+ return super.onStartActivity(who, intent, options);
+ }
+
final Activity launchingActivity;
if (who instanceof Activity) {
// We will check if the new activity should be split with the activity that launched
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index b38f8245a2aa..6c553a836dbd 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -86,6 +86,12 @@ class TaskFragmentContainer {
@Nullable
private Intent mPendingAppearedIntent;
+ /**
+ * The activities that were explicitly requested to be launched in its current TaskFragment,
+ * but haven't been added to {@link #mInfo} yet.
+ */
+ final ArrayList<IBinder> mPendingAppearedInRequestedTaskFragmentActivities = new ArrayList<>();
+
/** Containers that are dependent on this one and should be completely destroyed on exit. */
private final List<TaskFragmentContainer> mContainersToFinishOnExit =
new ArrayList<>();
@@ -296,6 +302,8 @@ class TaskFragmentContainer {
void removePendingAppearedActivity(@NonNull IBinder activityToken) {
mPendingAppearedActivities.remove(activityToken);
+ // Also remove the activity from the mPendingInRequestedTaskFragmentActivities.
+ mPendingAppearedInRequestedTaskFragmentActivities.remove(activityToken);
}
@GuardedBy("mController.mLock")
@@ -424,7 +432,7 @@ class TaskFragmentContainer {
for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
final IBinder activityToken = mPendingAppearedActivities.get(i);
if (infoActivities.contains(activityToken)) {
- mPendingAppearedActivities.remove(i);
+ removePendingAppearedActivity(activityToken);
}
}
}
@@ -720,6 +728,29 @@ class TaskFragmentContainer {
mLastCompanionTaskFragment = fragmentToken;
}
+ /**
+ * Adds the pending appeared activity that has requested to be launched in this task fragment.
+ * @see android.app.ActivityClient#isRequestedToLaunchInTaskFragment
+ */
+ void addPendingAppearedInRequestedTaskFragmentActivity(Activity activity) {
+ final IBinder activityToken = activity.getActivityToken();
+ if (hasActivity(activityToken)) {
+ return;
+ }
+ mPendingAppearedInRequestedTaskFragmentActivities.add(activity.getActivityToken());
+ }
+
+ /**
+ * Checks if the given activity has requested to be launched in this task fragment.
+ * @see #addPendingAppearedInRequestedTaskFragmentActivity
+ */
+ boolean isActivityInRequestedTaskFragment(IBinder activityToken) {
+ if (mInfo != null && mInfo.getActivitiesRequestedInTaskFragment().contains(activityToken)) {
+ return true;
+ }
+ return mPendingAppearedInRequestedTaskFragmentActivities.contains(activityToken);
+ }
+
/** Gets the parent leaf Task id. */
int getTaskId() {
return mTaskContainer.getTaskId();
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
index 459ec9f89c4a..a069ac7256d6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
@@ -177,6 +177,7 @@ public class EmbeddingTestUtils {
1,
isVisible,
Collections.singletonList(activity.getActivityToken()),
+ new ArrayList<>(),
new Point(),
false /* isTaskClearedForReuse */,
false /* isTaskFragmentClearedForPip */,
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index bbb454d31c38..dd087e8eb7c9 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -124,7 +124,7 @@ public class JetpackTaskFragmentOrganizerTest {
private TaskFragmentInfo createMockInfo(TaskFragmentContainer container) {
return new TaskFragmentInfo(container.getTaskFragmentToken(),
mock(WindowContainerToken.class), new Configuration(), 0 /* runningActivityCount */,
- false /* isVisible */, new ArrayList<>(), new Point(),
+ false /* isVisible */, new ArrayList<>(), new ArrayList<>(), new Point(),
false /* isTaskClearedForReuse */, false /* isTaskFragmentClearedForPip */,
false /* isClearedForReorderActivityToFront */, new Point());
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 17909d4a0763..88dbcd7bd631 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -696,7 +696,7 @@ public class SplitControllerTest {
final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
- assertFalse(result);
+ assertTrue(result);
verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(),
any(), anyBoolean());
}
@@ -730,7 +730,7 @@ public class SplitControllerTest {
final boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
- assertFalse(result);
+ assertTrue(result);
verify(mSplitPresenter, never()).startActivityToSide(any(), any(), any(), any(), any(),
any(), anyBoolean());
}
@@ -804,7 +804,7 @@ public class SplitControllerTest {
final Activity launchedActivity = createMockActivity();
primaryContainer.addPendingAppearedActivity(launchedActivity);
- assertFalse(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity,
+ assertTrue(mSplitController.resolveActivityToContainer(mTransaction, launchedActivity,
false /* isOnReparent */));
}
@@ -940,7 +940,7 @@ public class SplitControllerTest {
boolean result = mSplitController.resolveActivityToContainer(mTransaction, mActivity,
false /* isOnReparent */);
- assertFalse(result);
+ assertTrue(result);
assertEquals(primaryContainer, mSplitController.getContainerWithActivity(mActivity));
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 01e9522044a1..d108f0de5d15 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1714,4 +1714,20 @@ class ActivityClientController extends IActivityClientController.Stub {
}
}
}
+
+ /**
+ * Returns {@code true} if the activity was explicitly requested to be launched in its
+ * current TaskFragment.
+ *
+ * @see ActivityRecord#mRequestedLaunchingTaskFragmentToken
+ */
+ public boolean isRequestedToLaunchInTaskFragment(IBinder activityToken,
+ IBinder taskFragmentToken) {
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.isInRootTaskLocked(activityToken);
+ if (r == null) return false;
+
+ return r.mRequestedLaunchingTaskFragmentToken == taskFragmentToken;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3545747a67e3..59cd0c2242bd 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -560,6 +560,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
boolean inHistory; // are we in the history task?
final ActivityTaskSupervisor mTaskSupervisor;
final RootWindowContainer mRootWindowContainer;
+ // The token of the TaskFragment that this activity was requested to be launched into.
+ IBinder mRequestedLaunchingTaskFragmentToken;
// Tracking splash screen status from previous activity
boolean mSplashScreenStyleSolidColor = false;
@@ -1600,6 +1602,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (oldParent != null) {
oldParent.cleanUpActivityReferences(this);
+ // Clear the state as this activity is removed from its old parent.
+ mRequestedLaunchingTaskFragmentToken = null;
}
if (newParent != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 32dac49102bd..fbcf0fa3aeb8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2957,6 +2957,8 @@ class ActivityStarter {
int embeddingCheckResult = canEmbedActivity(mInTaskFragment, mStartActivity, task);
if (embeddingCheckResult == EMBEDDING_ALLOWED) {
newParent = mInTaskFragment;
+ mStartActivity.mRequestedLaunchingTaskFragmentToken =
+ mInTaskFragment.getFragmentToken();
} else {
// Start mStartActivity to task instead if it can't be embedded to mInTaskFragment.
sendCanNotEmbedActivityError(mInTaskFragment, embeddingCheckResult);
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index c2afeaf8990e..8ad6012db201 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2574,6 +2574,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
*/
TaskFragmentInfo getTaskFragmentInfo() {
List<IBinder> childActivities = new ArrayList<>();
+ List<IBinder> inRequestedTaskFragmentActivities = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
final WindowContainer<?> wc = getChildAt(i);
final ActivityRecord ar = wc.asActivityRecord();
@@ -2582,6 +2583,9 @@ class TaskFragment extends WindowContainer<WindowContainer> {
&& ar.getUid() == mTaskFragmentOrganizerUid && !ar.finishing) {
// Only includes Activities that belong to the organizer process for security.
childActivities.add(ar.token);
+ if (ar.mRequestedLaunchingTaskFragmentToken == mFragmentToken) {
+ inRequestedTaskFragmentActivities.add(ar.token);
+ }
}
}
final Point positionInParent = new Point();
@@ -2593,6 +2597,7 @@ class TaskFragment extends WindowContainer<WindowContainer> {
getNonFinishingActivityCount(),
shouldBeVisible(null /* starting */),
childActivities,
+ inRequestedTaskFragmentActivities,
positionInParent,
mClearedTaskForReuse,
mClearedTaskFragmentForPip,