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

Commit ad1a4f22 authored by Chris Li's avatar Chris Li
Browse files

Not resume TaskFragment behind translucent others

When an activity is resumed, it will call to pause the activity behind,
which can cause a loop of resume/pause if the top resume activity is
translucent.

Fix: 209356462
Test: atest WmTests:TaskTests
      #testResumeTask_doNotResumeTaskFragmentBehindTranslucent
Change-Id: Id9bf75c4e623fd382a5ca619ea742a1e86059ec2
parent 7f0df9d8
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -5041,8 +5041,7 @@ class Task extends TaskFragment {
            if (topFragment == f) {
                return;
            }
            if (!f.isFocusableAndVisible()) {
                // No need to resume activity in TaskFragment that is not visible.
            if (!f.canBeResumed(null /* starting */)) {
                return;
            }
            resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
+1 −4
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

@@ -1475,9 +1474,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {

            leafTask.forAllLeafTaskFragments((taskFrag) -> {
                final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
                if (resumedActivity != null
                        && (taskFrag.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE
                        || !taskFrag.isTopActivityFocusable())) {
                if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
                    if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
                        someActivityPaused[0]++;
                    }
+11 −0
Original line number Diff line number Diff line
@@ -1359,6 +1359,17 @@ class TaskFragment extends WindowContainer<WindowContainer> {
        return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
    }

    /**
     * Returns {@code true} is the activity in this TaskFragment can be resumed.
     *
     * @param starting The currently starting activity or {@code null} if there is none.
     */
    boolean canBeResumed(@Nullable ActivityRecord starting) {
        // No need to resume activity in TaskFragment that is not visible.
        return isTopActivityFocusable()
                && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
    }

    boolean isFocusableAndVisible() {
        return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
    }
+25 −0
Original line number Diff line number Diff line
@@ -44,6 +44,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.policy.WindowManagerPolicy.USER_ROTATION_FREE;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;

import static com.google.common.truth.Truth.assertThat;

@@ -66,6 +67,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;

import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -1424,6 +1426,29 @@ public class TaskTests extends WindowTestsBase {
        verify(task2).moveToFrontInner(anyString(), isNull());
    }

    @Test
    public void testResumeTask_doNotResumeTaskFragmentBehindTranslucent() {
        final Task task = createTask(mDisplayContent);
        final TaskFragment tfBehind = createTaskFragmentWithParentTask(
                task, false /* createEmbeddedTask */);
        final TaskFragment tfFront = createTaskFragmentWithParentTask(
                task, false /* createEmbeddedTask */);
        spyOn(tfFront);
        doReturn(true).when(tfFront).isTranslucent(any());

        // TaskFragment behind another translucent TaskFragment should not be resumed.
        assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
                tfBehind.getVisibility(null /* starting */));
        assertTrue(tfBehind.isFocusable());
        assertFalse(tfBehind.canBeResumed(null /* starting */));

        spyOn(tfBehind);
        task.resumeTopActivityUncheckedLocked(null /* prev */, ActivityOptions.makeBasic(),
                false /* deferPause */);

        verify(tfBehind, never()).resumeTopActivity(any(), any(), anyBoolean());
    }

    private Task getTestTask() {
        final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
        return task.getBottomMostTask();