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

Commit 8834b35c authored by Louis Chang's avatar Louis Chang Committed by Android (Google) Code Review
Browse files

Merge "Reconstruct the containers from the saved state" into main

parents aa5dd681 959e0337
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -68,6 +68,23 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
     */
    public static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type";

    /**
     * Key to bundle {@link TaskFragmentInfo}s from the system in
     * {@link #registerOrganizer(boolean, Bundle)}
     *
     * @hide
     */
    public static final String KEY_RESTORE_TASK_FRAGMENTS_INFO = "key_restore_task_fragments_info";

    /**
     * Key to bundle {@link TaskFragmentParentInfo} from the system in
     * {@link #registerOrganizer(boolean, Bundle)}
     *
     * @hide
     */
    public static final String KEY_RESTORE_TASK_FRAGMENT_PARENT_INFO =
            "key_restore_task_fragment_parent_info";

    /**
     * No change set.
     */
+110 −11
Original line number Diff line number Diff line
@@ -16,16 +16,26 @@

package androidx.window.extensions.embedding;

import static android.window.TaskFragmentOrganizer.KEY_RESTORE_TASK_FRAGMENTS_INFO;
import static android.window.TaskFragmentOrganizer.KEY_RESTORE_TASK_FRAGMENT_PARENT_INFO;

