Merge "Simplify check-behind-fullscreen-activity"

This commit is contained in:
Riddle Hsu
2020-07-09 10:15:12 +00:00
committed by Android (Google) Code Review
5 changed files with 50 additions and 126 deletions

View File

@@ -4605,8 +4605,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
final boolean behindFullscreenActivity = stack.checkBehindFullscreenActivity(
this, null /* handleBehindFullscreenActivity */);
final boolean behindFullscreenActivity = !stack.shouldBeVisible(null /* starting */)
|| stack.getOccludingActivityAbove(this) != null;
return shouldBeVisible(behindFullscreenActivity, false /* ignoringKeyguard */);
}

View File

@@ -328,81 +328,6 @@ class ActivityStack extends Task {
}
}
private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper =
new CheckBehindFullscreenActivityHelper();
private class CheckBehindFullscreenActivityHelper {
private boolean mAboveTop;
private boolean mBehindFullscreenActivity;
private ActivityRecord mToCheck;
private Consumer<ActivityRecord> mHandleBehindFullscreenActivity;
private boolean mHandlingOccluded;
private void reset(ActivityRecord toCheck,
Consumer<ActivityRecord> handleBehindFullscreenActivity) {
mToCheck = toCheck;
mHandleBehindFullscreenActivity = handleBehindFullscreenActivity;
mAboveTop = true;
mBehindFullscreenActivity = false;
if (!shouldBeVisible(null)) {
// The stack is not visible, so no activity in it should be displaying a starting
// window. Mark all activities below top and behind fullscreen.
mAboveTop = false;
mBehindFullscreenActivity = true;
}
mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null;
}
boolean process(ActivityRecord toCheck,
Consumer<ActivityRecord> handleBehindFullscreenActivity) {
reset(toCheck, handleBehindFullscreenActivity);
if (!mHandlingOccluded && mBehindFullscreenActivity) {
return true;
}
final ActivityRecord topActivity = topRunningActivity();
final PooledFunction f = PooledLambda.obtainFunction(
CheckBehindFullscreenActivityHelper::processActivity, this,
PooledLambda.__(ActivityRecord.class), topActivity);
forAllActivities(f);
f.recycle();
return mBehindFullscreenActivity;
}
/** Returns {@code true} to stop the outer loop and indicate the result is computed. */
private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) {
if (mAboveTop) {
if (r == topActivity) {
if (r == mToCheck) {
// It is the top activity in a visible stack.
mBehindFullscreenActivity = false;
return true;
}
mAboveTop = false;
}
mBehindFullscreenActivity |= r.occludesParent();
return false;
}
if (mHandlingOccluded) {
// Iterating through all occluded activities.
if (mBehindFullscreenActivity) {
mHandleBehindFullscreenActivity.accept(r);
}
} else if (r == mToCheck) {
return true;
} else if (mBehindFullscreenActivity) {
// It is occluded before {@param toCheck} is found.
return true;
}
mBehindFullscreenActivity |= r.occludesParent();
return false;
}
}
// TODO: Can we just loop through WindowProcessController#mActivities instead of doing this?
private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp =
new RemoveHistoryRecordsForApp();
@@ -1434,25 +1359,6 @@ class ActivityStack extends Task {
}
}
/** @see ActivityRecord#cancelInitializing() */
void cancelInitializingActivities() {
// We don't want to clear starting window for activities that aren't behind fullscreen
// activities as we need to display their starting window until they are done initializing.
checkBehindFullscreenActivity(null /* toCheck */, ActivityRecord::cancelInitializing);
}
/**
* If an activity {@param toCheck} is given, this method returns {@code true} if the activity
* is occluded by any fullscreen activity. If there is no {@param toCheck} and the handling
* function {@param handleBehindFullscreenActivity} is given, this method will pass all occluded
* activities to the function.
*/
boolean checkBehindFullscreenActivity(ActivityRecord toCheck,
Consumer<ActivityRecord> handleBehindFullscreenActivity) {
return mCheckBehindFullscreenActivityHelper.process(
toCheck, handleBehindFullscreenActivity);
}
/**
* Ensure that the top activity in the stack is resumed.
*
@@ -2660,16 +2566,6 @@ class ActivityStack extends Task {
task.setBounds(task.isResizeable() ? bounds : null);
}
/**
* Returns the top-most activity that occludes the given one, or @{code null} if none.
*/
@Nullable
private ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
ActivityRecord top = getActivity((ar) -> ar.occludesParent(),
true /* traverseTopToBottom */, activity);
return top != activity ? top : null;
}
boolean willActivityBeVisible(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {

View File

@@ -3353,7 +3353,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void cancelInitializingActivities() {
forAllTaskDisplayAreas(taskDisplayArea -> {
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
taskDisplayArea.getStackAt(sNdx).cancelInitializingActivities();
// We don't want to clear starting window for activities that aren't occluded
// as we need to display their starting window until they are done initializing.
taskDisplayArea.getStackAt(sNdx).forAllOccludedActivities(
ActivityRecord::cancelInitializing);
}
});
}

View File

@@ -3175,6 +3175,33 @@ class Task extends WindowContainer<WindowContainer> {
return false;
}
/** 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);
return top != activity ? top : null;
}
/** Iterates through all occluded activities. */
void forAllOccludedActivities(Consumer<ActivityRecord> handleOccludedActivity) {
if (!shouldBeVisible(null /* starting */)) {
// The stack is invisible so all activities are occluded.
forAllActivities(handleOccludedActivity);
return;
}
final ActivityRecord topOccluding = getOccludingActivityAbove(null);
if (topOccluding == null) {
// No activities are occluded.
return;
}
// Invoke the callback on the activities behind the top occluding activity.
forAllActivities(r -> {
handleOccludedActivity.accept(r);
return false;
}, topOccluding, false /* includeBoundary */, true /* traverseTopToBottom */);
}
@Override
public SurfaceControl.Builder makeAnimationLeash() {
return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);

View File

@@ -1331,42 +1331,40 @@ public class ActivityStackTests extends ActivityTestsBase {
}
@Test
public void testCheckBehindFullscreenActivity() {
public void testIterateOccludedActivity() {
final ArrayList<ActivityRecord> occludedActivities = new ArrayList<>();
final Consumer<ActivityRecord> handleBehindFullscreenActivity = occludedActivities::add;
final Consumer<ActivityRecord> handleOccludedActivity = occludedActivities::add;
final ActivityRecord bottomActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
final ActivityRecord topActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
doReturn(true).when(mStack).shouldBeVisible(any());
assertTrue(mStack.checkBehindFullscreenActivity(bottomActivity,
null /* handleBehindFullscreenActivity */));
assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
null /* handleBehindFullscreenActivity */));
// Top activity occludes bottom activity.
mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
doReturn(true).when(mStack).shouldBeVisible(any());
assertTrue(topActivity.shouldBeVisible());
assertFalse(bottomActivity.shouldBeVisible());
mStack.forAllOccludedActivities(handleOccludedActivity);
assertThat(occludedActivities).containsExactly(bottomActivity);
// Top activity doesn't occlude parent, so the bottom activity is not occluded.
doReturn(false).when(topActivity).occludesParent();
assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
null /* handleBehindFullscreenActivity */));
assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
null /* handleBehindFullscreenActivity */));
assertTrue(bottomActivity.shouldBeVisible());
occludedActivities.clear();
// Top activity doesn't occlude parent, so the bottom activity is not occluded.
mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
mStack.forAllOccludedActivities(handleOccludedActivity);
assertThat(occludedActivities).isEmpty();
// A finishing activity should not occlude other activities behind.
final ActivityRecord finishingActivity =
new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
finishingActivity.finishing = true;
doCallRealMethod().when(finishingActivity).occludesParent();
assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
null /* handleBehindFullscreenActivity */));
assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
null /* handleBehindFullscreenActivity */));
assertTrue(topActivity.shouldBeVisible());
assertTrue(bottomActivity.shouldBeVisible());
occludedActivities.clear();
mStack.forAllOccludedActivities(handleOccludedActivity);
assertThat(occludedActivities).isEmpty();
}
@Test