Loading core/java/android/window/ITaskFragmentOrganizer.aidl +2 −47 Original line number Diff line number Diff line Loading @@ -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); } core/java/android/window/TaskFragmentOrganizer.java +71 −45 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; /** Loading Loading @@ -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); Loading @@ -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)); } }; Loading core/java/android/window/TaskFragmentTransaction.aidl 0 → 100644 +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; core/java/android/window/TaskFragmentTransaction.java 0 → 100644 +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]; } }; } } services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +184 −103 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/window/ITaskFragmentOrganizer.aidl +2 −47 Original line number Diff line number Diff line Loading @@ -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); }
core/java/android/window/TaskFragmentOrganizer.java +71 −45 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; /** Loading Loading @@ -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); Loading @@ -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)); } }; Loading
core/java/android/window/TaskFragmentTransaction.aidl 0 → 100644 +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;
core/java/android/window/TaskFragmentTransaction.java 0 → 100644 +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]; } }; } }
services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +184 −103 File changed.Preview size limit exceeded, changes collapsed. Show changes