diff options
10 files changed, 74 insertions, 16 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 3b843a9c622a..852dd974ae42 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -536,6 +536,9 @@ public final class ActivityThread extends ClientTransactionHandler // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be // used without security checks public IBinder shareableActivityToken; + // The token of the initial TaskFragment that embedded this activity. Do not rely on it + // after creation because the activity could be reparented. + @Nullable public IBinder mInitialTaskFragmentToken; int ident; @UnsupportedAppUsage Intent intent; @@ -618,7 +621,8 @@ public final class ActivityThread extends ClientTransactionHandler PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client, - IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble) { + IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble, + IBinder initialTaskFragmentToken) { this.token = token; this.assistToken = assistToken; this.shareableActivityToken = shareableActivityToken; @@ -639,6 +643,7 @@ public final class ActivityThread extends ClientTransactionHandler compatInfo); mActivityOptions = activityOptions; mLaunchedFromBubble = launchedFromBubble; + mInitialTaskFragmentToken = initialTaskFragmentToken; init(); } diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index d7e09519bfb7..076dbef9ebc4 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -72,6 +72,7 @@ public class LaunchActivityItem extends ClientTransactionItem { private IBinder mAssistToken; private IBinder mShareableActivityToken; private boolean mLaunchedFromBubble; + private IBinder mTaskFragmentToken; /** * It is only non-null if the process is the first time to launch activity. It is only an * optimization for quick look up of the interface so the field is ignored for comparison. @@ -95,7 +96,8 @@ public class LaunchActivityItem extends ClientTransactionItem { ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, - client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble); + client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, + mTaskFragmentToken); client.handleLaunchActivity(r, pendingActions, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -119,7 +121,7 @@ public class LaunchActivityItem extends ClientTransactionItem { List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, IActivityClientController activityClientController, IBinder shareableActivityToken, - boolean launchedFromBubble) { + boolean launchedFromBubble, IBinder taskFragmentToken) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { instance = new LaunchActivityItem(); @@ -128,7 +130,7 @@ public class LaunchActivityItem extends ClientTransactionItem { voiceInteractor, procState, state, persistentState, pendingResults, pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken, activityClientController, shareableActivityToken, - launchedFromBubble); + launchedFromBubble, taskFragmentToken); return instance; } @@ -136,7 +138,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void recycle() { setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null, - null, false, null, null, null, null, false); + null, false, null, null, null, null, false, null); ObjectPool.recycle(this); } @@ -166,6 +168,7 @@ public class LaunchActivityItem extends ClientTransactionItem { dest.writeStrongInterface(mActivityClientController); dest.writeStrongBinder(mShareableActivityToken); dest.writeBoolean(mLaunchedFromBubble); + dest.writeStrongBinder(mTaskFragmentToken); } /** Read from Parcel. */ @@ -184,7 +187,8 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readStrongBinder(), IActivityClientController.Stub.asInterface(in.readStrongBinder()), in.readStrongBinder(), - in.readBoolean()); + in.readBoolean(), + in.readStrongBinder()); } public static final @NonNull Creator<LaunchActivityItem> CREATOR = @@ -222,7 +226,8 @@ public class LaunchActivityItem extends ClientTransactionItem { && mIsForward == other.mIsForward && Objects.equals(mProfilerInfo, other.mProfilerInfo) && Objects.equals(mAssistToken, other.mAssistToken) - && Objects.equals(mShareableActivityToken, other.mShareableActivityToken); + && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) + && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken); } @Override @@ -244,6 +249,7 @@ public class LaunchActivityItem extends ClientTransactionItem { result = 31 * result + Objects.hashCode(mProfilerInfo); result = 31 * result + Objects.hashCode(mAssistToken); result = 31 * result + Objects.hashCode(mShareableActivityToken); + result = 31 * result + Objects.hashCode(mTaskFragmentToken); return result; } @@ -291,7 +297,7 @@ public class LaunchActivityItem extends ClientTransactionItem { List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken, IActivityClientController activityClientController, - IBinder shareableActivityToken, boolean launchedFromBubble) { + IBinder shareableActivityToken, boolean launchedFromBubble, IBinder taskFragmentToken) { instance.mIntent = intent; instance.mIdent = ident; instance.mInfo = info; @@ -312,5 +318,6 @@ public class LaunchActivityItem extends ClientTransactionItem { instance.mActivityClientController = activityClientController; instance.mShareableActivityToken = shareableActivityToken; instance.mLaunchedFromBubble = launchedFromBubble; + instance.mTaskFragmentToken = taskFragmentToken; } } diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index 3e261a7113ac..50639be57f22 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -157,7 +157,7 @@ public class ObjectPoolTests { .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList()) .setIsForward(true).setAssistToken(assistToken) .setShareableActivityToken(shareableActivityToken) - .build(); + .setTaskFragmentToken(new Binder()).build(); LaunchActivityItem emptyItem = new LaunchActivityItemBuilder().build(); LaunchActivityItem item = itemSupplier.get(); diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java index 1467fed898c4..26d9628ba55b 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java +++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java @@ -110,6 +110,7 @@ class TestUtils { private IBinder mAssistToken; private IBinder mShareableActivityToken; private boolean mLaunchedFromBubble; + private IBinder mTaskFragmentToken; LaunchActivityItemBuilder setIntent(Intent intent) { mIntent = intent; @@ -206,13 +207,18 @@ class TestUtils { return this; } + LaunchActivityItemBuilder setTaskFragmentToken(IBinder taskFragmentToken) { + mTaskFragmentToken = taskFragmentToken; + return this; + } + LaunchActivityItem build() { return LaunchActivityItem.obtain(mIntent, mIdent, mInfo, mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */, mShareableActivityToken, - mLaunchedFromBubble); + mLaunchedFromBubble, mTaskFragmentToken); } } } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index beadc4464516..8276d10be4cd 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -203,6 +203,7 @@ public class TransactionParcelTests { .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic()) .setPendingNewIntents(referrerIntentList()).setIsForward(true) .setAssistToken(new Binder()).setShareableActivityToken(new Binder()) + .setTaskFragmentToken(new Binder()) .build(); writeAndPrepareForReading(item); diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index b006a1681a99..8d3751e6ad6c 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -345,7 +345,7 @@ public class ActivityThreadClientTest { null /* pendingResults */, null /* pendingNewIntents */, null /* activityOptions */, true /* isForward */, null /* profilerInfo */, mThread /* client */, null /* asssitToken */, null /* shareableActivityToken */, - false /* launchedFromBubble */); + false /* launchedFromBubble */, null /* taskfragmentToken */); } @Override 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 c76fa9658c67..01f5feb9b13e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -615,14 +615,22 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return null; } + private void updateCallbackIfNecessary() { + updateCallbackIfNecessary(true /* deferCallbackUntilAllActivitiesCreated */); + } + /** * Notifies listeners about changes to split states if necessary. + * + * @param deferCallbackUntilAllActivitiesCreated boolean to indicate whether the split info + * callback should be deferred until all the + * organized activities have been created. */ - private void updateCallbackIfNecessary() { + private void updateCallbackIfNecessary(boolean deferCallbackUntilAllActivitiesCreated) { if (mEmbeddingCallback == null) { return; } - if (!allActivitiesCreated()) { + if (deferCallbackUntilAllActivitiesCreated && !allActivitiesCreated()) { return; } List<SplitInfo> currentSplitStates = getActiveSplitStates(); @@ -838,6 +846,36 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private final class LifecycleCallbacks extends EmptyLifecycleCallbacksAdapter { @Override + public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) { + final IBinder activityToken = activity.getActivityToken(); + final IBinder initialTaskFragmentToken = ActivityThread.currentActivityThread() + .getActivityClient(activityToken).mInitialTaskFragmentToken; + // 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; + } + for (int i = mTaskContainers.size() - 1; i >= 0; i--) { + final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i) + .mContainers; + 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 and send a split info callback to the client before + // {@link Activity#onCreate} is called. + container.addPendingAppearedActivity(activity); + updateCallbackIfNecessary( + false /* deferCallbackUntilAllActivitiesCreated */); + return; + } + } + } + } + + @Override public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) { // Calling after Activity#onCreate is complete to allow the app launch something // first. In case of a configured placeholder activity we want to make sure 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 e49af41d4eac..9a12669f078a 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -120,7 +120,7 @@ class TaskFragmentContainer { } ActivityStack toActivityStack() { - return new ActivityStack(collectActivities(), mInfo.getRunningActivityCount() == 0); + return new ActivityStack(collectActivities(), isEmpty()); } void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index eb5ca9c2f43b..95de040551b1 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -897,6 +897,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { proc.getThread(), r.token); final boolean isTransitionForward = r.isTransitionForward(); + final IBinder fragmentToken = r.getTaskFragment().getFragmentToken(); clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global @@ -907,7 +908,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), results, newIntents, r.takeOptions(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, - r.shareableActivityToken, r.getLaunchedFromBubble())); + r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken)); // Set desired final state. final ActivityLifecycleItem lifecycleItem; diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 3a458fdc75bb..900963e29bd6 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -2262,7 +2262,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { mFragmentToken, mRemoteToken.toWindowContainerToken(), getConfiguration(), - getChildCount() == 0, + runningActivityCount[0] == 0, runningActivityCount[0], isVisible(), childActivities, |