Do not resolve activity creation if it is in unknown TaskFragment

This can happen in two cases:
1. The activity is embedded in another app. Then the current organizer
   shouldn't control it.
2. The activity is in a TaskFragment that the organizer just request to
   remove, but hasn't reach the server side. Then the activity will soon
   be finished with the TaskFragment.

In either case, the organizer shouldn't need to resolve it. Otherwise it
may incorrectly change the state, such as entering split for a finishing
activity.

Bug: 233295443
Test: atest WMJetpackUnitTests:SplitControllerTest
Change-Id: I5d2028dd45abd8d20a8e82bc4e51c4d6dc6e26ee
This commit is contained in:
Chris Li
2022-05-21 00:44:41 +08:00
parent fc974566b8
commit 9d4244ee6f
2 changed files with 36 additions and 3 deletions

View File

@@ -363,7 +363,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* @param activity the activity that is newly added to the Task.
* @param isOnReparent whether the activity is reparented to the Task instead of new launched.
* We only support to split as primary for reparented activity for now.
* @return {@code true} if the activity was placed in TaskFragment container.
* @return {@code true} if the activity has been handled, such as placed in a TaskFragment, or
* in a state that the caller shouldn't handle.
*/
@VisibleForTesting
boolean resolveActivityToContainer(@NonNull Activity activity, boolean isOnReparent) {
@@ -373,6 +374,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return true;
}
if (!isOnReparent && getContainerWithActivity(activity) == null
&& getInitialTaskFragmentToken(activity) != null) {
// We can't find the new launched activity in any recorded container, but it is
// currently placed in an embedded TaskFragment. This can happen in two cases:
// 1. the activity is embedded in another app.
// 2. the organizer has already requested to remove the TaskFragment.
// In either case, return true since we don't want any extra handling.
Log.d(TAG, "Activity is in a TaskFragment that is not recorded by the organizer. r="
+ activity);
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.
@@ -1285,6 +1298,18 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
return ActivityThread.currentActivityThread().getActivity(activityToken);
}
/**
* Gets the token of the initial TaskFragment that embedded this activity. Do not rely on it
* after creation because the activity could be reparented.
*/
@VisibleForTesting
@Nullable
IBinder getInitialTaskFragmentToken(@NonNull Activity activity) {
final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread()
.getActivityClient(activity.getActivityToken());
return record != null ? record.mInitialTaskFragmentToken : null;
}
/**
* Returns {@code true} if an Activity with the provided component name should always be
* expanded to occupy full task bounds. Such activity must not be put in a split.
@@ -1358,8 +1383,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
@Override
public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) {
final IBinder activityToken = activity.getActivityToken();
final IBinder initialTaskFragmentToken = ActivityThread.currentActivityThread()
.getActivityClient(activityToken).mInitialTaskFragmentToken;
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 (initialTaskFragmentToken == null) {

View File

@@ -733,6 +733,15 @@ public class SplitControllerTest {
assertSplitPair(mActivity, primaryActivity);
}
@Test
public void testResolveActivityToContainer_inUnknownTaskFragment() {
doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
// No need to handle when the new launched activity is in an unknown TaskFragment.
assertTrue(mSplitController.resolveActivityToContainer(mActivity,
false /* isOnReparent */));
}
@Test
public void testGetPlaceholderOptions() {
doReturn(true).when(mActivity).isResumed();