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

Commit b3a888c6 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix mLaunchTaskBehind is not restored when canceling recents" into qt-dev

parents dd82c451 43233b72
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -60,6 +60,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
    private final ActivityDisplay mDefaultDisplay;
    private final int mCallingPid;

    /**
     * The activity which has been launched behind. We need to remember the activity because the
     * target stack may have other activities, then we are able to restore the launch-behind state
     * for the exact activity.
     */
    private ActivityRecord mLaunchedTargetActivity;
    private int mTargetActivityType;

    // The stack to restore the target stack behind when the animation is finished
@@ -175,6 +181,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
            // Mark the target activity as launch-behind to bump its visibility for the
            // duration of the gesture that is driven by the recents component
            targetActivity.mLaunchTaskBehind = true;
            mLaunchedTargetActivity = targetActivity;

            // Fetch all the surface controls and pass them to the client to get the animation
            // started. Cancel any existing recents animation running synchronously (do not hold the
@@ -233,8 +240,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks,

                    final ActivityStack targetStack = mDefaultDisplay.getStack(
                            WINDOWING_MODE_UNDEFINED, mTargetActivityType);
                    // Prefer to use the original target activity instead of top activity because
                    // we may have moved another task to top (starting 3p launcher).
                    final ActivityRecord targetActivity = targetStack != null
                            ? targetStack.getTopActivity()
                            ? targetStack.isInStackLocked(mLaunchedTargetActivity)
                            : null;
                    if (DEBUG) Slog.d(TAG, "onAnimationFinished(): targetStack=" + targetStack
                            + " targetActivity=" + targetActivity
+4 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealM
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -132,6 +133,9 @@ class ActivityTestsBase {
            mService.setWindowManager(null);
            mService = null;
        }
        if (sMockWindowManagerService != null) {
            reset(sMockWindowManagerService);
        }

        mMockTracker.close();
        mMockTracker = null;
+79 −15
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -28,17 +29,20 @@ 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.RecentsAnimationController.REORDER_KEEP_IN_PLACE;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.platform.test.annotations.Presubmit;
import android.view.IRecentsAnimationRunner;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;

import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;

import org.junit.Before;
import org.junit.Test;

@@ -50,24 +54,62 @@ import org.junit.Test;
@Presubmit
public class RecentsAnimationTest extends ActivityTestsBase {

    private Context mContext = InstrumentationRegistry.getContext();
    private ComponentName mRecentsComponent;
    private final ComponentName mRecentsComponent =
            new ComponentName(mContext.getPackageName(), "RecentsActivity");
    private RecentsAnimationController mRecentsAnimationController;

    @Before
    public void setUp() throws Exception {
        mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity");
        mService = new TestActivityTaskManagerService(mContext);
        mRecentsAnimationController = mock(RecentsAnimationController.class);
        doReturn(mRecentsAnimationController).when(
                mService.mWindowManager).getRecentsAnimationController();
        doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation();

        final RecentTasks recentTasks = mService.getRecentTasks();
        spyOn(recentTasks);
        mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity");
        doReturn(mRecentsComponent).when(recentTasks).getRecentsComponent();
    }

    @Test
    public void testSetLaunchTaskBehindOfTargetActivity() {
        ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
        display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
        ActivityStack homeStack = display.getHomeStack();
        // Assume the home activity support recents.
        ActivityRecord targetActivity = homeStack.getTopActivity();
        // Put another home activity in home stack.
        ActivityRecord anotherHomeActivity = new ActivityBuilder(mService)
                .setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
                .setCreateTask(true)
                .setStack(homeStack)
                .build();
        // Start an activity on top so the recents activity can be started.
        new ActivityBuilder(mService)
                .setCreateTask(true)
                .build()
                .getActivityStack()
                .moveToFront("Activity start");

        // Start the recents animation.
        RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
                targetActivity.getTaskRecord().getBaseIntent().getComponent(),
                true /* getRecentsAnimation */);
        // Ensure launch-behind is set for being visible.
        assertTrue(targetActivity.mLaunchTaskBehind);

        anotherHomeActivity.moveFocusableActivityToTop("launchAnotherHome");
        // The current top activity is not the recents so the animation should be canceled.
        verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
                eq(REORDER_KEEP_IN_PLACE), any() /* reason */);

        // The test uses mocked RecentsAnimationController so we have to invoke the callback
        // manually to simulate the flow.
        recentsAnimation.onAnimationFinished(REORDER_KEEP_IN_PLACE, true /* runSychronously */,
                false /* sendUserLeaveHint */);
        // We should restore the launch-behind of the original target activity.
        assertFalse(targetActivity.mLaunchTaskBehind);
    }

    @Test
    public void testCancelAnimationOnVisibleStackOrderChange() {
        ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
@@ -93,12 +135,9 @@ public class RecentsAnimationTest extends ActivityTestsBase {
                .setCreateTask(true)
                .setStack(fullscreenStack2)
                .build();
        doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation();

        // Start the recents animation
        Intent recentsIntent = new Intent();
        recentsIntent.setComponent(mRecentsComponent);
        mService.startRecentsActivity(recentsIntent, null, mock(IRecentsAnimationRunner.class));
        startRecentsActivity();

        fullscreenStack.moveToFront("Activity start");

@@ -140,12 +179,9 @@ public class RecentsAnimationTest extends ActivityTestsBase {
                .setCreateTask(true)
                .setStack(fullscreenStack2)
                .build();
        doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation();

        // Start the recents animation
        Intent recentsIntent = new Intent();
        recentsIntent.setComponent(mRecentsComponent);
        mService.startRecentsActivity(recentsIntent, null, mock(IRecentsAnimationRunner.class));
        startRecentsActivity();

        fullscreenStack.remove();

@@ -154,4 +190,32 @@ public class RecentsAnimationTest extends ActivityTestsBase {
                eq(REORDER_KEEP_IN_PLACE), any());
        verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
    }

    private void startRecentsActivity() {
        startRecentsActivity(mRecentsComponent, false /* getRecentsAnimation */);
    }

    /**
     * @return non-null {@link RecentsAnimationCallbacks} if the given {@code getRecentsAnimation}
     *         is {@code true}.
     */
    private RecentsAnimationCallbacks startRecentsActivity(ComponentName recentsComponent,
            boolean getRecentsAnimation) {
        RecentsAnimationCallbacks[] recentsAnimation = { null };
        if (getRecentsAnimation) {
            doAnswer(invocation -> {
                // The callback is actually RecentsAnimation.
                recentsAnimation[0] = invocation.getArgument(2);
                return null;
            }).when(mService.mWindowManager).initializeRecentsAnimation(
                    anyInt() /* targetActivityType */, any() /* recentsAnimationRunner */,
                    any() /* callbacks */, anyInt() /* displayId */, any() /* recentTaskIds */);
        }

        Intent recentsIntent = new Intent();
        recentsIntent.setComponent(recentsComponent);
        mService.startRecentsActivity(recentsIntent, null /* assistDataReceiver */,
                mock(IRecentsAnimationRunner.class));
        return recentsAnimation[0];
    }
}