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

Commit d600010b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Convert TaskFragmentOrganizer callbacks to a transaction callback" into tm-qpr-dev

parents 4099b89e 6b94ca2d
Loading
Loading
Loading
Loading
+2 −47
Original line number Diff line number Diff line
@@ -16,54 +16,9 @@

package android.window;

import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentTransaction;

/** @hide */
oneway interface ITaskFragmentOrganizer {
    void onTaskFragmentAppeared(in TaskFragmentInfo taskFragmentInfo);
    void onTaskFragmentInfoChanged(in TaskFragmentInfo taskFragmentInfo);
    void onTaskFragmentVanished(in TaskFragmentInfo taskFragmentInfo);

    /**
     * Called when the parent leaf Task of organized TaskFragments is changed.
     * When the leaf Task is changed, the organizer may want to update the TaskFragments in one
     * transaction.
     *
     * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new
     * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override
     * bounds.
     */
    void onTaskFragmentParentInfoChanged(in IBinder fragmentToken, in Configuration parentConfig);

    /**
     * Called when the {@link WindowContainerTransaction} created with
     * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side.
     *
     * @param errorCallbackToken    Token set through {@link
     *                              WindowContainerTransaction#setErrorCallbackToken(IBinder)}
     * @param errorBundle       Bundle containing the exception, operation type and TaskFragmentInfo
     *                          if any. Should be created with
     *                          {@link TaskFragmentOrganizer#putErrorInfoInBundle}.
     */
    void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle errorBundle);

    /**
     * Called when an Activity is reparented to the Task with organized TaskFragment. For example,
     * when an Activity enters and then exits Picture-in-picture, it will be reparented back to its
     * orginial Task. In this case, we need to notify the organizer so that it can check if the
     * Activity matches any split rule.
     *
     * @param taskId            The Task that the activity is reparented to.
     * @param activityIntent    The intent that the activity is original launched with.
     * @param activityToken     If the activity belongs to the same process as the organizer, this
     *                          will be the actual activity token; if the activity belongs to a
     *                          different process, the server will generate a temporary token that
     *                          the organizer can use to reparent the activity through
     *                          {@link WindowContainerTransaction} if needed.
     */
    void onActivityReparentToTask(int taskId, in Intent activityIntent, in IBinder activityToken);
    void onTransactionReady(in TaskFragmentTransaction transaction);
}
+71 −45
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@

package android.window;

import static android.window.TaskFragmentTransaction.TYPE_ACTIVITY_REPARENT_TO_TASK;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_APPEARED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_ERROR;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED;
import static android.window.TaskFragmentTransaction.TYPE_TASK_FRAGMENT_VANISHED;

import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,6 +34,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.view.RemoteAnimationDefinition;

import java.util.List;
import java.util.concurrent.Executor;

