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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15390753

Change-Id: I878299bdb80bf2880fd5505b8ce9427a44a8c0f0
This commit is contained in:
Louis Chang
2021-08-04 05:44:16 +00:00
committed by Automerger Merge Worker
4 changed files with 119 additions and 15 deletions

View File

@@ -2784,7 +2784,8 @@ class ActivityStarter {
} }
} else { } else {
// Use the child TaskFragment (if any) as the new parent if the activity can be embedded // 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; newParent = top != null ? top.getTaskFragment() : task;
} }

View File

@@ -365,8 +365,26 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return false; 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. // 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 if (r == null || r.finishing || r.mUserId != userId
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r); 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); return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
} }
ActivityRecord getTopNonFinishingActivity() {
return getTopNonFinishingActivity(true /* includeOverlays */);
}
ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
return getTopActivity(false /*includeFinishing*/, includeOverlays);
}
ActivityRecord topRunningActivityLocked() { ActivityRecord topRunningActivityLocked() {
if (getParent() == null) { if (getParent() == null) {
return 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. */ /** Returns the top-most activity that occludes the given one, or {@code null} if none. */
@Nullable @Nullable
ActivityRecord getOccludingActivityAbove(ActivityRecord activity) { ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
final ActivityRecord top = getActivity(ActivityRecord::occludesParent, final ActivityRecord top = getActivity(r -> {
true /* traverseTopToBottom */, activity); 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; return top != activity ? top : null;
} }
private boolean isSelfOrNonEmbeddedTask(Task task) {
if (task == this) {
return true;
}
return task != null && !task.isEmbedded();
}
@Override @Override
public SurfaceControl.Builder makeAnimationLeash() { public SurfaceControl.Builder makeAnimationLeash() {
return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId); return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);

View File

@@ -614,17 +614,68 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false; 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() { ActivityRecord topRunningActivity() {
return topRunningActivity(false /* focusableOnly */); return topRunningActivity(false /* focusableOnly */);
} }
ActivityRecord topRunningActivity(boolean 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) { if (focusableOnly) {
if (includingEmbeddedTask) {
return getActivity((r) -> r.canBeTopRunning() && r.isFocusable()); return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
} else { }
return getActivity(
(r) -> r.canBeTopRunning() && r.isFocusable() && r.getTask() == this.getTask());
}
if (includingEmbeddedTask) {
return getActivity(ActivityRecord::canBeTopRunning); return getActivity(ActivityRecord::canBeTopRunning);
} }
return getActivity((r) -> r.canBeTopRunning() && r.getTask() == this.getTask());
} }
boolean isTopActivityFocusable() { boolean isTopActivityFocusable() {