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

Commit a5cf6804 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Do not execute app transition too early

We execute an app transition if something was moved to the front,
but that activity was already resumed because when moving a task
to the front, we rely on the activityResumed callback to update
visibility and execute the transition usually, which doesn't
happen in that case.

However, we should only do that for the top task/stack as
otherwise we may execute an app transition too early in case an
activity behind the top one is still visible and resumed, like it
can happen when Launcher finishes the recents animation and
quickly launches the next one.

Test: Quick switch 100 times, no flashing
Bug: 129729087
Change-Id: Id76643e01c8e1c4b3ffd0d5a2fa38a35336e1d9e
parent c84e33b3
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -1150,8 +1150,9 @@ class RootActivityContainer extends ConfigurationContainer
                    resumedOnDisplay |= result;
                    continue;
                }
                if (topRunningActivity.isState(RESUMED)) {
                    // Kick off any lingering app transitions form the MoveTaskToFront operation.
                if (display.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
                    // Kick off any lingering app transitions form the MoveTaskToFront operation,
                    // but only consider the top task and stack on that display.
                    stack.executeAppTransition(targetOptions);
                } else {
                    resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
+47 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import android.util.Pair;
import androidx.test.filters.MediumTest;

import com.android.internal.app.ResolverActivity;
import com.android.server.wm.ActivityStack.ActivityState;

import org.junit.Before;
import org.junit.Test;
@@ -394,6 +395,52 @@ public class RootActivityContainerTests extends ActivityTestsBase {
                eq(activity), eq(null /* targetOptions */));
    }

    /**
     * Verify that a lingering transition is being executed in case the activity to be resumed is
     * already resumed
     */
    @Test
    public void testResumeActivityLingeringTransition() {
        // Create a stack at top.
        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
        final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                ACTIVITY_TYPE_STANDARD, false /* onTop */));
        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
        final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
        activity.setState(ActivityState.RESUMED, "test");

        // Assume the stack is at the topmost position
        assertTrue(targetStack.isTopStackOnDisplay());

        // Use the stack as target to resume.
        mRootActivityContainer.resumeFocusedStacksTopActivities();

        // Verify the lingering app transition is being executed because it's already resumed
        verify(targetStack, times(1)).executeAppTransition(any());
    }

    @Test
    public void testResumeActivityLingeringTransition_notExecuted() {
        // Create a stack at bottom.
        final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
        final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                ACTIVITY_TYPE_STANDARD, false /* onTop */));
        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
        final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
        activity.setState(ActivityState.RESUMED, "test");
        display.positionChildAtBottom(targetStack);

        // Assume the stack is at the topmost position
        assertFalse(targetStack.isTopStackOnDisplay());
        doReturn(targetStack).when(mRootActivityContainer).getTopDisplayFocusedStack();

        // Use the stack as target to resume.
        mRootActivityContainer.resumeFocusedStacksTopActivities();

        // Verify the lingering app transition is being executed because it's already resumed
        verify(targetStack, never()).executeAppTransition(any());
    }

    /**
     * Tests that home activities can be started on the displays that supports system decorations.
     */