/**
@@ -204,6 +212,67 @@ public class TaskFragmentOrganizer extends WindowOrganizer {
    public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
            @NonNull IBinder activityToken) {}

    /**
     * Called when the transaction is ready so that the organizer can update the TaskFragments based
     * on the changes in transaction.
     * @hide
     */
    public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
        final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
        for (TaskFragmentTransaction.Change change : changes) {
            // TODO(b/240519866): apply all changes in one WCT.
            switch (change.getType()) {
                case TYPE_TASK_FRAGMENT_APPEARED:
                    onTaskFragmentAppeared(change.getTaskFragmentInfo());
                    if (change.getTaskConfiguration() != null) {
                        // TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the
                        // same Task
                        onTaskFragmentParentInfoChanged(
                                change.getTaskFragmentToken(),
                                change.getTaskConfiguration());
                    }
                    break;
                case TYPE_TASK_FRAGMENT_INFO_CHANGED:
                    if (change.getTaskConfiguration() != null) {
                        // TODO(b/240519866): convert to pass TaskConfiguration for all TFs in the
                        // same Task
                        onTaskFragmentParentInfoChanged(
                                change.getTaskFragmentToken(),
                                change.getTaskConfiguration());
                    }
                    onTaskFragmentInfoChanged(change.getTaskFragmentInfo());
                    break;
                case TYPE_TASK_FRAGMENT_VANISHED:
                    onTaskFragmentVanished(change.getTaskFragmentInfo());
                    break;
                case TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED:
                    onTaskFragmentParentInfoChanged(
                            change.getTaskFragmentToken(),
                            change.getTaskConfiguration());
                    break;
                case TYPE_TASK_FRAGMENT_ERROR:
                    final Bundle errorBundle = change.getErrorBundle();
                    onTaskFragmentError(
                            change.getErrorCallbackToken(),
                            errorBundle.getParcelable(
                                    KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class),
                            errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
                            errorBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION,
                                    java.lang.Throwable.class));
                    break;
                case TYPE_ACTIVITY_REPARENT_TO_TASK:
                    onActivityReparentToTask(
                            change.getTaskId(),
                            change.getActivityIntent(),
                            change.getActivityToken());
                    break;
                default:
                    throw new IllegalArgumentException(
                            "Unknown TaskFragmentEvent=" + change.getType());
            }
        }
    }

    @Override
    public void applyTransaction(@NonNull WindowContainerTransaction t) {
        t.setTaskFragmentOrganizer(mInterface);
@@ -221,51 +290,8 @@ public class TaskFragmentOrganizer extends WindowOrganizer {

    private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() {
        @Override
        public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
            mExecutor.execute(
                    () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo));
        }

        @Override
        public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {
            mExecutor.execute(
                    () -> TaskFragmentOrganizer.this.onTaskFragmentInfoChanged(taskFragmentInfo));
        }

        @Override
        public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {
            mExecutor.execute(
                    () -> TaskFragmentOrganizer.this.onTaskFragmentVanished(taskFragmentInfo));
        }

        @Override
        public void onTaskFragmentParentInfoChanged(
                @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {
            mExecutor.execute(
                    () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged(
                            fragmentToken, parentConfig));
        }

        @Override
        public void onTaskFragmentError(
                @NonNull IBinder errorCallbackToken, @NonNull Bundle errorBundle) {
            mExecutor.execute(() -> {
                final TaskFragmentInfo info = errorBundle.getParcelable(
                        KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, TaskFragmentInfo.class);
                TaskFragmentOrganizer.this.onTaskFragmentError(
                        errorCallbackToken, info,
                        errorBundle.getInt(KEY_ERROR_CALLBACK_OP_TYPE),
                        (Throwable) errorBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION,
                                java.lang.Throwable.class));
            });
        }

        @Override
        public void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent,
                @NonNull IBinder activityToken) {
            mExecutor.execute(
                    () -> TaskFragmentOrganizer.this.onActivityReparentToTask(
                            taskId, activityIntent, activityToken));
        public void onTransactionReady(@NonNull TaskFragmentTransaction transaction) {
            mExecutor.execute(() -> TaskFragmentOrganizer.this.onTransactionReady(transaction));
        }
    };

+20 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

parcelable TaskFragmentTransaction;
parcelable TaskFragmentTransaction.Change;
+335 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

import static java.util.Objects.requireNonNull;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;

/**
 * Used to communicate information about what are changing on embedded TaskFragments belonging to
 * the same TaskFragmentOrganizer. A transaction can contain multiple changes.
 * @see TaskFragmentTransaction.Change
 * @hide
 */
public final class TaskFragmentTransaction implements Parcelable {

    private final ArrayList<Change> mChanges = new ArrayList<>();

    public TaskFragmentTransaction() {}

    private TaskFragmentTransaction(Parcel in) {
        in.readTypedList(mChanges, Change.CREATOR);
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeTypedList(mChanges);
    }

    /** Adds a {@link Change} to this transaction. */
    public void addChange(@Nullable Change change) {
        if (change != null) {
            mChanges.add(change);
        }
    }

    /** Whether this transaction contains any {@link Change}. */
    public boolean isEmpty() {
        return mChanges.isEmpty();
    }