import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentParentInfo;
import android.window.WindowContainerTransaction;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Helper class to back up and restore the TaskFragmentOrganizer state, in order to resume
@@ -40,11 +50,21 @@ class BackupHelper {
    @NonNull
    private final SplitController mController;
    @NonNull
    private final SplitPresenter mPresenter;
    @NonNull
    private final BackupIdler mBackupIdler = new BackupIdler();
    private boolean mBackupIdlerScheduled;

    BackupHelper(@NonNull SplitController splitController, @NonNull Bundle savedState) {
    private final List<ParcelableTaskContainerData> mParcelableTaskContainerDataList =
            new ArrayList<>();
    private final ArrayMap<IBinder, TaskFragmentInfo> mTaskFragmentInfos = new ArrayMap<>();
    private final SparseArray<TaskFragmentParentInfo> mTaskFragmentParentInfos =
            new SparseArray<>();

    BackupHelper(@NonNull SplitController splitController, @NonNull SplitPresenter splitPresenter,
            @NonNull Bundle savedState) {
        mController = splitController;
        mPresenter = splitPresenter;

        if (!savedState.isEmpty()) {
            restoreState(savedState);
@@ -67,13 +87,13 @@ class BackupHelper {
        public boolean queueIdle() {
            synchronized (mController.mLock) {
                mBackupIdlerScheduled = false;
                startBackup();
                saveState();
            }
            return false;
        }
    }

    private void startBackup() {
    private void saveState() {
        final List<TaskContainer> taskContainers = mController.getTaskContainers();
        if (taskContainers.isEmpty()) {
            Log.w(TAG, "No task-container to back up");
@@ -97,13 +117,92 @@ class BackupHelper {
            return;
        }

        final List<ParcelableTaskContainerData> parcelableTaskContainerDataList =
                savedState.getParcelableArrayList(KEY_TASK_CONTAINERS,
                        ParcelableTaskContainerData.class);
        for (ParcelableTaskContainerData data : parcelableTaskContainerDataList) {
            final TaskContainer taskContainer = new TaskContainer(data, mController);
            if (DEBUG) Log.d(TAG, "Restoring task " + taskContainer.getTaskId());
            // TODO(b/289875940): implement the TaskContainer restoration.
        if (DEBUG) Log.d(TAG, "Start restoring saved-state");
        mParcelableTaskContainerDataList.addAll(savedState.getParcelableArrayList(
                KEY_TASK_CONTAINERS, ParcelableTaskContainerData.class));
        if (DEBUG) Log.d(TAG, "Retrieved tasks : " + mParcelableTaskContainerDataList.size());
        if (mParcelableTaskContainerDataList.isEmpty()) {
            return;
        }

        final List<TaskFragmentInfo> infos = savedState.getParcelableArrayList(
                KEY_RESTORE_TASK_FRAGMENTS_INFO, TaskFragmentInfo.class);
        for (TaskFragmentInfo info : infos) {
            if (DEBUG) Log.d(TAG, "Retrieved: " + info);
            mTaskFragmentInfos.put(info.getFragmentToken(), info);
            mPresenter.updateTaskFragmentInfo(info);
        }

        final List<TaskFragmentParentInfo> parentInfos = savedState.getParcelableArrayList(
                KEY_RESTORE_TASK_FRAGMENT_PARENT_INFO,
                TaskFragmentParentInfo.class);
        for (TaskFragmentParentInfo info : parentInfos) {
            if (DEBUG) Log.d(TAG, "Retrieved: " + info);
            mTaskFragmentParentInfos.put(info.getTaskId(), info);
        }
    }

    boolean hasPendingStateToRestore() {
        return !mParcelableTaskContainerDataList.isEmpty();
    }

    /**
     * Returns {@code true} if any of the {@link TaskContainer} is restored.
     * Otherwise, returns {@code false}.
     */
    boolean rebuildTaskContainers(@NonNull WindowContainerTransaction wct,
            @NonNull Set<EmbeddingRule> rules) {
        if (mParcelableTaskContainerDataList.isEmpty()) {
            return false;
        }

        if (DEBUG) Log.d(TAG, "Rebuilding TaskContainers.");
        final ArrayMap<String, EmbeddingRule> embeddingRuleMap = new ArrayMap<>();
        for (EmbeddingRule rule : rules) {
            embeddingRuleMap.put(rule.getTag(), rule);
        }

        boolean restoredAny = false;
        for (int i = mParcelableTaskContainerDataList.size() - 1; i >= 0; i--) {
            final ParcelableTaskContainerData parcelableTaskContainerData =
                    mParcelableTaskContainerDataList.get(i);
            final List<String> tags = parcelableTaskContainerData.getSplitRuleTags();
            if (!embeddingRuleMap.containsAll(tags)) {
                // has unknown tag, unable to restore.
                if (DEBUG) {
                    Log.d(TAG, "Rebuilding TaskContainer abort! Unknown Tag. Task#"
                            + parcelableTaskContainerData.mTaskId);
                }
                continue;
            }

            mParcelableTaskContainerDataList.remove(parcelableTaskContainerData);
            final TaskContainer taskContainer = new TaskContainer(parcelableTaskContainerData,
                    mController, mTaskFragmentInfos);
            if (DEBUG) Log.d(TAG, "Created TaskContainer " + taskContainer);
            mController.addTaskContainer(taskContainer.getTaskId(), taskContainer);

            for (ParcelableSplitContainerData splitData :
                    parcelableTaskContainerData.getParcelableSplitContainerDataList()) {
                final SplitRule rule = (SplitRule) embeddingRuleMap.get(splitData.mSplitRuleTag);
                assert rule != null;
                if (mController.getContainer(splitData.getPrimaryContainerToken()) != null
                        && mController.getContainer(splitData.getSecondaryContainerToken())
                        != null) {
                    taskContainer.addSplitContainer(
                            new SplitContainer(splitData, mController, rule));
                }
            }

            mController.onTaskFragmentParentRestored(wct, taskContainer.getTaskId(),
                    mTaskFragmentParentInfos.get(taskContainer.getTaskId()));
            restoredAny = true;
        }

        if (mParcelableTaskContainerDataList.isEmpty()) {
            mTaskFragmentParentInfos.clear();
            mTaskFragmentInfos.clear();
        }
        return restoredAny;
    }
}
 No newline at end of file
+2 −2
Original line number Diff line number Diff line
@@ -89,13 +89,13 @@ class ParcelableSplitContainerData implements Parcelable {
    };

    @NonNull
    private IBinder getPrimaryContainerToken() {
    IBinder getPrimaryContainerToken() {
        return mSplitContainer != null ? mSplitContainer.getPrimaryContainer().getToken()
                : mPrimaryContainerToken;
    }

    @NonNull
    private IBinder getSecondaryContainerToken() {
    IBinder getSecondaryContainerToken() {
        return mSplitContainer != null ? mSplitContainer.getSecondaryContainer().getToken()
                : mSecondaryContainerToken;
    }
+9 −0
Original line number Diff line number Diff line
@@ -108,6 +108,15 @@ class ParcelableTaskContainerData implements Parcelable {
                : mParcelableSplitContainerDataList;
    }

    @NonNull
    List<String> getSplitRuleTags() {
        final List<String> tags = new ArrayList<>();
        for (ParcelableSplitContainerData data : getParcelableSplitContainerDataList()) {
            tags.add(data.mSplitRuleTag);
        }
        return tags;
    }

    @Override
    public int describeContents() {
        return 0;
+19 −0
Original line number Diff line number Diff line
@@ -86,6 +86,25 @@ class SplitContainer {
        }
    }

    /** This is only used when restoring it from a {@link ParcelableSplitContainerData}. */
    SplitContainer(@NonNull ParcelableSplitContainerData parcelableData,
            @NonNull SplitController splitController, @NonNull SplitRule splitRule) {
        mParcelableData = parcelableData;
        mPrimaryContainer = splitController.getContainer(parcelableData.getPrimaryContainerToken());
        mSecondaryContainer = splitController.getContainer(
                parcelableData.getSecondaryContainerToken());
        mSplitRule = splitRule;
        mDefaultSplitAttributes = splitRule.getDefaultSplitAttributes();
        mCurrentSplitAttributes = mDefaultSplitAttributes;

        if (shouldFinishPrimaryWithSecondary(splitRule)) {
            mSecondaryContainer.addContainerToFinishOnExit(mPrimaryContainer);
        }
        if (shouldFinishSecondaryWithPrimary(splitRule)) {
            mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
        }
    }

    void setPrimaryContainer(@NonNull TaskFragmentContainer primaryContainer) {
        if (!mParcelableData.mIsPrimaryContainerMutable) {
            throw new IllegalStateException("Cannot update primary TaskFragmentContainer");
Loading