diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl index 0bfc2541061ca..5eb432e785ee2 100644 --- a/core/java/android/window/ITaskFragmentOrganizer.aidl +++ b/core/java/android/window/ITaskFragmentOrganizer.aidl @@ -17,6 +17,7 @@ package android.window; import android.content.res.Configuration; +import android.os.Bundle; import android.os.IBinder; import android.window.TaskFragmentAppearedInfo; import android.window.TaskFragmentInfo; @@ -37,4 +38,15 @@ oneway interface ITaskFragmentOrganizer { * 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 exceptionBundle Bundle containing the exception. Should be created with + * {@link TaskFragmentOrganizer#putExceptionInBundle}. + */ + void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle exceptionBundle); } diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 51722cccb44d1..78c55a223eaf0 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -19,6 +19,7 @@ package android.window; import android.annotation.CallSuper; import android.annotation.NonNull; import android.content.res.Configuration; +import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -30,6 +31,21 @@ import java.util.concurrent.Executor; */ public class TaskFragmentOrganizer extends WindowOrganizer { + /** + * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}. + */ + private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception"; + + /** + * Creates a {@link Bundle} with an exception that can be passed to + * {@link ITaskFragmentOrganizer#onTaskFragmentError}. + */ + public static Bundle putExceptionInBundle(@NonNull Throwable exception) { + final Bundle exceptionBundle = new Bundle(); + exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); + return exceptionBundle; + } + /** * Callbacks from WM Core are posted on this executor. */ @@ -93,6 +109,17 @@ public class TaskFragmentOrganizer extends WindowOrganizer { public void onTaskFragmentParentInfoChanged( @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {} + /** + * Called when the {@link WindowContainerTransaction} created with + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side. + * + * @param errorCallbackToken token set in + * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} + * @param exception exception from the server side. + */ + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} + private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { @Override public void onTaskFragmentAppeared(@NonNull TaskFragmentAppearedInfo taskFragmentInfo) { @@ -119,6 +146,14 @@ public class TaskFragmentOrganizer extends WindowOrganizer { () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged( fragmentToken, parentConfig)); } + + @Override + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) { + mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError( + errorCallbackToken, + (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION))); + } }; private ITaskFragmentOrganizerController getController() { diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 8c3dc2e2044e9..9c512add3345a 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -49,11 +49,15 @@ public final class WindowContainerTransaction implements Parcelable { // Flat list because re-order operations are order-dependent private final ArrayList mHierarchyOps = new ArrayList<>(); + @Nullable + private IBinder mErrorCallbackToken; + public WindowContainerTransaction() {} private WindowContainerTransaction(Parcel in) { in.readMap(mChanges, null /* loader */); in.readList(mHierarchyOps, null /* loader */); + mErrorCallbackToken = in.readStrongBinder(); } private Change getOrCreateChange(IBinder token) { @@ -475,6 +479,23 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + /** + * When this {@link WindowContainerTransaction} failed to finish on the server side, it will + * trigger callback with this {@param errorCallbackToken}. + * @param errorCallbackToken client provided token that will be passed back as parameter in + * the callback if there is an error on the server side. + * @see ITaskFragmentOrganizer#onTaskFragmentError + * @hide + */ + @NonNull + public WindowContainerTransaction setErrorCallbackToken(@NonNull IBinder errorCallbackToken) { + if (mErrorCallbackToken != null) { + throw new IllegalStateException("Can't set multiple error token for one transaction."); + } + mErrorCallbackToken = errorCallbackToken; + return this; + } + /** * Merges another WCT into this one. * @param transfer When true, this will transfer everything from other potentially leaving @@ -496,6 +517,13 @@ public final class WindowContainerTransaction implements Parcelable { mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i) : new HierarchyOp(other.mHierarchyOps.get(i))); } + if (mErrorCallbackToken != null && other.mErrorCallbackToken != null && mErrorCallbackToken + != other.mErrorCallbackToken) { + throw new IllegalArgumentException("Can't merge two WCT with different error token"); + } + mErrorCallbackToken = mErrorCallbackToken != null + ? mErrorCallbackToken + : other.mErrorCallbackToken; } /** @hide */ @@ -513,11 +541,17 @@ public final class WindowContainerTransaction implements Parcelable { return mHierarchyOps; } + /** @hide */ + @Nullable + public IBinder getErrorCallbackToken() { + return mErrorCallbackToken; + } + @Override @NonNull public String toString() { return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps - + " }"; + + " errorCallbackToken=" + mErrorCallbackToken + " }"; } @Override @@ -525,6 +559,7 @@ public final class WindowContainerTransaction implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeMap(mChanges); dest.writeList(mHierarchyOps); + dest.writeStrongBinder(mErrorCallbackToken); } @Override