Merge "Prevent the launching activity be reparented into embedded task" into sc-v2-dev

This commit is contained in:
Louis Chang
2021-08-04 05:33:45 +00:00
committed by Android (Google) Code Review
4 changed files with 119 additions and 15 deletions

View File

@@ -2784,7 +2784,8 @@ class ActivityStarter {
}
} else {
// Use the child TaskFragment (if any) as the new parent if the activity can be embedded
final ActivityRecord top = task.topRunningActivity();
final ActivityRecord top = task.topRunningActivity(false /* focusableOnly */,
false /* includingEmbeddedTask */);
newParent = top != null ? top.getTaskFragment() : task;
}

View File

@@ -365,8 +365,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return false;
}
if (matchingCandidate(task)) {
return true;
}
// Looking for the embedded tasks (if any)
return !task.isLeafTaskFragment() && task.forAllLeafTaskFragments(
this::matchingCandidate);
}
boolean matchingCandidate(TaskFragment taskFragment) {
final Task task = taskFragment.asTask();
if (task == null) {
return false;
}
// Overlays should not be considered as the task's logical top activity.
final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
// Activities of the tasks that embedded from this one should not be used.
final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */,
false /* includingEmbeddedTask */);
if (r == null || r.finishing || r.mUserId != userId
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);

View File

@@ -1394,14 +1394,6 @@ class Task extends TaskFragment {
return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
}
ActivityRecord getTopNonFinishingActivity() {
return getTopNonFinishingActivity(true /* includeOverlays */);
}
ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
return getTopActivity(false /*includeFinishing*/, includeOverlays);
}
ActivityRecord topRunningActivityLocked() {
if (getParent() == null) {
return null;
@@ -2976,11 +2968,53 @@ class Task extends TaskFragment {
/** Returns the top-most activity that occludes the given one, or {@code null} if none. */
@Nullable
ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
final ActivityRecord top = getActivity(ActivityRecord::occludesParent,
true /* traverseTopToBottom */, activity);
final ActivityRecord top = getActivity(r -> {
if (!r.occludesParent()) {
return false;
}
if (r == activity) {
// Reached the given activity, return the activity to stop searching.
return true;
}
TaskFragment parent = r.getTaskFragment();
if (parent == activity.getTaskFragment()) {
// Found it. This activity on top of the given activity on the same TaskFragment.
return true;
}
if (isSelfOrNonEmbeddedTask(parent.asTask())) {
// Found it. This activity is the direct child of a leaf Task without being
// embedded.
return true;
}
// The candidate activity is being embedded. Checking if the bounds of the containing
// TaskFragment equals to the outer TaskFragment.
TaskFragment grandParent = parent.getParent().asTaskFragment();
while (grandParent != null) {
if (!parent.getBounds().equals(grandParent.getBounds())) {
// Not occluding the grandparent.
break;
}
if (isSelfOrNonEmbeddedTask(grandParent.asTask())) {
// Found it. The activity occludes its parent TaskFragment and the parent
// TaskFragment also occludes its parent all the way up.
return true;
}
parent = grandParent;
grandParent = parent.getParent().asTaskFragment();
}
return false;
});
return top != activity ? top : null;
}
private boolean isSelfOrNonEmbeddedTask(Task task) {
if (task == this) {
return true;
}
return task != null && !task.isEmbedded();
}
@Override
public SurfaceControl.Builder makeAnimationLeash() {
return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);

View File

@@ -614,17 +614,68 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false;
}
ActivityRecord getTopNonFinishingActivity() {
return getTopNonFinishingActivity(true /* includeOverlays */);
}
ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
return getTopNonFinishingActivity(includeOverlays, true /* includingEmbeddedTask */);
}
/**
* Returns the top-most non-finishing activity, even if the activity is NOT ok to show to
* the current user.
* @param includeOverlays whether the task overlay activity should be included.
* @param includingEmbeddedTask whether the activity in a task that being embedded from this
* one should be included.
* @see #topRunningActivity(boolean, boolean)
* @see ActivityRecord#okToShowLocked()
*/
ActivityRecord getTopNonFinishingActivity(boolean includeOverlays,
boolean includingEmbeddedTask) {
// Split into 4 to avoid object creation due to variable capture.
if (includeOverlays) {
if (includingEmbeddedTask) {
return getActivity((r) -> !r.finishing);
}
return getActivity((r) -> !r.finishing && r.getTask() == this.getTask());
}
if (includingEmbeddedTask) {
return getActivity((r) -> !r.finishing && !r.isTaskOverlay());
}
return getActivity(
(r) -> !r.finishing && !r.isTaskOverlay() && r.getTask() == this.getTask());
}
ActivityRecord topRunningActivity() {
return topRunningActivity(false /* focusableOnly */);
}
ActivityRecord topRunningActivity(boolean focusableOnly) {
// Split into 2 to avoid object creation due to variable capture.
return topRunningActivity(focusableOnly, true /* includingEmbeddedTask */);
}
/**
* Returns the top-most running activity, which the activity is non-finishing and ok to show
* to the current user.
*
* @see ActivityRecord#canBeTopRunning()
*/
ActivityRecord topRunningActivity(boolean focusableOnly, boolean includingEmbeddedTask) {
// Split into 4 to avoid object creation due to variable capture.
if (focusableOnly) {
return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
} else {
if (includingEmbeddedTask) {
return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
}
return getActivity(
(r) -> r.canBeTopRunning() && r.isFocusable() && r.getTask() == this.getTask());
}
if (includingEmbeddedTask) {
return getActivity(ActivityRecord::canBeTopRunning);
}
return getActivity((r) -> r.canBeTopRunning() && r.getTask() == this.getTask());
}
boolean isTopActivityFocusable() {