diff options
10 files changed, 204 insertions, 54 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 8bfb1aef1989..da5b88bbfbf4 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3350,7 +3350,8 @@ package android.window { method @NonNull public java.util.concurrent.Executor getExecutor(); method @NonNull public android.window.TaskFragmentOrganizerToken getOrganizerToken(); method public void onTaskFragmentAppeared(@NonNull android.window.TaskFragmentInfo); - method public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable); + method @Deprecated public void onTaskFragmentError(@NonNull android.os.IBinder, @NonNull Throwable); + method public void onTaskFragmentError(@NonNull android.os.IBinder, @Nullable android.window.TaskFragmentInfo, int, @NonNull Throwable); method public void onTaskFragmentInfoChanged(@NonNull android.window.TaskFragmentInfo); method public void onTaskFragmentParentInfoChanged(@NonNull android.os.IBinder, @NonNull android.content.res.Configuration); method public void onTaskFragmentVanished(@NonNull android.window.TaskFragmentInfo); diff --git a/core/java/android/window/ITaskFragmentOrganizer.aidl b/core/java/android/window/ITaskFragmentOrganizer.aidl index 8dfda7d41c2d..3335c9c073e0 100644 --- a/core/java/android/window/ITaskFragmentOrganizer.aidl +++ b/core/java/android/window/ITaskFragmentOrganizer.aidl @@ -45,10 +45,11 @@ oneway interface ITaskFragmentOrganizer { * * @param errorCallbackToken Token set through {@link * WindowContainerTransaction#setErrorCallbackToken(IBinder)} - * @param exceptionBundle Bundle containing the exception. Should be created with - * {@link TaskFragmentOrganizer#putExceptionInBundle}. + * @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 exceptionBundle); + void onTaskFragmentError(in IBinder errorCallbackToken, in Bundle errorBundle); /** * Called when an Activity is reparented to the Task with organized TaskFragment. For example, diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java index 2ef49c3e2aac..e4a6ad87053c 100644 --- a/core/java/android/window/TaskFragmentOrganizer.java +++ b/core/java/android/window/TaskFragmentOrganizer.java @@ -18,6 +18,7 @@ package android.window; import android.annotation.CallSuper; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; import android.content.Intent; import android.content.res.Configuration; @@ -39,16 +40,23 @@ 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"; + private static final String KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO = "task_fragment_info"; + private static final String KEY_ERROR_CALLBACK_OP_TYPE = "operation_type"; /** - * Creates a {@link Bundle} with an exception that can be passed to - * {@link ITaskFragmentOrganizer#onTaskFragmentError}. + * Creates a {@link Bundle} with an exception, operation type and TaskFragmentInfo (if any) + * that can be passed to {@link ITaskFragmentOrganizer#onTaskFragmentError}. * @hide */ - public static Bundle putExceptionInBundle(@NonNull Throwable exception) { - final Bundle exceptionBundle = new Bundle(); - exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); - return exceptionBundle; + public static @NonNull Bundle putErrorInfoInBundle(@NonNull Throwable exception, + @Nullable TaskFragmentInfo info, int opType) { + final Bundle errorBundle = new Bundle(); + errorBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); + if (info != null) { + errorBundle.putParcelable(KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO, info); + } + errorBundle.putInt(KEY_ERROR_CALLBACK_OP_TYPE, opType); + return errorBundle; } /** @@ -151,11 +159,34 @@ public class TaskFragmentOrganizer extends WindowOrganizer { * @param errorCallbackToken token set in * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} * @param exception exception from the server side. + * + * @deprecated Use {@link #onTaskFragmentError(IBinder, TaskFragmentInfo, int, Throwable)} + * instead. */ + @Deprecated public void onTaskFragmentError( @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} /** + * 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 taskFragmentInfo The {@link TaskFragmentInfo}. This could be {@code null} if no + * TaskFragment created. + * @param opType The {@link WindowContainerTransaction.HierarchyOp} of the failed + * transaction operation. + * @param exception exception from the server side. + */ + public void onTaskFragmentError( + @NonNull IBinder errorCallbackToken, @Nullable TaskFragmentInfo taskFragmentInfo, + int opType, @NonNull Throwable exception) { + // Doing so to keep compatibility. This will be removed in the next release. + onTaskFragmentError(errorCallbackToken, exception); + } + + /** * 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 @@ -217,10 +248,16 @@ public class TaskFragmentOrganizer extends WindowOrganizer { @Override public void onTaskFragmentError( - @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) { - mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError( - errorCallbackToken, - (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION))); + @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 diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java index 3ff531573f1f..0dba6b0049c0 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java @@ -72,6 +72,7 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { @NonNull Configuration parentConfig); void onActivityReparentToTask(int taskId, @NonNull Intent activityIntent, @NonNull IBinder activityToken); + void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType); } /** @@ -323,4 +324,18 @@ class JetpackTaskFragmentOrganizer extends TaskFragmentOrganizer { mCallback.onActivityReparentToTask(taskId, activityIntent, activityToken); } } + + @Override + public void onTaskFragmentError(@NonNull IBinder errorCallbackToken, + @Nullable TaskFragmentInfo taskFragmentInfo, + int opType, @NonNull Throwable exception) { + if (taskFragmentInfo != null) { + final IBinder fragmentToken = taskFragmentInfo.getFragmentToken(); + mFragmentInfos.put(fragmentToken, taskFragmentInfo); + } + + if (mCallback != null) { + mCallback.onTaskFragmentError(taskFragmentInfo, opType); + } + } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index da9fd0c2d96f..c688080ad929 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -19,6 +19,8 @@ package androidx.window.extensions.embedding; import static android.app.ActivityManager.START_SUCCESS; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static androidx.window.extensions.embedding.SplitContainer.getFinishPrimaryWithSecondaryBehavior; import static androidx.window.extensions.embedding.SplitContainer.getFinishSecondaryWithPrimaryBehavior; @@ -296,6 +298,37 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } } + @Override + public void onTaskFragmentError(@Nullable TaskFragmentInfo taskFragmentInfo, int opType) { + synchronized (mLock) { + switch (opType) { + case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: + case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: { + final TaskFragmentContainer container; + if (taskFragmentInfo != null) { + container = getContainer(taskFragmentInfo.getFragmentToken()); + } else { + container = null; + } + if (container == null) { + break; + } + + // Update the latest taskFragmentInfo and perform necessary clean-up + container.setInfo(taskFragmentInfo); + container.clearPendingAppearedActivities(); + if (container.isEmpty()) { + mPresenter.cleanupContainer(container, false /* shouldFinishDependent */); + } + break; + } + default: + Log.e(TAG, "onTaskFragmentError: taskFragmentInfo = " + taskFragmentInfo + + ", opType = " + opType); + } + } + } + /** Called on receiving {@link #onTaskFragmentVanished(TaskFragmentInfo)} for cleanup. */ private void cleanupTaskFragment(@NonNull IBinder taskFragmentToken) { for (int i = mTaskContainers.size() - 1; i >= 0; i--) { diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index a188e2bf4985..37f5b6dc399e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -193,6 +193,11 @@ class TaskFragmentContainer { mPendingAppearedActivities.remove(pendingAppearedActivity); } + void clearPendingAppearedActivities() { + mPendingAppearedActivities.clear(); + mPendingAppearedIntent = null; + } + @Nullable Intent getPendingAppearedIntent() { return mPendingAppearedIntent; diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 890b91025151..393c1be9f686 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -56,6 +56,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.INVALID_UID; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_OPEN; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS; @@ -3011,6 +3012,7 @@ class ActivityStarter { if (taskFragment.isOrganized()) { mService.mWindowOrganizerController.sendTaskFragmentOperationFailure( taskFragment.getTaskFragmentOrganizer(), mRequest.errorCallbackToken, + taskFragment, HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT, new SecurityException(errMsg)); } else { // If the taskFragment is not organized, just dump error message as warning logs. diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 392d4c2f772b..d4551becbaaf 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static android.window.TaskFragmentOrganizer.putExceptionInBundle; +import static android.window.TaskFragmentOrganizer.putErrorInfoInBundle; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED; @@ -214,12 +214,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } - void onTaskFragmentError(IBinder errorCallbackToken, Throwable exception) { + void onTaskFragmentError(IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, + int opType, Throwable exception) { ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Sending TaskFragment error exception=%s", exception.toString()); - final Bundle exceptionBundle = putExceptionInBundle(exception); + final TaskFragmentInfo info = + taskFragment != null ? taskFragment.getTaskFragmentInfo() : null; + final Bundle errorBundle = putErrorInfoInBundle(exception, info, opType); try { - mOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle); + mOrganizer.onTaskFragmentError(errorCallbackToken, errorBundle); } catch (RemoteException e) { Slog.d(TAG, "Exception sending onTaskFragmentError callback", e); } @@ -462,13 +465,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken, - Throwable exception) { + TaskFragment taskFragment, int opType, Throwable exception) { validateAndGetState(organizer); Slog.w(TAG, "onTaskFragmentError ", exception); final PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent.Builder( PendingTaskFragmentEvent.EVENT_ERROR, organizer) .setErrorCallbackToken(errorCallbackToken) + .setTaskFragment(taskFragment) .setException(exception) + .setOpType(opType) .build(); mPendingTaskFragmentEvents.add(pendingEvent); // Make sure the error event will be dispatched if there are no other changes. @@ -567,19 +572,22 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr // Set when the event is deferred due to the host task is invisible. The defer time will // be the last active time of the host task. private long mDeferTime; + private int mOpType; private PendingTaskFragmentEvent(@EventType int eventType, ITaskFragmentOrganizer taskFragmentOrg, @Nullable TaskFragment taskFragment, @Nullable IBinder errorCallbackToken, @Nullable Throwable exception, - @Nullable ActivityRecord activity) { + @Nullable ActivityRecord activity, + int opType) { mEventType = eventType; mTaskFragmentOrg = taskFragmentOrg; mTaskFragment = taskFragment; mErrorCallbackToken = errorCallbackToken; mException = exception; mActivity = activity; + mOpType = opType; } /** @@ -610,6 +618,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr private Throwable mException; @Nullable private ActivityRecord mActivity; + private int mOpType; Builder(@EventType int eventType, ITaskFragmentOrganizer taskFragmentOrg) { mEventType = eventType; @@ -636,9 +645,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr return this; } + Builder setOpType(int opType) { + mOpType = opType; + return this; + } + PendingTaskFragmentEvent build() { return new PendingTaskFragmentEvent(mEventType, mTaskFragmentOrg, mTaskFragment, - mErrorCallbackToken, mException, mActivity); + mErrorCallbackToken, mException, mActivity, mOpType); } } } @@ -667,6 +681,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } private boolean shouldSendEventWhenTaskInvisible(@NonNull PendingTaskFragmentEvent event) { + if (event.mEventType == PendingTaskFragmentEvent.EVENT_ERROR) { + return true; + } + final TaskFragmentOrganizerState state = mTaskFragmentOrganizerState.get(event.mTaskFragmentOrg.asBinder()); final TaskFragmentInfo lastInfo = state.mLastSentTaskFragmentInfos.get(event.mTaskFragment); @@ -757,7 +775,8 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr state.onTaskFragmentParentInfoChanged(taskFragment); break; case PendingTaskFragmentEvent.EVENT_ERROR: - state.onTaskFragmentError(event.mErrorCallbackToken, event.mException); + state.onTaskFragmentError(event.mErrorCallbackToken, taskFragment, event.mOpType, + event.mException); break; case PendingTaskFragmentEvent.EVENT_ACTIVITY_REPARENT_TO_TASK: state.onActivityReparentToTask(event.mActivity); diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index ee6435493699..d9797532fb82 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -764,7 +764,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub bottomActivity)) { Slog.w(TAG, "Skip removing TaskFragment due in lock task mode."); sendTaskFragmentOperationFailure(organizer, errorCallbackToken, - new IllegalStateException( + taskFragment, type, new IllegalStateException( "Not allow to delete task fragment in lock task mode.")); break; } @@ -778,13 +778,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (tf == null) { final Throwable exception = new IllegalArgumentException( "Not allowed to operate with invalid fragment token"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type, + exception); break; } if (tf.isEmbeddedTaskFragmentInPip()) { final Throwable exception = new IllegalArgumentException( "Not allowed to start activity in PIP TaskFragment"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type, + exception); break; } final Intent activityIntent = hop.getActivityIntent(); @@ -794,7 +796,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub hop.getCallingActivity(), caller.mUid, caller.mPid, errorCallbackToken); if (!isStartResultSuccessful(result)) { - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf, type, convertStartFailureToThrowable(result, activityIntent)); } else { effects |= TRANSACT_EFFECTS_LIFECYCLE; @@ -815,25 +817,29 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (parent == null || activity == null) { final Throwable exception = new IllegalArgumentException( "Not allowed to operate with invalid fragment token or activity."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, + exception); break; } if (parent.isEmbeddedTaskFragmentInPip()) { final Throwable exception = new IllegalArgumentException( "Not allowed to reparent activity to PIP TaskFragment"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, + exception); break; } if (parent.isAllowedToEmbedActivity(activity) != EMBEDDING_ALLOWED) { final Throwable exception = new SecurityException( "The task fragment is not allowed to embed the given activity."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, + exception); break; } if (parent.getTask() != activity.getTask()) { final Throwable exception = new SecurityException("The reparented activity is" + " not in the same Task as the target TaskFragment."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, parent, type, + exception); break; } @@ -851,14 +857,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (tf1 == null || (adjacentFragmentToken != null && tf2 == null)) { final Throwable exception = new IllegalArgumentException( "Not allowed to set adjacent on invalid fragment tokens"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type, + exception); break; } if (tf1.isEmbeddedTaskFragmentInPip() || (tf2 != null && tf2.isEmbeddedTaskFragmentInPip())) { final Throwable exception = new IllegalArgumentException( "Not allowed to set adjacent on TaskFragment in PIP Task"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, tf1, type, + exception); break; } tf1.setAdjacentTaskFragment(tf2); @@ -1071,7 +1079,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub + taskFragment.getBounds() + " does not satisfy minimum dimensions:" + minDimensions + " " + reason); sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(), - errorCallbackToken, exception); + errorCallbackToken, taskFragment, -1 /* opType */, exception); } /** @@ -1624,13 +1632,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (ownerActivity == null || ownerActivity.getTask() == null) { final Throwable exception = new IllegalArgumentException("Not allowed to operate with invalid ownerToken"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, + HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } if (!ownerActivity.isResizeable()) { final IllegalArgumentException exception = new IllegalArgumentException("Not allowed" + " to operate with non-resizable owner Activity"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, + HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } // The ownerActivity has to belong to the same app as the target Task. @@ -1640,13 +1650,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final Throwable exception = new SecurityException("Not allowed to operate with the ownerToken while " + "the root activity of the target task belong to the different app"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, + HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } if (ownerTask.inPinnedWindowingMode()) { final Throwable exception = new IllegalArgumentException( "Not allowed to create TaskFragment in PIP Task"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, null /* taskFragment */, + HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, exception); return; } final TaskFragment taskFragment = new TaskFragment(mService, @@ -1674,7 +1686,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (newParentTF == null) { final Throwable exception = new IllegalArgumentException("Not allowed to operate with invalid container"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, + HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); return; } if (newParentTF.getTaskFragmentOrganizer() != null) { @@ -1685,20 +1698,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (isEmbeddingDisallowed) { final Throwable exception = new SecurityException( "The new parent is not allowed to embed the activities."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, + HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); return; } } if (newParentTF.isEmbeddedTaskFragmentInPip() || oldParent.isEmbeddedTaskFragmentInPip()) { final Throwable exception = new SecurityException( "Not allow to reparent in TaskFragment in PIP Task."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, + HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); return; } if (newParentTF.getTask() != oldParent.getTask()) { final Throwable exception = new SecurityException( "The new parent is not in the same Task as the old parent."); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, newParentTF, + HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception); return; } while (oldParent.hasChild()) { @@ -1713,7 +1729,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final Throwable exception = new IllegalArgumentException("Not allowed to operate with invalid " + "taskFragment"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception); return 0; } if (taskFragment.isEmbeddedTaskFragmentInPip() @@ -1722,7 +1739,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub && taskFragment.getTopNonFinishingActivity() != null) { final Throwable exception = new IllegalArgumentException( "Not allowed to delete TaskFragment in PIP Task"); - sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception); + sendTaskFragmentOperationFailure(organizer, errorCallbackToken, taskFragment, + HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception); return 0; } mLaunchTaskFragments.removeAt(index); @@ -1750,12 +1768,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer, - @Nullable IBinder errorCallbackToken, @NonNull Throwable exception) { + @Nullable IBinder errorCallbackToken, @Nullable TaskFragment taskFragment, int opType, + @NonNull Throwable exception) { if (organizer == null) { throw new IllegalArgumentException("Not allowed to operate with invalid organizer"); } mService.mTaskFragmentOrganizerController - .onTaskFragmentError(organizer, errorCallbackToken, exception); + .onTaskFragmentError(organizer, errorCallbackToken, taskFragment, opType, + exception); } private Throwable convertStartFailureToThrowable(int result, Intent intent) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java index e47bcc98b908..97f0918e8136 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java @@ -18,6 +18,12 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_CHILDREN; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -237,10 +243,10 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mController.registerOrganizer(mIOrganizer); mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(), - mErrorToken, exception); + mErrorToken, null /* taskFragment */, -1 /* opType */, exception); mController.dispatchPendingEvents(); - verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(exception)); + verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), eq(null), eq(-1), eq(exception)); } @Test @@ -604,7 +610,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(), any(), any(), anyInt(), anyInt(), any()); verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), any(IllegalArgumentException.class)); + eq(mErrorToken), eq(mTaskFragment), + eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT), + any(IllegalArgumentException.class)); } @Test @@ -619,7 +627,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mWindowOrganizerController.applyTransaction(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), any(IllegalArgumentException.class)); + eq(mErrorToken), eq(mTaskFragment), + eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT), + any(IllegalArgumentException.class)); assertNull(activity.getOrganizedTaskFragment()); } @@ -635,7 +645,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mWindowOrganizerController.applyTransaction(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), any(IllegalArgumentException.class)); + eq(mErrorToken), eq(mTaskFragment), + eq(HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS), + any(IllegalArgumentException.class)); verify(mTaskFragment, never()).setAdjacentTaskFragment(any()); } @@ -654,7 +666,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mWindowOrganizerController.applyTransaction(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), any(IllegalArgumentException.class)); + eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT), + any(IllegalArgumentException.class)); assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken)); } @@ -669,7 +682,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { mWindowOrganizerController.applyTransaction(mTransaction); verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer), - eq(mErrorToken), any(IllegalArgumentException.class)); + eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT), + any(IllegalArgumentException.class)); assertNotNull(mWindowOrganizerController.getTaskFragment(mFragmentToken)); // Allow organizer to delete empty TaskFragment for cleanup. @@ -931,7 +945,9 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // The pending event will be dispatched on the handler (from requestTraversal). waitHandlerIdle(mWm.mAnimationHandler); - verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class)); + verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(), + eq(HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT), + any(SecurityException.class)); } @Test @@ -968,7 +984,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase { // The pending event will be dispatched on the handler (from requestTraversal). waitHandlerIdle(mWm.mAnimationHandler); - verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(SecurityException.class)); + verify(mOrganizer).onTaskFragmentError(eq(mErrorToken), any(), + eq(HIERARCHY_OP_TYPE_REPARENT_CHILDREN), any(SecurityException.class)); } @Test |