    @NonNull
    public List<Change> getChanges() {
        return mChanges;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("TaskFragmentTransaction{changes=[");
        for (int i = 0; i < mChanges.size(); ++i) {
            if (i > 0) {
                sb.append(',');
            }
            sb.append(mChanges.get(i));
        }
        sb.append("]}");
        return sb.toString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    public static final Creator<TaskFragmentTransaction> CREATOR = new Creator<>() {
        @Override
        public TaskFragmentTransaction createFromParcel(Parcel in) {
            return new TaskFragmentTransaction(in);
        }

        @Override
        public TaskFragmentTransaction[] newArray(int size) {
            return new TaskFragmentTransaction[size];
        }
    };

    /** Change type: the TaskFragment is attached to the hierarchy. */
    public static final int TYPE_TASK_FRAGMENT_APPEARED = 1;

    /** Change type: the status of the TaskFragment is changed. */
    public static final int TYPE_TASK_FRAGMENT_INFO_CHANGED = 2;

    /** Change type: the TaskFragment is removed form the hierarchy. */
    public static final int TYPE_TASK_FRAGMENT_VANISHED = 3;

    /** Change type: the status of the parent leaf Task is changed. */
    public static final int TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED = 4;

    /** Change type: the TaskFragment related operation failed on the server side. */
    public static final int TYPE_TASK_FRAGMENT_ERROR = 5;

    /**
     * Change type: an Activity is reparented to the Task. For example, when an Activity enters and
     * then exits Picture-in-picture, it will be reparented back to its original Task. In this case,
     * we need to notify the organizer so that it can check if the Activity matches any split rule.
     */
    public static final int TYPE_ACTIVITY_REPARENT_TO_TASK = 6;

    @IntDef(prefix = { "TYPE_" }, value = {
            TYPE_TASK_FRAGMENT_APPEARED,
            TYPE_TASK_FRAGMENT_INFO_CHANGED,
            TYPE_TASK_FRAGMENT_VANISHED,
            TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED,
            TYPE_TASK_FRAGMENT_ERROR,
            TYPE_ACTIVITY_REPARENT_TO_TASK
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface ChangeType {}

    /** Represents the change an embedded TaskFragment undergoes. */
    public static final class Change implements Parcelable {

        /** @see ChangeType */
        @ChangeType
        private final int mType;

        /** @see #setTaskFragmentToken(IBinder) */
        @Nullable
        private IBinder mTaskFragmentToken;

        /** @see #setTaskFragmentInfo(TaskFragmentInfo) */
        @Nullable
        private TaskFragmentInfo mTaskFragmentInfo;

        /** @see #setTaskId(int) */
        private int mTaskId;

        /** @see #setTaskConfiguration(Configuration) */
        @Nullable
        private Configuration mTaskConfiguration;

        /** @see #setErrorCallbackToken(IBinder) */
        @Nullable
        private IBinder mErrorCallbackToken;

        /** @see #setErrorBundle(Bundle) */
        @Nullable
        private Bundle mErrorBundle;

        /** @see #setActivityIntent(Intent) */
        @Nullable
        private Intent mActivityIntent;

        /** @see #setActivityToken(IBinder) */
        @Nullable
        private IBinder mActivityToken;

        public Change(@ChangeType int type) {
            mType = type;
        }

        private Change(Parcel in) {
            mType = in.readInt();
            mTaskFragmentToken = in.readStrongBinder();
            mTaskFragmentInfo = in.readTypedObject(TaskFragmentInfo.CREATOR);
            mTaskId = in.readInt();
            mTaskConfiguration = in.readTypedObject(Configuration.CREATOR);
            mErrorCallbackToken = in.readStrongBinder();
            mErrorBundle = in.readBundle(TaskFragmentTransaction.class.getClassLoader());
            mActivityIntent = in.readTypedObject(Intent.CREATOR);
            mActivityToken = in.readStrongBinder();
        }

        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeInt(mType);
            dest.writeStrongBinder(mTaskFragmentToken);
            dest.writeTypedObject(mTaskFragmentInfo, flags);
            dest.writeInt(mTaskId);
            dest.writeTypedObject(mTaskConfiguration, flags);
            dest.writeStrongBinder(mErrorCallbackToken);
            dest.writeBundle(mErrorBundle);
            dest.writeTypedObject(mActivityIntent, flags);
            dest.writeStrongBinder(mActivityToken);
        }

        /** The change is related to the TaskFragment created with this unique token. */
        public Change setTaskFragmentToken(@NonNull IBinder taskFragmentToken) {
            mTaskFragmentToken = requireNonNull(taskFragmentToken);
            return this;
        }

        /** Info of the embedded TaskFragment. */
        public Change setTaskFragmentInfo(@NonNull TaskFragmentInfo info) {
            mTaskFragmentInfo = requireNonNull(info);
            return this;
        }

        /** Task id the parent Task. */
        public Change setTaskId(int taskId) {
            mTaskId = taskId;
            return this;
        }

        /** Configuration of the parent Task. */
        public Change setTaskConfiguration(@NonNull Configuration configuration) {
            mTaskConfiguration = requireNonNull(configuration);
            return this;
        }

        /**
         * If the {@link #TYPE_TASK_FRAGMENT_ERROR} is from a {@link WindowContainerTransaction}
         * from the {@link TaskFragmentOrganizer}, it may come with an error callback token to
         * report back.
         */
        public Change setErrorCallbackToken(@Nullable IBinder errorCallbackToken) {
            mErrorCallbackToken = errorCallbackToken;
            return this;
        }

        /**
         * Bundle with necessary info about the failure operation of
         * {@link #TYPE_TASK_FRAGMENT_ERROR}.
         */
        public Change setErrorBundle(@NonNull Bundle errorBundle) {
            mErrorBundle = requireNonNull(errorBundle);
            return this;
        }

        /**
         * Intent of the activity that is reparented to the Task for
         * {@link #TYPE_ACTIVITY_REPARENT_TO_TASK}.
         */
        public Change setActivityIntent(@NonNull Intent intent) {
            mActivityIntent = requireNonNull(intent);
            return this;
        }

        /**
         * Token of the reparent activity for {@link #TYPE_ACTIVITY_REPARENT_TO_TASK}.
         * If the activity belongs to the same process as the organizer, this will be the actual
         * activity token; if the activity belongs to a different process, the server will generate
         * a temporary token that the organizer can use to reparent the activity through
         * {@link WindowContainerTransaction} if needed.
         */
        public Change setActivityToken(@NonNull IBinder activityToken) {
            mActivityToken = requireNonNull(activityToken);
            return this;
        }

        @ChangeType
        public int getType() {
            return mType;
        }

        @Nullable
        public IBinder getTaskFragmentToken() {
            return mTaskFragmentToken;
        }

        @Nullable
        public TaskFragmentInfo getTaskFragmentInfo() {
            return mTaskFragmentInfo;
        }

        public int getTaskId() {
            return mTaskId;
        }

        @Nullable
        public Configuration getTaskConfiguration() {
            return mTaskConfiguration;
        }

        @Nullable
        public IBinder getErrorCallbackToken() {
            return mErrorCallbackToken;
        }

        @Nullable
        public Bundle getErrorBundle() {
            return mErrorBundle;
        }

        @Nullable
        public Intent getActivityIntent() {
            return mActivityIntent;
        }

        @Nullable
        public IBinder getActivityToken() {
            return mActivityToken;
        }

        @Override
        public String toString() {
            return "Change{ type=" + mType + " }";
        }

        @Override
        public int describeContents() {
            return 0;
        }

        public static final Creator<Change> CREATOR = new Creator<>() {
            @Override
            public Change createFromParcel(Parcel in) {
                return new Change(in);
            }

            @Override
            public Change[] newArray(int size) {
                return new Change[size];
            }
        };
    }
}
+184 −103

File changed.

Preview size limit exceeded, changes collapsed.

Loading