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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user