Merge "Allows running TaskFragment related hierarchy op in lock task mode" into sc-v2-dev
This commit is contained in:
@@ -581,115 +581,18 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
task.getDisplayArea().setLaunchAdjacentFlagRootTask(clearRoot ? null : task);
|
task.getDisplayArea().setLaunchAdjacentFlagRootTask(clearRoot ? null : task);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS:
|
case HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS: {
|
||||||
effects |= setAdjacentRootsHierarchyOp(hop);
|
effects |= setAdjacentRootsHierarchyOp(hop);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// The following operations may change task order so they are skipped while in lock task
|
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
|
||||||
// mode. The above operations are still allowed because they don't move tasks. And it may
|
|
||||||
// be necessary such as clearing launch root after entering lock task mode.
|
|
||||||
if (isInLockTaskMode) {
|
|
||||||
Slog.w(TAG, "Skip applying hierarchy operation " + hop + " while in lock task mode");
|
|
||||||
return effects;
|
|
||||||
}
|
|
||||||
|
|
||||||
final WindowContainer wc;
|
|
||||||
final IBinder fragmentToken;
|
|
||||||
switch (type) {
|
|
||||||
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT:
|
|
||||||
effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
|
|
||||||
break;
|
|
||||||
case HIERARCHY_OP_TYPE_REORDER:
|
|
||||||
case HIERARCHY_OP_TYPE_REPARENT:
|
|
||||||
wc = WindowContainer.fromBinder(hop.getContainer());
|
|
||||||
if (wc == null || !wc.isAttached()) {
|
|
||||||
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (syncId >= 0) {
|
|
||||||
addToSyncSet(syncId, wc);
|
|
||||||
}
|
|
||||||
if (transition != null) {
|
|
||||||
transition.collect(wc);
|
|
||||||
if (hop.isReparent()) {
|
|
||||||
if (wc.getParent() != null) {
|
|
||||||
// Collect the current parent. It's visibility may change as
|
|
||||||
// a result of this reparenting.
|
|
||||||
transition.collect(wc.getParent());
|
|
||||||
}
|
|
||||||
if (hop.getNewParent() != null) {
|
|
||||||
final WindowContainer parentWc =
|
|
||||||
WindowContainer.fromBinder(hop.getNewParent());
|
|
||||||
if (parentWc == null) {
|
|
||||||
Slog.e(TAG, "Can't resolve parent window from token");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
transition.collect(parentWc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
|
|
||||||
break;
|
|
||||||
case HIERARCHY_OP_TYPE_LAUNCH_TASK:
|
|
||||||
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
|
||||||
"launchTask HierarchyOp");
|
|
||||||
final Bundle launchOpts = hop.getLaunchOptions();
|
|
||||||
final int taskId = launchOpts.getInt(
|
|
||||||
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
|
|
||||||
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
|
|
||||||
final SafeActivityOptions safeOptions =
|
|
||||||
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
|
|
||||||
final Integer[] starterResult = { null };
|
|
||||||
// startActivityFromRecents should not be called in lock.
|
|
||||||
mService.mH.post(() -> {
|
|
||||||
try {
|
|
||||||
starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
|
|
||||||
caller.mPid, caller.mUid, taskId, safeOptions);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
starterResult[0] = ActivityManager.START_CANCELED;
|
|
||||||
Slog.w(TAG, t);
|
|
||||||
}
|
|
||||||
synchronized (mGlobalLock) {
|
|
||||||
mGlobalLock.notifyAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
while (starterResult[0] == null) {
|
|
||||||
try {
|
|
||||||
mGlobalLock.wait();
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HIERARCHY_OP_TYPE_PENDING_INTENT:
|
|
||||||
String resolvedType = hop.getActivityIntent() != null
|
|
||||||
? hop.getActivityIntent().resolveTypeIfNeeded(
|
|
||||||
mService.mContext.getContentResolver())
|
|
||||||
: null;
|
|
||||||
|
|
||||||
Bundle options = null;
|
|
||||||
if (hop.getPendingIntent().isActivity()) {
|
|
||||||
// Set the context display id as preferred for this activity launches, so that
|
|
||||||
// it can land on caller's display. Or just brought the task to front at the
|
|
||||||
// display where it was on since it has higher preference.
|
|
||||||
ActivityOptions activityOptions = hop.getLaunchOptions() != null
|
|
||||||
? new ActivityOptions(hop.getLaunchOptions())
|
|
||||||
: ActivityOptions.makeBasic();
|
|
||||||
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
|
|
||||||
options = activityOptions.toBundle();
|
|
||||||
}
|
|
||||||
|
|
||||||
mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
|
|
||||||
hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
|
|
||||||
hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
|
|
||||||
null /* requiredPermission */, options);
|
|
||||||
break;
|
|
||||||
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
|
|
||||||
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
||||||
hop.getTaskFragmentCreationOptions();
|
hop.getTaskFragmentCreationOptions();
|
||||||
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
|
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
|
||||||
break;
|
break;
|
||||||
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT:
|
}
|
||||||
wc = WindowContainer.fromBinder(hop.getContainer());
|
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
|
||||||
|
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
|
||||||
if (wc == null || !wc.isAttached()) {
|
if (wc == null || !wc.isAttached()) {
|
||||||
Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
|
Slog.e(TAG, "Attempt to operate on unknown or detached container: " + wc);
|
||||||
break;
|
break;
|
||||||
@@ -699,10 +602,24 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Can only delete organized TaskFragment, but not Task.");
|
"Can only delete organized TaskFragment, but not Task.");
|
||||||
}
|
}
|
||||||
|
if (isInLockTaskMode) {
|
||||||
|
final ActivityRecord bottomActivity = taskFragment.getActivity(
|
||||||
|
a -> !a.finishing, false /* traverseTopToBottom */);
|
||||||
|
if (bottomActivity != null
|
||||||
|
&& mService.getLockTaskController().activityBlockedFromFinish(
|
||||||
|
bottomActivity)) {
|
||||||
|
Slog.w(TAG, "Skip removing TaskFragment due in lock task mode.");
|
||||||
|
sendTaskFragmentOperationFailure(organizer, errorCallbackToken,
|
||||||
|
new IllegalStateException(
|
||||||
|
"Not allow to delete task fragment in lock task mode."));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
effects |= deleteTaskFragment(taskFragment, errorCallbackToken);
|
effects |= deleteTaskFragment(taskFragment, errorCallbackToken);
|
||||||
break;
|
break;
|
||||||
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT:
|
}
|
||||||
fragmentToken = hop.getContainer();
|
case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
|
||||||
|
final IBinder fragmentToken = hop.getContainer();
|
||||||
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
|
if (!mLaunchTaskFragments.containsKey(fragmentToken)) {
|
||||||
final Throwable exception = new IllegalArgumentException(
|
final Throwable exception = new IllegalArgumentException(
|
||||||
"Not allowed to operate with invalid fragment token");
|
"Not allowed to operate with invalid fragment token");
|
||||||
@@ -721,8 +638,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
convertStartFailureToThrowable(result, activityIntent));
|
convertStartFailureToThrowable(result, activityIntent));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT:
|
}
|
||||||
fragmentToken = hop.getNewParent();
|
case HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT: {
|
||||||
|
final IBinder fragmentToken = hop.getNewParent();
|
||||||
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
|
final ActivityRecord activity = ActivityRecord.forTokenLocked(hop.getContainer());
|
||||||
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
|
if (!mLaunchTaskFragments.containsKey(fragmentToken) || activity == null) {
|
||||||
final Throwable exception = new IllegalArgumentException(
|
final Throwable exception = new IllegalArgumentException(
|
||||||
@@ -733,21 +651,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
|
activity.reparent(mLaunchTaskFragments.get(fragmentToken), POSITION_TOP);
|
||||||
effects |= TRANSACT_EFFECTS_LIFECYCLE;
|
effects |= TRANSACT_EFFECTS_LIFECYCLE;
|
||||||
break;
|
break;
|
||||||
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN:
|
}
|
||||||
final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
|
case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: {
|
||||||
final WindowContainer newParent = hop.getNewParent() != null
|
final IBinder fragmentToken = hop.getContainer();
|
||||||
? WindowContainer.fromBinder(hop.getNewParent())
|
|
||||||
: null;
|
|
||||||
if (oldParent == null || !oldParent.isAttached()) {
|
|
||||||
Slog.e(TAG, "Attempt to operate on unknown or detached container: "
|
|
||||||
+ oldParent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reparentTaskFragment(oldParent, newParent, errorCallbackToken);
|
|
||||||
effects |= TRANSACT_EFFECTS_LIFECYCLE;
|
|
||||||
break;
|
|
||||||
case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS:
|
|
||||||
fragmentToken = hop.getContainer();
|
|
||||||
final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
|
final IBinder adjacentFragmentToken = hop.getAdjacentRoot();
|
||||||
final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
|
final TaskFragment tf1 = mLaunchTaskFragments.get(fragmentToken);
|
||||||
final TaskFragment tf2 = adjacentFragmentToken != null
|
final TaskFragment tf2 = adjacentFragmentToken != null
|
||||||
@@ -777,6 +683,126 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
adjacentParams.shouldDelaySecondaryLastActivityRemoval());
|
adjacentParams.shouldDelaySecondaryLastActivityRemoval());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// The other operations may change task order so they are skipped while in lock
|
||||||
|
// task mode. The above operations are still allowed because they don't move
|
||||||
|
// tasks. And it may be necessary such as clearing launch root after entering
|
||||||
|
// lock task mode.
|
||||||
|
if (isInLockTaskMode) {
|
||||||
|
Slog.w(TAG, "Skip applying hierarchy operation " + hop
|
||||||
|
+ " while in lock task mode");
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
|
||||||
|
effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HIERARCHY_OP_TYPE_REORDER:
|
||||||
|
case HIERARCHY_OP_TYPE_REPARENT: {
|
||||||
|
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
|
||||||
|
if (wc == null || !wc.isAttached()) {
|
||||||
|
Slog.e(TAG, "Attempt to operate on detached container: " + wc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (syncId >= 0) {
|
||||||
|
addToSyncSet(syncId, wc);
|
||||||
|
}
|
||||||
|
if (transition != null) {
|
||||||
|
transition.collect(wc);
|
||||||
|
if (hop.isReparent()) {
|
||||||
|
if (wc.getParent() != null) {
|
||||||
|
// Collect the current parent. It's visibility may change as
|
||||||
|
// a result of this reparenting.
|
||||||
|
transition.collect(wc.getParent());
|
||||||
|
}
|
||||||
|
if (hop.getNewParent() != null) {
|
||||||
|
final WindowContainer parentWc =
|
||||||
|
WindowContainer.fromBinder(hop.getNewParent());
|
||||||
|
if (parentWc == null) {
|
||||||
|
Slog.e(TAG, "Can't resolve parent window from token");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
transition.collect(parentWc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HIERARCHY_OP_TYPE_LAUNCH_TASK: {
|
||||||
|
mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
|
||||||
|
"launchTask HierarchyOp");
|
||||||
|
final Bundle launchOpts = hop.getLaunchOptions();
|
||||||
|
final int taskId = launchOpts.getInt(
|
||||||
|
WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
|
||||||
|
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
|
||||||
|
final SafeActivityOptions safeOptions =
|
||||||
|
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
|
||||||
|
final Integer[] starterResult = {null};
|
||||||
|
// startActivityFromRecents should not be called in lock.
|
||||||
|
mService.mH.post(() -> {
|
||||||
|
try {
|
||||||
|
starterResult[0] = mService.mTaskSupervisor.startActivityFromRecents(
|
||||||
|
caller.mPid, caller.mUid, taskId, safeOptions);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
starterResult[0] = ActivityManager.START_CANCELED;
|
||||||
|
Slog.w(TAG, t);
|
||||||
|
}
|
||||||
|
synchronized (mGlobalLock) {
|
||||||
|
mGlobalLock.notifyAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
while (starterResult[0] == null) {
|
||||||
|
try {
|
||||||
|
mGlobalLock.wait();
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
|
||||||
|
String resolvedType = hop.getActivityIntent() != null
|
||||||
|
? hop.getActivityIntent().resolveTypeIfNeeded(
|
||||||
|
mService.mContext.getContentResolver())
|
||||||
|
: null;
|
||||||
|
|
||||||
|
Bundle options = null;
|
||||||
|
if (hop.getPendingIntent().isActivity()) {
|
||||||
|
// Set the context display id as preferred for this activity launches, so that
|
||||||
|
// it can land on caller's display. Or just brought the task to front at the
|
||||||
|
// display where it was on since it has higher preference.
|
||||||
|
ActivityOptions activityOptions = hop.getLaunchOptions() != null
|
||||||
|
? new ActivityOptions(hop.getLaunchOptions())
|
||||||
|
: ActivityOptions.makeBasic();
|
||||||
|
activityOptions.setCallerDisplayId(DEFAULT_DISPLAY);
|
||||||
|
options = activityOptions.toBundle();
|
||||||
|
}
|
||||||
|
|
||||||
|
mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
|
||||||
|
hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
|
||||||
|
hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
|
||||||
|
null /* requiredPermission */, options);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: {
|
||||||
|
final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer());
|
||||||
|
final WindowContainer newParent = hop.getNewParent() != null
|
||||||
|
? WindowContainer.fromBinder(hop.getNewParent())
|
||||||
|
: null;
|
||||||
|
if (oldParent == null || !oldParent.isAttached()) {
|
||||||
|
Slog.e(TAG, "Attempt to operate on unknown or detached container: "
|
||||||
|
+ oldParent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reparentTaskFragment(oldParent, newParent, errorCallbackToken);
|
||||||
|
effects |= TRANSACT_EFFECTS_LIFECYCLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return effects;
|
return effects;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user