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

Commit d86fb556 authored by Chilun Huang's avatar Chilun Huang Committed by Automerger Merge Worker
Browse files

Merge "Update visibility when finishing activity" into sc-dev am: c4c9e2ca

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

Change-Id: If0d3ed5d7f8fc2cd18f83230788a45de50be0de7
parents 3d5033c0 c4c9e2ca
Loading
Loading
Loading
Loading
+19 −21
Original line number Diff line number Diff line
@@ -115,8 +115,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_UNSET;

import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -325,7 +323,6 @@ import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
@@ -2385,7 +2382,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        return occludesParent(false /* includingFinishing */);
    }

    private boolean occludesParent(boolean includingFinishing) {
    @VisibleForTesting
    boolean occludesParent(boolean includingFinishing) {
        if (!includingFinishing && finishing) {
            return false;
        }
@@ -2843,7 +2841,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

            final boolean endTask = task.getTopNonFinishingActivity() == null
                    && !task.isClearingToReuseTask();
            final int transit = endTask ? TRANSIT_OLD_TASK_CLOSE : TRANSIT_OLD_ACTIVITY_CLOSE;
            if (newTransition != null) {
                mAtmService.getTransitionController().requestStartTransition(newTransition,
                        endTask ? task : null, null /* remote */);
@@ -2900,7 +2897,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            } else if (!isState(PAUSING)) {
                if (mVisibleRequested) {
                    // Prepare and execute close transition.
                    prepareActivityHideTransitionAnimation(transit);
                    prepareActivityHideTransitionAnimation();
                }

                final boolean removedActivity = completeFinishing("finishIfPossible") == null;
@@ -2918,11 +2915,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                // In this case, we can set the visibility of all the task overlay activities when
                // we detect the last one is finishing to keep them in sync.
                if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) {
                    final PooledConsumer c = PooledLambda.obtainConsumer(
                            ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay,
                            PooledLambda.__(ActivityRecord.class), transit);
                    task.forAllActivities(c);
                    c.recycle();
                    task.forAllActivities((r) -> {
                        r.prepareActivityHideTransitionAnimationIfOvarlay();
                    });
                }
                return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
            } else {
@@ -2935,28 +2930,33 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        }
    }

    private void prepareActivityHideTransitionAnimationIfOvarlay(@TransitionOldType int transit) {
    private void prepareActivityHideTransitionAnimationIfOvarlay() {
        if (mTaskOverlay) {
            prepareActivityHideTransitionAnimation(transit);
            prepareActivityHideTransitionAnimation();
        }
    }

    private void prepareActivityHideTransitionAnimation(@TransitionOldType int transit) {
    private void prepareActivityHideTransitionAnimation() {
        final DisplayContent dc = mDisplayContent;
        dc.prepareAppTransition(TRANSIT_CLOSE);
        setVisibility(false);
        dc.executeAppTransition();
    }

    ActivityRecord completeFinishing(String reason) {
        return completeFinishing(true /* updateVisibility */, reason);
    }

    /**
     * Complete activity finish request that was initiated earlier. If the activity is still
     * pausing we will wait for it to complete its transition. If the activity that should appear in
     * place of this one is not visible yet - we'll wait for it first. Otherwise - activity can be
     * destroyed right away.
     * @param updateVisibility Indicate if need to update activity visibility.
     * @param reason Reason for finishing the activity.
     * @return Flag indicating whether the activity was removed from history.
     */
    ActivityRecord completeFinishing(String reason) {
    ActivityRecord completeFinishing(boolean updateVisibility, String reason) {
        if (!finishing || isState(RESUMED)) {
            throw new IllegalArgumentException(
                    "Activity must be finishing and not resumed to complete, r=" + this
@@ -2968,13 +2968,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            return this;
        }

        final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED);
        if (isCurrentVisible) {
            final Task rootTask = getRootTask();
            final ActivityRecord activity = rootTask.getResumedActivity();
        final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED, STARTED);
        if (updateVisibility && isCurrentVisible) {
            boolean ensureVisibility = false;
            if (activity != null && !activity.occludesParent()) {
                // If the resume activity is not opaque, we need to make sure the visibilities of
            if (occludesParent(true /* includingFinishing */)) {
                // If the current activity is not opaque, we need to make sure the visibilities of
                // activities be updated, they may be seen by users.
                ensureVisibility = true;
            } else if (mTaskSupervisor.getKeyguardController().isKeyguardLocked()
+6 −1
Original line number Diff line number Diff line
@@ -5842,8 +5842,13 @@ class Task extends WindowContainer<WindowContainer> {
            final boolean wasStopping = prev.isState(STOPPING);
            prev.setState(PAUSED, "completePausedLocked");
            if (prev.finishing) {
                // We will update the activity visibility later, no need to do in
                // completeFinishing(). Updating visibility here might also making the next
                // activities to be resumed, and could result in wrong app transition due to
                // lack of previous activity information.
                ProtoLog.v(WM_DEBUG_STATES, "Executing finish of activity: %s", prev);
                prev = prev.completeFinishing("completePausedLocked");
                prev = prev.completeFinishing(false /* updateVisibility */,
                        "completePausedLocked");
            } else if (prev.hasProcess()) {
                ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
                        + "wasStopping=%b visibleRequested=%b",  prev,  wasStopping,
+24 −6
Original line number Diff line number Diff line
@@ -1351,25 +1351,39 @@ public class ActivityRecordTests extends WindowTestsBase {
     * must ensure the visibilities of activities being updated.
     */
    @Test
    public void testCompleteFinishing_ensureActivitiesVisible() {
    public void testCompleteFinishing_ensureActivitiesVisible_withConditions() {
        testCompleteFinishing_ensureActivitiesVisible(false, PAUSED);
        testCompleteFinishing_ensureActivitiesVisible(false, STARTED);
        testCompleteFinishing_ensureActivitiesVisible(true, PAUSED);
        testCompleteFinishing_ensureActivitiesVisible(true, STARTED);
    }

    private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask,
            ActivityState secondActivityState) {
        final ActivityRecord activity = createActivityWithTask();
        final Task task = activity.getTask();
        final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build();
        firstActivity.mVisibleRequested = false;
        firstActivity.nowVisible = false;
        firstActivity.setState(STOPPED, "true");
        firstActivity.setState(STOPPED, "test");

        final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build();
        secondActivity.mVisibleRequested = true;
        secondActivity.nowVisible = true;
        secondActivity.setState(PAUSED, "true");
        secondActivity.setState(secondActivityState, "test");

        final ActivityRecord translucentActivity = new ActivityBuilder(mAtm).setTask(task).build();
        ActivityRecord translucentActivity;
        if (diffTask) {
            translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
        } else {
            translucentActivity = new ActivityBuilder(mAtm).setTask(task).build();
        }
        translucentActivity.mVisibleRequested = true;
        translucentActivity.nowVisible = true;
        translucentActivity.setState(RESUMED, "true");
        translucentActivity.setState(RESUMED, "test");

        doReturn(false).when(translucentActivity).occludesParent();
        doReturn(true).when(firstActivity).occludesParent(true);
        doReturn(true).when(secondActivity).occludesParent(true);

        // Finish the second activity
        secondActivity.finishing = true;
@@ -1385,6 +1399,10 @@ public class ActivityRecordTests extends WindowTestsBase {
        verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
                0 /* configChanges */ , false /* preserveWindows */,
                true /* notifyClients */);

        // Remove the translucent activity and clear invocations for next test
        translucentActivity.getTask().removeImmediately("test");
        clearInvocations(mDefaultDisplay);
    }

    /**
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
import static com.android.server.wm.Task.ActivityState.DESTROYED;
import static com.android.server.wm.Task.ActivityState.DESTROYING;
import static com.android.server.wm.Task.ActivityState.FINISHING;
import static com.android.server.wm.Task.ActivityState.PAUSING;
@@ -1204,6 +1205,9 @@ public class RootTaskTests extends WindowTestsBase {
        // See {@link ActivityStack#destroyActivityLocked}.
        activity.app = null;
        overlayActivity.app = null;
        // Simulate the process is dead
        activity.mVisibleRequested = false;
        activity.setState(DESTROYED, "Test");

        assertEquals(2, task.getChildCount());