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

Commit fae90467 authored by Evan Rosky's avatar Evan Rosky Committed by Automerger Merge Worker
Browse files

Merge "Don't abort transition for activity re-ordering." into tm-qpr-dev am:...

Merge "Don't abort transition for activity re-ordering." into tm-qpr-dev am: 6fae7ad3 am: 11b75eba

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



Change-Id: I4a02b42a3166be2de0b107a2b602b7e57fcde196
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 67ce114b 11b75eba
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -194,6 +194,10 @@ class ActivityStarter {
    private TaskFragment mAddingToTaskFragment;
    @VisibleForTesting
    boolean mAddingToTask;
    // Activity that was moved to the top of its task in situations where activity-order changes
    // due to launch flags (eg. REORDER_TO_TOP).
    @VisibleForTesting
    ActivityRecord mMovedToTopActivity;

    private Task mSourceRootTask;
    private Task mTargetRootTask;
@@ -1484,7 +1488,9 @@ class ActivityStarter {
            // The activity is started new rather than just brought forward, so record it as an
            // existence change.
            transitionController.collectExistenceChange(started);
        } else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
        } else if (result == START_DELIVERED_TO_TOP && newTransition != null
                // An activity has changed order/visibility so this isn't just deliver-to-top
                && mMovedToTopActivity == null) {
            // We just delivered to top, so there isn't an actual transition here.
            if (!forceTransientTransition) {
                newTransition.abort();
@@ -2071,10 +2077,15 @@ class ActivityStarter {
            // In this situation we want to remove all activities from the task up to the one
            // being started. In most cases this means we are resetting the task to its initial
            // state.
            int[] finishCount = new int[1];
            final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
                    mLaunchFlags);
                    mLaunchFlags, finishCount);

            if (clearTop != null && !clearTop.finishing) {
                if (finishCount[0] > 0) {
                    // Only record if actually moved to top.
                    mMovedToTopActivity = clearTop;
                }
                if (clearTop.isRootOfTask()) {
                    // Activity aliases may mean we use different intents for the top activity,
                    // so make sure the task now has the identity of the new intent.
@@ -2111,7 +2122,11 @@ class ActivityStarter {
                            mStartActivity.mUserId);
            if (act != null) {
                final Task task = act.getTask();
                task.moveActivityToFrontLocked(act);
                boolean actuallyMoved = task.moveActivityToFrontLocked(act);
                if (actuallyMoved) {
                    // Only record if the activity actually moved.
                    mMovedToTopActivity = act;
                }
                act.updateOptionsLocked(mOptions);
                deliverNewIntent(act, intentGrants);
                act.getTaskFragment().clearLastPausedActivity();
+16 −7
Original line number Diff line number Diff line
@@ -1402,13 +1402,15 @@ class Task extends TaskFragment {

    /**
     * Reorder the history task so that the passed activity is brought to the front.
     * @return whether it was actually moved (vs already being top).
     */
    final void moveActivityToFrontLocked(ActivityRecord newTop) {
    final boolean moveActivityToFrontLocked(ActivityRecord newTop) {
        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top "
                + "callers=%s", newTop, Debug.getCallers(4));

        int origDist = getDistanceFromTop(newTop);
        positionChildAtTop(newTop);
        updateEffectiveIntent();
        return getDistanceFromTop(newTop) != origDist;
    }

    @Override
@@ -1607,14 +1609,14 @@ class Task extends TaskFragment {
        }
    }

    ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
    ActivityRecord performClearTop(ActivityRecord newR, int launchFlags, int[] finishCount) {
        // The task should be preserved for putting new activity in case the last activity is
        // finished if it is normal launch mode and not single top ("clear-task-top").
        mReuseTask = true;
        mTaskSupervisor.beginDeferResume();
        final ActivityRecord result;
        try {
            result = clearTopActivities(newR, launchFlags);
            result = clearTopActivities(newR, launchFlags, finishCount);
        } finally {
            mTaskSupervisor.endDeferResume();
            mReuseTask = false;
@@ -1630,14 +1632,19 @@ class Task extends TaskFragment {
     * activities on top of it and return the instance.
     *
     * @param newR Description of the new activity being started.
     * @param finishCount 1-element array that will be populated with the number of activities
     *                    that have been finished.
     * @return Returns the existing activity in the task that performs the clear-top operation,
     * or {@code null} if none was found.
     */
    private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags) {
    private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags,
            int[] finishCount) {
        final ActivityRecord r = findActivityInHistory(newR.mActivityComponent, newR.mUserId);
        if (r == null) return null;

        final PooledPredicate f = PooledLambda.obtainPredicate(Task::finishActivityAbove,
        final PooledPredicate f = PooledLambda.obtainPredicate(
                (ActivityRecord ar, ActivityRecord boundaryActivity) ->
                        finishActivityAbove(ar, boundaryActivity, finishCount),
                PooledLambda.__(ActivityRecord.class), r);
        forAllActivities(f);
        f.recycle();
@@ -1655,7 +1662,8 @@ class Task extends TaskFragment {
        return r;
    }

    private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
    private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity,
            @NonNull int[] finishCount) {
        // Stop operation once we reach the boundary activity.
        if (r == boundaryActivity) return true;

@@ -1666,6 +1674,7 @@ class Task extends TaskFragment {
                // TODO: Why is this updating the boundary activity vs. the current activity???
                boundaryActivity.updateOptionsLocked(opts);
            }
            finishCount[0] += 1;
            r.finishIfPossible("clear-task-stack", false /* oomAdj */);
        }

+5 −0
Original line number Diff line number Diff line
@@ -1837,6 +1837,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        return null;
    }

    int getDistanceFromTop(WindowContainer child) {
        int idx = mChildren.indexOf(child);
        return idx < 0 ? -1 : mChildren.size() - 1 - idx;
    }

    private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback,
            WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
            boolean[] boundaryFound, WindowContainer wc) {
+35 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
@@ -66,6 +67,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -1408,6 +1410,39 @@ public class ActivityStarterTests extends WindowTestsBase {
                canEmbedActivity(taskFragment, starting, task));
    }

    @Test
    public void testRecordActivityMovementBeforeDeliverToTop() {
        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
        final ActivityRecord activityBot = new ActivityBuilder(mAtm).setTask(task).build();
        final ActivityRecord activityTop = new ActivityBuilder(mAtm).setTask(task).build();

        activityBot.setVisible(false);
        activityBot.mVisibleRequested = false;

        assertTrue(activityTop.isVisible());
        assertTrue(activityTop.mVisibleRequested);

        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
                        | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
        starter.mStartActivity = activityBot;
        task.inRecents = true;
        starter.setInTask(task);
        starter.getIntent().setComponent(activityBot.mActivityComponent);
        final int result = starter.setReason("testRecordActivityMovement").execute();

        assertEquals(START_DELIVERED_TO_TOP, result);
        assertNotNull(starter.mMovedToTopActivity);

        final ActivityStarter starter2 = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
                        | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
        starter2.setInTask(task);
        starter2.getIntent().setComponent(activityBot.mActivityComponent);
        final int result2 = starter2.setReason("testRecordActivityMovement").execute();

        assertEquals(START_DELIVERED_TO_TOP, result2);
        assertNull(starter2.mMovedToTopActivity);
    }

    private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
            ActivityRecord source, ActivityOptions options, Task inTask,
            TaskFragment inTaskFragment) {
+3 −2
Original line number Diff line number Diff line
@@ -263,7 +263,8 @@ public class TaskTests extends WindowTestsBase {
        // Detach from process so the activities can be removed from hierarchy when finishing.
        activity1.detachFromProcess();
        activity2.detachFromProcess();
        assertTrue(task.performClearTop(activity1, 0 /* launchFlags */).finishing);
        int[] finishCount = new int[1];
        assertTrue(task.performClearTop(activity1, 0 /* launchFlags */, finishCount).finishing);
        assertFalse(task.hasChild());
        // In real case, the task should be preserved for adding new activity.
        assertTrue(task.isAttached());
@@ -277,7 +278,7 @@ public class TaskTests extends WindowTestsBase {
        doReturn(true).when(activityB).shouldBeVisibleUnchecked();
        doReturn(true).when(activityC).shouldBeVisibleUnchecked();
        activityA.getConfiguration().densityDpi += 100;
        assertTrue(task.performClearTop(activityA, 0 /* launchFlags */).finishing);
        assertTrue(task.performClearTop(activityA, 0 /* launchFlags */, finishCount).finishing);
        // The bottom activity should destroy directly without relaunch for config change.
        assertEquals(ActivityRecord.State.DESTROYING, activityA.getState());
        verify(activityA, never()).startRelaunching();