Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 684dc6bd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Update TaskFragmentToken for Activity relaunch" into tm-qpr-dev am:...

Merge "Update TaskFragmentToken for Activity relaunch" into tm-qpr-dev am: 379c38b1 am: de4ca984

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19707668



Change-Id: Ic8407732ba353215b6e466247d1e8710bf59b51a
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents c7388938 de4ca984
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -533,9 +533,8 @@ 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;
        // The token of the TaskFragment that embedded this activity.
        @Nullable public IBinder mTaskFragmentToken;
        int ident;
        @UnsupportedAppUsage
        Intent intent;
@@ -619,7 +618,7 @@ public final class ActivityThread extends ClientTransactionHandler
                List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
                IBinder initialTaskFragmentToken) {
                IBinder taskFragmentToken) {
            this.token = token;
            this.assistToken = assistToken;
            this.shareableActivityToken = shareableActivityToken;
@@ -638,7 +637,7 @@ public final class ActivityThread extends ClientTransactionHandler
            this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo);
            mActivityOptions = activityOptions;
            mLaunchedFromBubble = launchedFromBubble;
            mInitialTaskFragmentToken = initialTaskFragmentToken;
            mTaskFragmentToken = taskFragmentToken;
            init();
        }

+10 −7
Original line number Diff line number Diff line
@@ -583,7 +583,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        }

        if (!isOnReparent && getContainerWithActivity(activity) == null
                && getInitialTaskFragmentToken(activity) != null) {
                && getTaskFragmentTokenFromActivityClientRecord(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.
@@ -866,11 +866,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    }

    @VisibleForTesting
    @GuardedBy("mLock")
    void onActivityDestroyed(@NonNull Activity activity) {
        // Remove any pending appeared activity, as the server won't send finished activity to the
        // organizer.
        for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
            mTaskContainers.valueAt(i).cleanupPendingAppearedActivity(activity);
            mTaskContainers.valueAt(i).onActivityDestroyed(activity);
        }
        // We didn't trigger the callback if there were any pending appeared activities, so check
        // again after the pending is removed.
@@ -1605,15 +1606,16 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    }

    /**
     * Gets the token of the initial TaskFragment that embedded this activity. Do not rely on it
     * after creation because the activity could be reparented.
     * Gets the token of the TaskFragment that embedded this activity. It is available as soon as
     * the activity is created and attached, so it can be used during {@link #onActivityCreated}
     * before the server notifies the organizer to avoid racing condition.
     */
    @VisibleForTesting
    @Nullable
    IBinder getInitialTaskFragmentToken(@NonNull Activity activity) {
    IBinder getTaskFragmentTokenFromActivityClientRecord(@NonNull Activity activity) {
        final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread()
                .getActivityClient(activity.getActivityToken());
        return record != null ? record.mInitialTaskFragmentToken : null;
        return record != null ? record.mTaskFragmentToken : null;
    }

    /**
@@ -1691,7 +1693,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                @Nullable Bundle savedInstanceState) {
            synchronized (mLock) {
                final IBinder activityToken = activity.getActivityToken();
                final IBinder initialTaskFragmentToken = getInitialTaskFragmentToken(activity);
                final IBinder initialTaskFragmentToken =
                        getTaskFragmentTokenFromActivityClientRecord(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) {
+7 −0
Original line number Diff line number Diff line
@@ -137,6 +137,13 @@ class TaskContainer {
        return mContainers.isEmpty() && mFinishedContainer.isEmpty();
    }

    /** Called when the activity is destroyed. */
    void onActivityDestroyed(@NonNull Activity activity) {
        for (TaskFragmentContainer container : mContainers) {
            container.onActivityDestroyed(activity);
        }
    }

    /** Removes the pending appeared activity from all TaskFragments in this Task. */
    void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
        for (TaskFragmentContainer container : mContainers) {
+35 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;

import android.app.Activity;
import android.app.ActivityThread;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Intent;
import android.graphics.Rect;
@@ -190,6 +191,19 @@ class TaskFragmentContainer {
        // Remove the pending activity from other TaskFragments.
        mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity);
        mPendingAppearedActivities.add(pendingAppearedActivity);
        updateActivityClientRecordTaskFragmentToken(pendingAppearedActivity);
    }

    /**
     * Updates the {@link ActivityThread.ActivityClientRecord#mTaskFragmentToken} for the
     * activity. This makes sure the token is up-to-date if the activity is relaunched later.
     */
    private void updateActivityClientRecordTaskFragmentToken(@NonNull Activity activity) {
        final ActivityThread.ActivityClientRecord record = ActivityThread
                .currentActivityThread().getActivityClient(activity.getActivityToken());
        if (record != null) {
            record.mTaskFragmentToken = mToken;
        }
    }

    void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
@@ -197,8 +211,29 @@ class TaskFragmentContainer {
    }

    void clearPendingAppearedActivities() {
        final List<Activity> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
        // Clear mPendingAppearedActivities so that #getContainerWithActivity won't return the
        // current TaskFragment.
        mPendingAppearedActivities.clear();
        mPendingAppearedIntent = null;

        // For removed pending activities, we need to update the them to their previous containers.
        for (Activity activity : cleanupActivities) {
            final TaskFragmentContainer curContainer = mController.getContainerWithActivity(
                    activity);
            if (curContainer != null) {
                curContainer.updateActivityClientRecordTaskFragmentToken(activity);
            }
        }
    }

    /** Called when the activity is destroyed. */
    void onActivityDestroyed(@NonNull Activity activity) {
        removePendingAppearedActivity(activity);
        if (mInfo != null) {
            // Remove the activity now because there can be a delay before the server callback.
            mInfo.getActivities().remove(activity.getActivityToken());
        }
    }

    @Nullable
+2 −1
Original line number Diff line number Diff line
@@ -930,7 +930,8 @@ public class SplitControllerTest {

    @Test
    public void testResolveActivityToContainer_inUnknownTaskFragment() {
        doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
        doReturn(new Binder()).when(mSplitController)
                .getTaskFragmentTokenFromActivityClientRecord(mActivity);

        // No need to handle when the new launched activity is in an unknown TaskFragment.
        assertTrue(mSplitController.resolveActivityToContainer(mTransaction, mActivity,
Loading