summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/TaskFragmentTransaction.java27
-rw-r--r--core/java/android/window/flags/windowing_sdk.aconfig5
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java79
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java31
-rw-r--r--libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java24
-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/ActivityRecord.java20
-rw-r--r--services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java71
8 files changed, 247 insertions, 18 deletions
diff --git a/core/java/android/window/TaskFragmentTransaction.java b/core/java/android/window/TaskFragmentTransaction.java
index 32e3f5ad10ca..1e5b0971aad6 100644
--- a/core/java/android/window/TaskFragmentTransaction.java
+++ b/core/java/android/window/TaskFragmentTransaction.java
@@ -189,6 +189,10 @@ public final class TaskFragmentTransaction implements Parcelable {
@Nullable
private IBinder mActivityToken;
+ /** @see #setOtherActivityToken(IBinder) */
+ @Nullable
+ private IBinder mOtherActivityToken;
+
@Nullable
private TaskFragmentParentInfo mTaskFragmentParentInfo;
@@ -210,6 +214,7 @@ public final class TaskFragmentTransaction implements Parcelable {
mActivityToken = in.readStrongBinder();
mTaskFragmentParentInfo = in.readTypedObject(TaskFragmentParentInfo.CREATOR);
mSurfaceControl = in.readTypedObject(SurfaceControl.CREATOR);
+ mOtherActivityToken = in.readStrongBinder();
}
@Override
@@ -224,6 +229,7 @@ public final class TaskFragmentTransaction implements Parcelable {
dest.writeStrongBinder(mActivityToken);
dest.writeTypedObject(mTaskFragmentParentInfo, flags);
dest.writeTypedObject(mSurfaceControl, flags);
+ dest.writeStrongBinder(mOtherActivityToken);
}
/** The change is related to the TaskFragment created with this unique token. */
@@ -292,6 +298,21 @@ public final class TaskFragmentTransaction implements Parcelable {
}
/**
+ * Token of another activity.
+ * <p>For {@link #TYPE_ACTIVITY_REPARENTED_TO_TASK}, it is the next activity (behind the
+ * reparented one) that fills the Task and occludes other activities. It will be the
+ * actual activity token if the activity belongs to the same process as the organizer.
+ * Otherwise, it is {@code null}.
+ *
+ * @hide
+ */
+ @NonNull
+ public Change setOtherActivityToken(@NonNull IBinder activityToken) {
+ mOtherActivityToken = requireNonNull(activityToken);
+ return this;
+ }
+
+ /**
* Sets info of the parent Task of the embedded TaskFragment.
* @see TaskFragmentParentInfo
*
@@ -350,6 +371,12 @@ public final class TaskFragmentTransaction implements Parcelable {
return mActivityToken;
}
+ /** @hide */
+ @Nullable
+ public IBinder getOtherActivityToken() {
+ return mOtherActivityToken;
+ }
+
/**
* Obtains the {@link TaskFragmentParentInfo} for this transaction.
*/
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 4d1b87a3d97a..b4678f6d812d 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -124,7 +124,10 @@ flag {
flag {
namespace: "windowing_sdk"
- name: "pip_restore_to_overlay"
+ name: "fix_pip_restore_to_overlay"
description: "Restore exit-pip activity back to ActivityEmbedding overlay"
bug: "297887697"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
} \ No newline at end of file
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 13c2d1f73461..b764b6ee065f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -50,6 +50,7 @@ import static androidx.window.extensions.embedding.SplitPresenter.getActivityInt
import static androidx.window.extensions.embedding.SplitPresenter.getMinDimensions;
import static androidx.window.extensions.embedding.SplitPresenter.sanitizeBounds;
import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit;
+import static androidx.window.extensions.embedding.TaskFragmentContainer.OverlayContainerRestoreParams;
import android.annotation.CallbackExecutor;
import android.app.Activity;
@@ -133,6 +134,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
/**
+ * Stores the token of the associated Activity that maps to the
+ * {@link OverlayContainerRestoreParams} of the most recent created overlay container.
+ */
+ @GuardedBy("mLock")
+ final ArrayMap<IBinder, OverlayContainerRestoreParams> mOverlayRestoreParams = new ArrayMap<>();
+
+ /**
* A developer-defined {@link SplitAttributes} calculator to compute the current
* {@link SplitAttributes} with the current device and window states.
* It is registered via {@link #setSplitAttributesCalculator(Function)}
@@ -686,11 +694,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
exception);
break;
case TYPE_ACTIVITY_REPARENTED_TO_TASK:
+ final IBinder candidateAssociatedActToken, lastOverlayToken;
+ if (Flags.fixPipRestoreToOverlay()) {
+ candidateAssociatedActToken = change.getOtherActivityToken();
+ lastOverlayToken = change.getTaskFragmentToken();
+ } else {
+ candidateAssociatedActToken = lastOverlayToken = null;
+ }
onActivityReparentedToTask(
wct,
taskId,
change.getActivityIntent(),
- change.getActivityToken());
+ change.getActivityToken(),
+ candidateAssociatedActToken,
+ lastOverlayToken);
break;
default:
throw new IllegalArgumentException(
@@ -917,11 +934,28 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* different process, the server will generate a temporary token that
* the organizer can use to reparent the activity through
* {@link WindowContainerTransaction} if needed.
+ * @param candidateAssociatedActToken The token of the candidate associated-activity.
+ * @param lastOverlayToken The last parent overlay container token.
*/
@VisibleForTesting
@GuardedBy("mLock")
void onActivityReparentedToTask(@NonNull WindowContainerTransaction wct,
- int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) {
+ int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken,
+ @Nullable IBinder candidateAssociatedActToken, @Nullable IBinder lastOverlayToken) {
+ // Reparent the activity to an overlay container if needed.
+ final OverlayContainerRestoreParams params = getOverlayContainerRestoreParams(
+ candidateAssociatedActToken, lastOverlayToken);
+ if (params != null) {
+ final Activity associatedActivity = getActivity(candidateAssociatedActToken);
+ final TaskFragmentContainer targetContainer = createOrUpdateOverlayTaskFragmentIfNeeded(
+ wct, params.mOptions, params.mIntent, associatedActivity);
+ if (targetContainer != null) {
+ wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(),
+ activityToken);
+ return;
+ }
+ }
+
// If the activity belongs to the current app process, we treat it as a new activity
// launch.
final Activity activity = getActivity(activityToken);
@@ -966,6 +1000,43 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
}
/**
+ * Returns the {@link OverlayContainerRestoreParams} that stored last time the {@code
+ * associatedActivityToken} associated with and only if data matches the {@code overlayToken}.
+ * Otherwise, return {@code null}.
+ */
+ @VisibleForTesting
+ @GuardedBy("mLock")
+ @Nullable
+ OverlayContainerRestoreParams getOverlayContainerRestoreParams(
+ @Nullable IBinder associatedActivityToken, @Nullable IBinder overlayToken) {
+ if (!Flags.fixPipRestoreToOverlay()) {
+ return null;
+ }
+
+ if (associatedActivityToken == null || overlayToken == null) {
+ return null;
+ }
+
+ final TaskFragmentContainer.OverlayContainerRestoreParams params =
+ mOverlayRestoreParams.get(associatedActivityToken);
+ if (params == null) {
+ return null;
+ }
+
+ if (params.mOverlayToken != overlayToken) {
+ // Not the same overlay container, no need to restore.
+ return null;
+ }
+
+ final Activity associatedActivity = getActivity(associatedActivityToken);
+ if (associatedActivity == null || associatedActivity.isFinishing()) {
+ return null;
+ }
+
+ return params;
+ }
+
+ /**
* Called when the {@link WindowContainerTransaction} created with
* {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
*
@@ -1433,6 +1504,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
mTaskContainers.valueAt(i).onFinishingActivityPaused(wct, activityToken);
}
+
+ mOverlayRestoreParams.remove(activity.getActivityToken());
updateCallbackIfNecessary();
}
@@ -1450,6 +1523,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
mTaskContainers.valueAt(i).onActivityDestroyed(wct, activityToken);
}
+
+ mOverlayRestoreParams.remove(activity.getActivityToken());
// We didn't trigger the callback if there were any pending appeared activities, so check
// again after the pending is removed.
updateCallbackIfNecessary();
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 482554351b97..d0b6a01bb51e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -36,6 +36,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
import java.util.ArrayList;
import java.util.Collections;
@@ -274,6 +275,15 @@ class TaskFragmentContainer {
addPendingAppearedActivity(pendingAppearedActivity);
}
mPendingAppearedIntent = pendingAppearedIntent;
+
+ // Save the information necessary for restoring the overlay when needed.
+ if (Flags.fixPipRestoreToOverlay() && overlayTag != null && pendingAppearedIntent != null
+ && associatedActivity != null && !associatedActivity.isFinishing()) {
+ final IBinder associatedActivityToken = associatedActivity.getActivityToken();
+ final OverlayContainerRestoreParams params = new OverlayContainerRestoreParams(mToken,
+ launchOptions, pendingAppearedIntent);
+ mController.mOverlayRestoreParams.put(associatedActivityToken, params);
+ }
}
/**
@@ -1105,4 +1115,25 @@ class TaskFragmentContainer {
}
return sb.append("]").toString();
}
+
+ static class OverlayContainerRestoreParams {
+ /** The token of the overlay container */
+ @NonNull
+ final IBinder mOverlayToken;
+
+ /** The launch options to create this container. */
+ @NonNull
+ final Bundle mOptions;
+
+ /** The Intent that used to be started in the overlay container. */
+ @NonNull
+ final Intent mIntent;
+
+ OverlayContainerRestoreParams(@NonNull IBinder overlayToken, @NonNull Bundle options,
+ @NonNull Intent intent) {
+ mOverlayToken = overlayToken;
+ mOptions = options;
+ mIntent = intent;
+ }
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 9ebcb759115d..f3222572a3e2 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -836,6 +836,30 @@ public class OverlayPresentationTest {
any());
}
+ @Test
+ public void testOnActivityReparentedToTask_overlayRestoration() {
+ mSetFlagRule.enableFlags(Flags.FLAG_FIX_PIP_RESTORE_TO_OVERLAY);
+
+ // Prepares and mock the data necessary for the test.
+ final IBinder activityToken = mActivity.getActivityToken();
+ final Intent intent = new Intent();
+ final IBinder fillTaskActivityToken = new Binder();
+ final IBinder lastOverlayToken = new Binder();
+ final TaskFragmentContainer overlayContainer = mSplitController.newContainer(intent,
+ mActivity, TASK_ID);
+ final TaskFragmentContainer.OverlayContainerRestoreParams params = mock(
+ TaskFragmentContainer.OverlayContainerRestoreParams.class);
+ doReturn(params).when(mSplitController).getOverlayContainerRestoreParams(any(), any());
+ doReturn(overlayContainer).when(mSplitController).createOrUpdateOverlayTaskFragmentIfNeeded(
+ any(), any(), any(), any());
+
+ // Verify the activity should be reparented to the overlay container.
+ mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken,
+ fillTaskActivityToken, lastOverlayToken);
+ verify(mTransaction).reparentActivityToTaskFragment(
+ eq(overlayContainer.getTaskFragmentToken()), eq(activityToken));
+ }
+
/**
* A simplified version of {@link SplitController#createOrUpdateOverlayTaskFragmentIfNeeded}
*/
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 7d86ec2272af..35353dbe36be 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
@@ -397,7 +397,8 @@ public class SplitControllerTest {
@Test
public void testOnActivityReparentedToTask_sameProcess() {
mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, new Intent(),
- mActivity.getActivityToken());
+ mActivity.getActivityToken(), null /* fillTaskActivityToken */,
+ null /* lastOverlayToken */);
// Treated as on activity created, but allow to split as primary.
verify(mSplitController).resolveActivityToContainer(mTransaction,
@@ -413,7 +414,8 @@ public class SplitControllerTest {
final IBinder activityToken = new Binder();
final Intent intent = new Intent();
- mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken);
+ mSplitController.onActivityReparentedToTask(mTransaction, TASK_ID, intent, activityToken,
+ null /* fillTaskActivityToken */, null /* lastOverlayToken */);
// Treated as starting new intent
verify(mSplitController, never()).resolveActivityToContainer(any(), any(), anyBoolean());
@@ -1210,7 +1212,7 @@ public class SplitControllerTest {
mSplitController.onTransactionReady(transaction);
verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
- eq(activityToken));
+ eq(activityToken), any(), any());
verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
anyInt(), anyBoolean());
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76e7f535c60f..d053bbb28ad1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -77,7 +77,6 @@ import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
@@ -87,6 +86,7 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
@@ -121,6 +121,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.ACTIVITY_EMBEDDING_GUARD_WITH_ANDROID_15;
+import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -128,7 +129,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED;
import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING;
-import static android.view.WindowManager.ENABLE_ACTIVITY_EMBEDDING_FOR_ANDROID_15;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OLD_UNSET;
@@ -682,6 +682,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// it references to gets removed. This should also be cleared when we move out of pip.
private Task mLastParentBeforePip;
+ // The token of the previous TaskFragment parent of this embedded ActivityRecord when it is
+ // reparented to a new Task due to picture-in-picture.
+ // Note that the TaskFragment may be finished and no longer attached in WM hierarchy.
+ @Nullable
+ private IBinder mLastEmbeddedParentTfTokenBeforePip;
+
// Only set if this instance is a launch-into-pip Activity, points to the
// host Activity the launch-into-pip Activity is originated from.
private ActivityRecord mLaunchIntoPipHostActivity;
@@ -1806,6 +1812,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLastTaskFragmentOrganizerBeforePip = organizedTf != null
? organizedTf.getTaskFragmentOrganizer()
: null;
+ if (organizedTf != null
+ // Not necessary for content pip.
+ && launchIntoPipHostActivity == null) {
+ mLastEmbeddedParentTfTokenBeforePip = organizedTf.getFragmentToken();
+ }
}
void clearLastParentBeforePip() {
@@ -1815,12 +1826,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
mLaunchIntoPipHostActivity = null;
mLastTaskFragmentOrganizerBeforePip = null;
+ mLastEmbeddedParentTfTokenBeforePip = null;
}
@Nullable Task getLastParentBeforePip() {
return mLastParentBeforePip;
}
+ @Nullable IBinder getLastEmbeddedParentTfTokenBeforePip() {
+ return mLastEmbeddedParentTfTokenBeforePip;
+ }
+
@Nullable ActivityRecord getLaunchIntoPipHostActivity() {
return mLaunchIntoPipHostActivity;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 24b533a23af6..c4e932abecd3 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -365,7 +365,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@Nullable
TaskFragmentTransaction.Change prepareActivityReparentedToTask(
- @NonNull ActivityRecord activity) {
+ @NonNull ActivityRecord activity, @Nullable ActivityRecord nextFillTaskActivity,
+ @Nullable IBinder lastParentTfToken) {
if (activity.finishing) {
Slog.d(TAG, "Reparent activity=" + activity.token + " is finishing");
return null;
@@ -408,10 +409,21 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Activity=%s reparent to taskId=%d",
activity.token, task.mTaskId);
- return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
- .setTaskId(task.mTaskId)
- .setActivityIntent(trimIntent(activity.intent))
- .setActivityToken(activityToken);
+
+ final TaskFragmentTransaction.Change change =
+ new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
+ .setTaskId(task.mTaskId)
+ .setActivityIntent(trimIntent(activity.intent))
+ .setActivityToken(activityToken);
+ if (lastParentTfToken != null) {
+ change.setTaskFragmentToken(lastParentTfToken);
+ }
+ // Only pass the activity token to the client if it belongs to the same process.
+ if (Flags.fixPipRestoreToOverlay() && nextFillTaskActivity != null
+ && nextFillTaskActivity.getPid() == mOrganizerPid) {
+ change.setOtherActivityToken(nextFillTaskActivity.token);
+ }
+ return change;
}
void dispatchTransaction(@NonNull TaskFragmentTransaction transaction) {
@@ -733,13 +745,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
void onActivityReparentedToTask(@NonNull ActivityRecord activity) {
+ final Task task = activity.getTask();
final ITaskFragmentOrganizer organizer;
if (activity.mLastTaskFragmentOrganizerBeforePip != null) {
// If the activity is previously embedded in an organized TaskFragment.
organizer = activity.mLastTaskFragmentOrganizerBeforePip;
} else {
// Find the topmost TaskFragmentOrganizer.
- final Task task = activity.getTask();
final TaskFragment[] organizedTf = new TaskFragment[1];
task.forAllLeafTaskFragments(tf -> {
if (tf.isOrganizedTaskFragment()) {
@@ -757,10 +769,24 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
Slog.w(TAG, "The last TaskFragmentOrganizer no longer exists");
return;
}
- addPendingEvent(new PendingTaskFragmentEvent.Builder(
+
+ final IBinder parentTfTokenBeforePip = activity.getLastEmbeddedParentTfTokenBeforePip();
+ final PendingTaskFragmentEvent.Builder builder = new PendingTaskFragmentEvent.Builder(
PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK, organizer)
.setActivity(activity)
- .build());
+ .setTaskFragmentToken(activity.getLastEmbeddedParentTfTokenBeforePip());
+
+ // Sets the next activity behinds the reparented Activity that's also not in the last
+ // embedded parent TF.
+ final ActivityRecord candidateAssociatedActivity = task.getActivity(
+ ar -> ar != activity && !ar.finishing
+ && ar.getTaskFragment().getFragmentToken() != parentTfTokenBeforePip);
+ if (candidateAssociatedActivity != null && (!candidateAssociatedActivity.isEmbedded()
+ || candidateAssociatedActivity.getTaskFragment().fillsParent())) {
+ builder.setOtherActivity(candidateAssociatedActivity);
+ }
+
+ addPendingEvent(builder.build());
}
void onTaskFragmentParentInfoChanged(@NonNull ITaskFragmentOrganizer organizer,
@@ -889,11 +915,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@Nullable
private final TaskFragment mTaskFragment;
@Nullable
+ private final IBinder mTaskFragmentToken;
+ @Nullable
private final IBinder mErrorCallbackToken;
@Nullable
private final Throwable mException;
@Nullable
private final ActivityRecord mActivity;
+ // An additional Activity that's needed to send back to the client other than the mActivity.
+ @Nullable
+ private final ActivityRecord mOtherActivity;
@Nullable
private final Task mTask;
// Set when the event is deferred due to the host task is invisible. The defer time will
@@ -905,17 +936,21 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
private PendingTaskFragmentEvent(@EventType int eventType,
ITaskFragmentOrganizer taskFragmentOrg,
@Nullable TaskFragment taskFragment,
+ @Nullable IBinder taskFragmentToken,
@Nullable IBinder errorCallbackToken,
@Nullable Throwable exception,
@Nullable ActivityRecord activity,
+ @Nullable ActivityRecord otherActivity,
@Nullable Task task,
@TaskFragmentOperation.OperationType int opType) {
mEventType = eventType;
mTaskFragmentOrg = taskFragmentOrg;
mTaskFragment = taskFragment;
+ mTaskFragmentToken = taskFragmentToken;
mErrorCallbackToken = errorCallbackToken;
mException = exception;
mActivity = activity;
+ mOtherActivity = otherActivity;
mTask = task;
mOpType = opType;
}
@@ -943,12 +978,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
@Nullable
private TaskFragment mTaskFragment;
@Nullable
+ private IBinder mTaskFragmentToken;
+ @Nullable
private IBinder mErrorCallbackToken;
@Nullable
private Throwable mException;
@Nullable
private ActivityRecord mActivity;
@Nullable
+ private ActivityRecord mOtherActivity;
+ @Nullable
private Task mTask;
@TaskFragmentOperation.OperationType
private int mOpType;
@@ -963,6 +1002,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return this;
}
+ Builder setTaskFragmentToken(@Nullable IBinder fragmentToken) {
+ mTaskFragmentToken = fragmentToken;
+ return this;
+ }
+
Builder setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
mErrorCallbackToken = errorCallbackToken;
return this;
@@ -978,6 +1022,11 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return this;
}
+ Builder setOtherActivity(@NonNull ActivityRecord otherActivity) {
+ mOtherActivity = otherActivity;
+ return this;
+ }
+
Builder setTask(@NonNull Task task) {
mTask = requireNonNull(task);
return this;
@@ -990,7 +1039,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
PendingTaskFragmentEvent build() {
return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment,
- mErrorCallbackToken, mException, mActivity, mTask, mOpType);
+ mTaskFragmentToken, mErrorCallbackToken, mException, mActivity,
+ mOtherActivity, mTask, mOpType);
}
}
}
@@ -1191,7 +1241,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return state.prepareTaskFragmentError(event.mErrorCallbackToken, taskFragment,
event.mOpType, event.mException);
case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENTED_TO_TASK:
- return state.prepareActivityReparentedToTask(event.mActivity);
+ return state.prepareActivityReparentedToTask(event.mActivity, event.mOtherActivity,
+ event.mTaskFragmentToken);
default:
throw new IllegalArgumentException("Unknown TaskFragmentEvent=" + event.mEventType);
}