Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +196 −159 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.util.SparseArray; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; import androidx.annotation.GuardedBy; import androidx.window.common.EmptyLifecycleCallbacksAdapter; import com.android.internal.annotations.VisibleForTesting; Loading @@ -65,9 +66,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private static final String TAG = "SplitController"; @VisibleForTesting @GuardedBy("mLock") final SplitPresenter mPresenter; // Currently applied split configuration. @GuardedBy("mLock") private final List<EmbeddingRule> mSplitRules = new ArrayList<>(); /** * Map from Task id to {@link TaskContainer} which contains all TaskFragment and split pair info Loading @@ -76,6 +79,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen * organizer. */ @VisibleForTesting @GuardedBy("mLock") final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>(); // Callback to Jetpack to notify about changes to split states. Loading @@ -83,6 +87,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private Consumer<List<SplitInfo>> mEmbeddingCallback; private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>(); private final Handler mHandler; private final Object mLock = new Object(); public SplitController() { final MainThreadExecutor executor = new MainThreadExecutor(); Loading @@ -100,45 +105,34 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen /** Updates the embedding rules applied to future activity launches. */ @Override public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) { synchronized (mLock) { mSplitRules.clear(); mSplitRules.addAll(rules); for (int i = mTaskContainers.size() - 1; i >= 0; i--) { updateAnimationOverride(mTaskContainers.valueAt(i)); } } } @NonNull public List<EmbeddingRule> getSplitRules() { List<EmbeddingRule> getSplitRules() { return mSplitRules; } /** * Starts an activity to side of the launchingActivity with the provided split config. */ public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent, @Nullable Bundle options, @NonNull SplitRule sideRule, @Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) { try { mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule, isPlaceholder); } catch (Exception e) { if (failureCallback != null) { failureCallback.accept(e); } } } /** * Registers the split organizer callback to notify about changes to active splits. */ @Override public void setSplitInfoCallback(@NonNull Consumer<List<SplitInfo>> callback) { synchronized (mLock) { mEmbeddingCallback = callback; updateCallbackIfNecessary(); } } @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { synchronized (mLock) { TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); if (container == null) { return; Loading @@ -150,9 +144,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } updateCallbackIfNecessary(); } } @Override public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { synchronized (mLock) { TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); if (container == null) { return; Loading @@ -162,21 +158,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen final boolean wasInPip = isInPictureInPicture(container); container.setInfo(taskFragmentInfo); final boolean isInPip = isInPictureInPicture(container); // Check if there are no running activities - consider the container empty if there are no // non-finishing activities left. // Check if there are no running activities - consider the container empty if there are // no non-finishing activities left. if (!taskFragmentInfo.hasRunningActivity()) { if (taskFragmentInfo.isTaskFragmentClearedForPip()) { // Do not finish the dependents if the last activity is reparented to PiP. // Instead, the original split should be cleanup, and the dependent may be expanded // to fullscreen. // Instead, the original split should be cleanup, and the dependent may be // expanded to fullscreen. cleanupForEnterPip(wct, container); mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else if (taskFragmentInfo.isTaskClearedForReuse()) { // Do not finish the dependents if this TaskFragment was cleared due to launching // activity in the Task. // Do not finish the dependents if this TaskFragment was cleared due to // launching activity in the Task. mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else if (!container.isWaitingActivityAppear()) { // Do not finish the container before the expected activity appear until timeout. // Do not finish the container before the expected activity appear until // timeout. mPresenter.cleanupContainer(container, true /* shouldFinishDependent */, wct); } } else if (wasInPip && isInPip) { Loading @@ -190,16 +187,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen cleanupForEnterPip(wct, container); } else if (wasInPip) { // Exit PIP. // Updates the presentation of the container. Expand or launch placeholder if needed. // Updates the presentation of the container. Expand or launch placeholder if // needed. updateContainer(wct, container); } mPresenter.applyTransaction(wct); updateCallbackIfNecessary(); } } @Override public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { final TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); synchronized (mLock) { final TaskFragmentContainer container = getContainer( taskFragmentInfo.getFragmentToken()); if (container != null) { // Cleanup if the TaskFragment vanished is not requested by the organizer. removeContainer(container); Loading @@ -215,10 +216,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } cleanupTaskFragment(taskFragmentInfo.getFragmentToken()); } } @Override public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) { synchronized (mLock) { final TaskFragmentContainer container = getContainer(fragmentToken); if (container != null) { onTaskConfigurationChanged(container.getTaskId(), parentConfig); Loading @@ -230,17 +233,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen updateCallbackIfNecessary(); } } } @Override public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) { // If the activity belongs to the current app process, we treat it as a new activity launch. synchronized (mLock) { // If the activity belongs to the current app process, we treat it as a new activity // launch. final Activity activity = getActivity(activityToken); if (activity != null) { // We don't allow split as primary for new launch because we currently only support // launching to top. We allow split as primary for activity reparent because the // activity may be split as primary before it is reparented out. In that case, we want // to show it as primary again when it is reparented back. // activity may be split as primary before it is reparented out. In that case, we // want to show it as primary again when it is reparented back. if (!resolveActivityToContainer(activity, true /* isOnReparent */)) { // When there is no embedding rule matched, try to place it in the top container // like a normal launch. Loading @@ -256,25 +262,27 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return; } // If the activity belongs to a different app process, we treat it as starting new intent, // since both actions might result in a new activity that should appear in an organized // TaskFragment. // If the activity belongs to a different app process, we treat it as starting new // intent, since both actions might result in a new activity that should appear in an // organized TaskFragment. final WindowContainerTransaction wct = new WindowContainerTransaction(); TaskFragmentContainer targetContainer = resolveStartActivityIntent(wct, taskId, activityIntent, null /* launchingActivity */); if (targetContainer == null) { // When there is no embedding rule matched, try to place it in the top container like a // normal launch. // When there is no embedding rule matched, try to place it in the top container // like a normal launch. targetContainer = taskContainer.getTopTaskFragmentContainer(); } if (targetContainer == null) { return; } wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(), activityToken); wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(), activityToken); mPresenter.applyTransaction(wct); // Because the activity does not belong to the organizer process, we wait until // onTaskFragmentAppeared to trigger updateCallbackIfNecessary(). } } /** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */ private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) { Loading Loading @@ -480,6 +488,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen mPresenter.applyTransaction(wct); } /** * Starts an activity to side of the launchingActivity with the provided split config. */ private void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent, @Nullable Bundle options, @NonNull SplitRule sideRule, @Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) { try { mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule, isPlaceholder); } catch (Exception e) { if (failureCallback != null) { failureCallback.accept(e); } } } /** * Expands the given activity by either expanding the TaskFragment it is currently in or putting * it into a new expanded TaskFragment. Loading Loading @@ -1382,10 +1406,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @Override public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) { synchronized (mLock) { final IBinder activityToken = activity.getActivityToken(); final IBinder initialTaskFragmentToken = getInitialTaskFragmentToken(activity); // If the activity is not embedded, then it will not have an initial task fragment token // so no further action is needed. // If the activity is not embedded, then it will not have an initial task fragment // token so no further action is needed. if (initialTaskFragmentToken == null) { return; } Loading @@ -1395,16 +1420,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen for (int j = containers.size() - 1; j >= 0; j--) { final TaskFragmentContainer container = containers.get(j); if (!container.hasActivity(activityToken) && container.getTaskFragmentToken().equals(initialTaskFragmentToken)) { // The onTaskFragmentInfoChanged callback containing this activity has not // reached the client yet, so add the activity to the pending appeared // activities. && container.getTaskFragmentToken() .equals(initialTaskFragmentToken)) { // The onTaskFragmentInfoChanged callback containing this activity has // not reached the client yet, so add the activity to the pending // appeared activities. container.addPendingAppearedActivity(activity); return; } } } } } @Override public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) { Loading @@ -1412,19 +1439,25 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // first. In case of a configured placeholder activity we want to make sure // that we don't launch it if an activity itself already requested something to be // launched to side. synchronized (mLock) { SplitController.this.onActivityCreated(activity); } } @Override public void onActivityConfigurationChanged(Activity activity) { synchronized (mLock) { SplitController.this.onActivityConfigurationChanged(activity); } } @Override public void onActivityPostDestroyed(Activity activity) { synchronized (mLock) { SplitController.this.onActivityDestroyed(activity); } } } /** Executor that posts on the main application thread. */ private static class MainThreadExecutor implements Executor { Loading Loading @@ -1457,17 +1490,19 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return super.onStartActivity(who, intent, options); } synchronized (mLock) { final int taskId = getTaskId(launchingActivity); final WindowContainerTransaction wct = new WindowContainerTransaction(); final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct, taskId, intent, launchingActivity); if (launchedInTaskFragment != null) { mPresenter.applyTransaction(wct); // Amend the request to let the WM know that the activity should be placed in the // dedicated container. // Amend the request to let the WM know that the activity should be placed in // the dedicated container. options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN, launchedInTaskFragment.getTaskFragmentToken()); } } return super.onStartActivity(who, intent, options); } Loading @@ -1479,8 +1514,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Override public boolean isActivityEmbedded(@NonNull Activity activity) { synchronized (mLock) { return mPresenter.isActivityEmbedded(activity.getActivityToken()); } } /** * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +196 −159 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.util.SparseArray; import android.window.TaskFragmentInfo; import android.window.WindowContainerTransaction; import androidx.annotation.GuardedBy; import androidx.window.common.EmptyLifecycleCallbacksAdapter; import com.android.internal.annotations.VisibleForTesting; Loading @@ -65,9 +66,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private static final String TAG = "SplitController"; @VisibleForTesting @GuardedBy("mLock") final SplitPresenter mPresenter; // Currently applied split configuration. @GuardedBy("mLock") private final List<EmbeddingRule> mSplitRules = new ArrayList<>(); /** * Map from Task id to {@link TaskContainer} which contains all TaskFragment and split pair info Loading @@ -76,6 +79,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen * organizer. */ @VisibleForTesting @GuardedBy("mLock") final SparseArray<TaskContainer> mTaskContainers = new SparseArray<>(); // Callback to Jetpack to notify about changes to split states. Loading @@ -83,6 +87,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private Consumer<List<SplitInfo>> mEmbeddingCallback; private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>(); private final Handler mHandler; private final Object mLock = new Object(); public SplitController() { final MainThreadExecutor executor = new MainThreadExecutor(); Loading @@ -100,45 +105,34 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen /** Updates the embedding rules applied to future activity launches. */ @Override public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) { synchronized (mLock) { mSplitRules.clear(); mSplitRules.addAll(rules); for (int i = mTaskContainers.size() - 1; i >= 0; i--) { updateAnimationOverride(mTaskContainers.valueAt(i)); } } } @NonNull public List<EmbeddingRule> getSplitRules() { List<EmbeddingRule> getSplitRules() { return mSplitRules; } /** * Starts an activity to side of the launchingActivity with the provided split config. */ public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent, @Nullable Bundle options, @NonNull SplitRule sideRule, @Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) { try { mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule, isPlaceholder); } catch (Exception e) { if (failureCallback != null) { failureCallback.accept(e); } } } /** * Registers the split organizer callback to notify about changes to active splits. */ @Override public void setSplitInfoCallback(@NonNull Consumer<List<SplitInfo>> callback) { synchronized (mLock) { mEmbeddingCallback = callback; updateCallbackIfNecessary(); } } @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { synchronized (mLock) { TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); if (container == null) { return; Loading @@ -150,9 +144,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } updateCallbackIfNecessary(); } } @Override public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { synchronized (mLock) { TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); if (container == null) { return; Loading @@ -162,21 +158,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen final boolean wasInPip = isInPictureInPicture(container); container.setInfo(taskFragmentInfo); final boolean isInPip = isInPictureInPicture(container); // Check if there are no running activities - consider the container empty if there are no // non-finishing activities left. // Check if there are no running activities - consider the container empty if there are // no non-finishing activities left. if (!taskFragmentInfo.hasRunningActivity()) { if (taskFragmentInfo.isTaskFragmentClearedForPip()) { // Do not finish the dependents if the last activity is reparented to PiP. // Instead, the original split should be cleanup, and the dependent may be expanded // to fullscreen. // Instead, the original split should be cleanup, and the dependent may be // expanded to fullscreen. cleanupForEnterPip(wct, container); mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else if (taskFragmentInfo.isTaskClearedForReuse()) { // Do not finish the dependents if this TaskFragment was cleared due to launching // activity in the Task. // Do not finish the dependents if this TaskFragment was cleared due to // launching activity in the Task. mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct); } else if (!container.isWaitingActivityAppear()) { // Do not finish the container before the expected activity appear until timeout. // Do not finish the container before the expected activity appear until // timeout. mPresenter.cleanupContainer(container, true /* shouldFinishDependent */, wct); } } else if (wasInPip && isInPip) { Loading @@ -190,16 +187,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen cleanupForEnterPip(wct, container); } else if (wasInPip) { // Exit PIP. // Updates the presentation of the container. Expand or launch placeholder if needed. // Updates the presentation of the container. Expand or launch placeholder if // needed. updateContainer(wct, container); } mPresenter.applyTransaction(wct); updateCallbackIfNecessary(); } } @Override public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { final TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken()); synchronized (mLock) { final TaskFragmentContainer container = getContainer( taskFragmentInfo.getFragmentToken()); if (container != null) { // Cleanup if the TaskFragment vanished is not requested by the organizer. removeContainer(container); Loading @@ -215,10 +216,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } cleanupTaskFragment(taskFragmentInfo.getFragmentToken()); } } @Override public void onTaskFragmentParentInfoChanged(@NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) { synchronized (mLock) { final TaskFragmentContainer container = getContainer(fragmentToken); if (container != null) { onTaskConfigurationChanged(container.getTaskId(), parentConfig); Loading @@ -230,17 +233,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen updateCallbackIfNecessary(); } } } @Override public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken) { // If the activity belongs to the current app process, we treat it as a new activity launch. synchronized (mLock) { // If the activity belongs to the current app process, we treat it as a new activity // launch. final Activity activity = getActivity(activityToken); if (activity != null) { // We don't allow split as primary for new launch because we currently only support // launching to top. We allow split as primary for activity reparent because the // activity may be split as primary before it is reparented out. In that case, we want // to show it as primary again when it is reparented back. // activity may be split as primary before it is reparented out. In that case, we // want to show it as primary again when it is reparented back. if (!resolveActivityToContainer(activity, true /* isOnReparent */)) { // When there is no embedding rule matched, try to place it in the top container // like a normal launch. Loading @@ -256,25 +262,27 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return; } // If the activity belongs to a different app process, we treat it as starting new intent, // since both actions might result in a new activity that should appear in an organized // TaskFragment. // If the activity belongs to a different app process, we treat it as starting new // intent, since both actions might result in a new activity that should appear in an // organized TaskFragment. final WindowContainerTransaction wct = new WindowContainerTransaction(); TaskFragmentContainer targetContainer = resolveStartActivityIntent(wct, taskId, activityIntent, null /* launchingActivity */); if (targetContainer == null) { // When there is no embedding rule matched, try to place it in the top container like a // normal launch. // When there is no embedding rule matched, try to place it in the top container // like a normal launch. targetContainer = taskContainer.getTopTaskFragmentContainer(); } if (targetContainer == null) { return; } wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(), activityToken); wct.reparentActivityToTaskFragment(targetContainer.getTaskFragmentToken(), activityToken); mPresenter.applyTransaction(wct); // Because the activity does not belong to the organizer process, we wait until // onTaskFragmentAppeared to trigger updateCallbackIfNecessary(). } } /** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */ private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) { Loading Loading @@ -480,6 +488,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen mPresenter.applyTransaction(wct); } /** * Starts an activity to side of the launchingActivity with the provided split config. */ private void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent, @Nullable Bundle options, @NonNull SplitRule sideRule, @Nullable Consumer<Exception> failureCallback, boolean isPlaceholder) { try { mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule, isPlaceholder); } catch (Exception e) { if (failureCallback != null) { failureCallback.accept(e); } } } /** * Expands the given activity by either expanding the TaskFragment it is currently in or putting * it into a new expanded TaskFragment. Loading Loading @@ -1382,10 +1406,11 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @Override public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) { synchronized (mLock) { final IBinder activityToken = activity.getActivityToken(); final IBinder initialTaskFragmentToken = getInitialTaskFragmentToken(activity); // If the activity is not embedded, then it will not have an initial task fragment token // so no further action is needed. // If the activity is not embedded, then it will not have an initial task fragment // token so no further action is needed. if (initialTaskFragmentToken == null) { return; } Loading @@ -1395,16 +1420,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen for (int j = containers.size() - 1; j >= 0; j--) { final TaskFragmentContainer container = containers.get(j); if (!container.hasActivity(activityToken) && container.getTaskFragmentToken().equals(initialTaskFragmentToken)) { // The onTaskFragmentInfoChanged callback containing this activity has not // reached the client yet, so add the activity to the pending appeared // activities. && container.getTaskFragmentToken() .equals(initialTaskFragmentToken)) { // The onTaskFragmentInfoChanged callback containing this activity has // not reached the client yet, so add the activity to the pending // appeared activities. container.addPendingAppearedActivity(activity); return; } } } } } @Override public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) { Loading @@ -1412,19 +1439,25 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen // first. In case of a configured placeholder activity we want to make sure // that we don't launch it if an activity itself already requested something to be // launched to side. synchronized (mLock) { SplitController.this.onActivityCreated(activity); } } @Override public void onActivityConfigurationChanged(Activity activity) { synchronized (mLock) { SplitController.this.onActivityConfigurationChanged(activity); } } @Override public void onActivityPostDestroyed(Activity activity) { synchronized (mLock) { SplitController.this.onActivityDestroyed(activity); } } } /** Executor that posts on the main application thread. */ private static class MainThreadExecutor implements Executor { Loading Loading @@ -1457,17 +1490,19 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return super.onStartActivity(who, intent, options); } synchronized (mLock) { final int taskId = getTaskId(launchingActivity); final WindowContainerTransaction wct = new WindowContainerTransaction(); final TaskFragmentContainer launchedInTaskFragment = resolveStartActivityIntent(wct, taskId, intent, launchingActivity); if (launchedInTaskFragment != null) { mPresenter.applyTransaction(wct); // Amend the request to let the WM know that the activity should be placed in the // dedicated container. // Amend the request to let the WM know that the activity should be placed in // the dedicated container. options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN, launchedInTaskFragment.getTaskFragmentToken()); } } return super.onStartActivity(who, intent, options); } Loading @@ -1479,8 +1514,10 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Override public boolean isActivityEmbedded(@NonNull Activity activity) { synchronized (mLock) { return mPresenter.isActivityEmbedded(activity.getActivityToken()); } } /** * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if Loading