Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95630a20 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Simplify check-behind-fullscreen-activity

Since the general traversal methods getOccludingActivityAbove
and forAllActivities are available, the complex helper can
be replaced with the combination of traversal methods.

Bug: 160776093
Test: atest ActivityStackTests#testIterateOccludedActivity
Change-Id: Ifd821a12a0148d7e51b145a507ef8b54ccbdc531
parent 59ce935e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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 */);
    }

+0 −104
Original line number Diff line number Diff line
@@ -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) {
+4 −1
Original line number Diff line number Diff line
@@ -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);
            }
        });
    }
+27 −0
Original line number Diff line number Diff line
@@ -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);
+16 −18
Original line number Diff line number Diff line
@@ -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();
        // Top activity occludes bottom activity.
        doReturn(true).when(mStack).shouldBeVisible(any());
        assertTrue(mStack.checkBehindFullscreenActivity(bottomActivity,
                null /* handleBehindFullscreenActivity */));
        assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
                null /* handleBehindFullscreenActivity */));
        assertTrue(topActivity.shouldBeVisible());
        assertFalse(bottomActivity.shouldBeVisible());

        // Top activity occludes bottom activity.
        mStack.checkBehindFullscreenActivity(null /* toCheck */, handleBehindFullscreenActivity);
        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