Merge "Report the failure back to the organizer" into sc-v2-dev
This commit is contained in:
@@ -490,9 +490,16 @@ public class ActivityStartController {
|
||||
return START_SUCCESS;
|
||||
}
|
||||
|
||||
void startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
|
||||
/**
|
||||
* Starts an activity in the TaskFragment.
|
||||
* @param taskFragment TaskFragment {@link TaskFragment} to start the activity in.
|
||||
* @param activityIntent intent to start the activity.
|
||||
* @param activityOptions ActivityOptions to start the activity with.
|
||||
* @return the start result.
|
||||
*/
|
||||
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
|
||||
@NonNull Intent activityIntent, @Nullable Bundle activityOptions) {
|
||||
obtainStarter(activityIntent, "startActivityInTaskFragment")
|
||||
return obtainStarter(activityIntent, "startActivityInTaskFragment")
|
||||
.setActivityOptions(activityOptions)
|
||||
.setInTaskFragment(taskFragment)
|
||||
.setCallingUid(Binder.getCallingUid())
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
|
||||
import static com.android.server.wm.WindowOrganizerController.configurationsAreEqualForOrganizer;
|
||||
|
||||
@@ -23,6 +25,7 @@ import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
@@ -190,6 +193,16 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
|
||||
Throwable exception) {
|
||||
final Bundle exceptionBundle = putExceptionInBundle(exception);
|
||||
try {
|
||||
organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -289,6 +302,14 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
state.removeTaskFragment(taskFragment);
|
||||
}
|
||||
|
||||
void onTaskFragmentError(ITaskFragmentOrganizer organizer, IBinder errorCallbackToken,
|
||||
Throwable exception) {
|
||||
validateAndGetState(organizer);
|
||||
PendingTaskFragmentEvent pendingEvent = new PendingTaskFragmentEvent(organizer,
|
||||
errorCallbackToken, exception, PendingTaskFragmentEvent.EVENT_ERROR);
|
||||
mPendingTaskFragmentEvents.add(pendingEvent);
|
||||
}
|
||||
|
||||
private void removeOrganizer(ITaskFragmentOrganizer organizer) {
|
||||
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
|
||||
// remove all of the children of the organized TaskFragment
|
||||
@@ -321,25 +342,45 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
static final int EVENT_VANISHED = 1;
|
||||
static final int EVENT_INFO_CHANGED = 2;
|
||||
static final int EVENT_PARENT_INFO_CHANGED = 3;
|
||||
static final int EVENT_ERROR = 4;
|
||||
|
||||
@IntDef(prefix = "EVENT_", value = {
|
||||
EVENT_APPEARED,
|
||||
EVENT_VANISHED,
|
||||
EVENT_INFO_CHANGED,
|
||||
EVENT_PARENT_INFO_CHANGED
|
||||
EVENT_PARENT_INFO_CHANGED,
|
||||
EVENT_ERROR
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface EventType {}
|
||||
|
||||
@EventType
|
||||
final int mEventType;
|
||||
final TaskFragment mTaskFragment;
|
||||
final ITaskFragmentOrganizer mTaskFragmentOrg;
|
||||
private final int mEventType;
|
||||
private final ITaskFragmentOrganizer mTaskFragmentOrg;
|
||||
private final TaskFragment mTaskFragment;
|
||||
private final IBinder mErrorCallback;
|
||||
private final Throwable mException;
|
||||
|
||||
PendingTaskFragmentEvent(TaskFragment taskFragment, ITaskFragmentOrganizer taskFragmentOrg,
|
||||
private PendingTaskFragmentEvent(TaskFragment taskFragment,
|
||||
ITaskFragmentOrganizer taskFragmentOrg, @EventType int eventType) {
|
||||
this(taskFragment, taskFragmentOrg, null /* errorCallback */,
|
||||
null /* exception */, eventType);
|
||||
|
||||
}
|
||||
|
||||
private PendingTaskFragmentEvent(ITaskFragmentOrganizer taskFragmentOrg,
|
||||
IBinder errorCallback, Throwable exception, @EventType int eventType) {
|
||||
this(null /* taskFragment */, taskFragmentOrg, errorCallback, exception,
|
||||
eventType);
|
||||
}
|
||||
|
||||
private PendingTaskFragmentEvent(TaskFragment taskFragment,
|
||||
ITaskFragmentOrganizer taskFragmentOrg, IBinder errorCallback, Throwable exception,
|
||||
@EventType int eventType) {
|
||||
mTaskFragment = taskFragment;
|
||||
mTaskFragmentOrg = taskFragmentOrg;
|
||||
mErrorCallback = errorCallback;
|
||||
mException = exception;
|
||||
mEventType = eventType;
|
||||
}
|
||||
|
||||
@@ -407,6 +448,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
|
||||
break;
|
||||
case PendingTaskFragmentEvent.EVENT_PARENT_INFO_CHANGED:
|
||||
state.onTaskFragmentParentInfoChanged(taskFragmentOrg, taskFragment);
|
||||
break;
|
||||
case PendingTaskFragmentEvent.EVENT_ERROR:
|
||||
state.onTaskFragmentError(taskFragmentOrg, event.mErrorCallback,
|
||||
event.mException);
|
||||
}
|
||||
}
|
||||
mPendingTaskFragmentEvents.clear();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
|
||||
import static android.app.ActivityManager.isStartResultSuccessful;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
|
||||
@@ -44,6 +45,7 @@ import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.WindowConfiguration;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
@@ -369,7 +371,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
final boolean isInLockTaskMode = mService.isInLockTaskMode();
|
||||
for (int i = 0; i < hopSize; ++i) {
|
||||
effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
|
||||
isInLockTaskMode, caller);
|
||||
isInLockTaskMode, caller, t.getErrorCallbackToken(),
|
||||
t.getTaskFragmentOrganizer());
|
||||
}
|
||||
}
|
||||
// Queue-up bounds-change transactions for tasks which are now organized. Do
|
||||
@@ -525,7 +528,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
|
||||
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
|
||||
int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
|
||||
@Nullable CallerInfo caller) {
|
||||
@Nullable CallerInfo caller, @Nullable IBinder errorCallbackToken,
|
||||
@Nullable ITaskFragmentOrganizer organizer) {
|
||||
final int type = hop.getType();
|
||||
switch (type) {
|
||||
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
|
||||
@@ -652,7 +656,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
|
||||
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
||||
hop.getTaskFragmentCreationOptions();
|
||||
createTaskFragment(taskFragmentCreationOptions);
|
||||
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
|
||||
break;
|
||||
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
|
||||
wc = WindowContainer.fromBinder(hop.getContainer());
|
||||
@@ -665,28 +669,36 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
throw new IllegalArgumentException(
|
||||
"Can only delete organized TaskFragment, but not Task.");
|
||||
}
|
||||
deleteTaskFragment(taskFragment);
|
||||
deleteTaskFragment(taskFragment, errorCallbackToken);
|
||||
break;
|
||||
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
|
||||
fragmentToken = hop.getContainer();
|
||||
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
|
||||
throw new IllegalArgumentException(
|
||||
final Throwable exception = new IllegalArgumentException(
|
||||
"Not allowed to operate with invalid fragment token");
|
||||
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
|
||||
break;
|
||||
}
|
||||
final Intent activityIntent = hop.getActivityIntent();
|
||||
final Bundle activityOptions = hop.getLaunchOptions();
|
||||
mService.getActivityStartController()
|
||||
.startActivityInTaskFragment(mLaunchTaskFragments.get(fragmentToken),
|
||||
activityIntent, activityOptions);
|
||||
// TODO(b/189385246) : report the failure back to the organizer if the activity
|
||||
// start failed
|
||||
final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
|
||||
final int result = mService.getActivityStartController()
|
||||
.startActivityInTaskFragment(tf, activityIntent, activityOptions);
|
||||
if (!isStartResultSuccessful(result)) {
|
||||
final Throwable exception =
|
||||
new ActivityNotFoundException("start activity in taskFragment failed");
|
||||
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
|
||||
errorCallbackToken, exception);
|
||||
}
|
||||
break;
|
||||
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
|
||||
fragmentToken = hop.getNewParent();
|
||||
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
|
||||
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
|
||||
throw new IllegalArgumentException(
|
||||
final Throwable exception = new IllegalArgumentException(
|
||||
"Not allowed to operate with invalid fragment token or activity.");
|
||||
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
|
||||
break;
|
||||
}
|
||||
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
|
||||
break;
|
||||
@@ -700,7 +712,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
+ oldParent);
|
||||
break;
|
||||
}
|
||||
reparentTaskFragment(oldParent, newParent);
|
||||
reparentTaskFragment(oldParent, newParent, errorCallbackToken);
|
||||
break;
|
||||
}
|
||||
return effects;
|
||||
@@ -1076,17 +1088,25 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams) {
|
||||
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
|
||||
@Nullable IBinder errorCallbackToken) {
|
||||
final ActivityRecord ownerActivity =
|
||||
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
|
||||
if (ownerActivity == null || ownerActivity.getTask() == null) {
|
||||
// TODO(b/189385246) : report the failure back to the organizer
|
||||
final Throwable exception =
|
||||
new IllegalArgumentException("Not allowed to operate with invalid ownerToken");
|
||||
sendTaskFragmentOperationFailure(creationParams.getOrganizer(), errorCallbackToken,
|
||||
exception);
|
||||
return;
|
||||
}
|
||||
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
|
||||
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
|
||||
if (rootActivity.getUid() != ownerActivity.getUid()) {
|
||||
// TODO(b/189385246) : report the failure back to the organizer
|
||||
final Throwable exception =
|
||||
new IllegalArgumentException("Not allowed to operate with the ownerToken while "
|
||||
+ "the root activity of the target task belong to the different app");
|
||||
sendTaskFragmentOperationFailure(creationParams.getOrganizer(), errorCallbackToken,
|
||||
exception);
|
||||
return;
|
||||
}
|
||||
final TaskFragment taskFragment = new TaskFragment(mService,
|
||||
@@ -1102,13 +1122,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
}
|
||||
|
||||
void reparentTaskFragment(@NonNull WindowContainer oldParent,
|
||||
@Nullable WindowContainer newParent) {
|
||||
@Nullable WindowContainer newParent, @Nullable IBinder errorCallbackToken) {
|
||||
WindowContainer parent = newParent;
|
||||
if (parent == null && oldParent.asTaskFragment() != null) {
|
||||
parent = oldParent.asTaskFragment().getTask();
|
||||
}
|
||||
if (parent == null) {
|
||||
// TODO(b/189385246) : report the failure back to the organizer
|
||||
final Throwable exception =
|
||||
new IllegalArgumentException("Not allowed to operate with invalid container");
|
||||
sendTaskFragmentOperationFailure(oldParent.asTaskFragment().getTaskFragmentOrganizer(),
|
||||
errorCallbackToken, exception);
|
||||
return;
|
||||
}
|
||||
while (oldParent.hasChild()) {
|
||||
@@ -1116,11 +1139,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void deleteTaskFragment(@NonNull TaskFragment taskFragment) {
|
||||
void deleteTaskFragment(@NonNull TaskFragment taskFragment,
|
||||
@Nullable IBinder errorCallbackToken) {
|
||||
final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Not allowed to operate with invalid taskFragment");
|
||||
final Throwable exception =
|
||||
new IllegalArgumentException("Not allowed to operate with invalid "
|
||||
+ "taskFragment");
|
||||
sendTaskFragmentOperationFailure(taskFragment.getTaskFragmentOrganizer(),
|
||||
errorCallbackToken, exception);
|
||||
return;
|
||||
}
|
||||
mLaunchTaskFragments.removeAt(index);
|
||||
taskFragment.removeImmediately();
|
||||
@@ -1135,4 +1163,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
||||
mUid = Binder.getCallingUid();
|
||||
}
|
||||
}
|
||||
|
||||
void sendTaskFragmentOperationFailure(@NonNull ITaskFragmentOrganizer organizer,
|
||||
@Nullable IBinder errorCallbackToken, @NonNull Throwable exception) {
|
||||
if (organizer == null) {
|
||||
throw new IllegalArgumentException("Not allowed to operate with invalid organizer");
|
||||
}
|
||||
mService.mTaskFragmentOrganizerController
|
||||
.onTaskFragmentError(organizer, errorCallbackToken, exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.window.TaskFragmentOrganizer.putExceptionInBundle;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.server.wm.testing.Assert.assertThrows;
|
||||
@@ -35,7 +33,6 @@ import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
@@ -198,9 +195,11 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
||||
public void testOnTaskFragmentError() throws RemoteException {
|
||||
final IBinder errorCallbackToken = new Binder();
|
||||
final Throwable exception = new IllegalArgumentException("Test exception");
|
||||
final Bundle exceptionBundle = putExceptionInBundle(exception);
|
||||
|
||||
mIOrganizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
|
||||
mController.registerOrganizer(mIOrganizer);
|
||||
mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
|
||||
errorCallbackToken, exception);
|
||||
mController.dispatchPendingEvents();
|
||||
|
||||
verify(mOrganizer).onTaskFragmentError(eq(errorCallbackToken), eq(exception));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user