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

Commit 6f0cd1ec authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Use non finishing activity for remote animation opening target

If an existing task is moving to front by launching a trampoline
activity on top of the task, the finishing trampoline activity
should be skipped when choosing the remote animation target.
Otherwise there is no opening animation because the topmost activity
of the task may not have a window, i.e. RemoteAnimationController
skips the animation due to ActivityRecord#createRemoteAnimationTarget
returns null.

Now the mode of remote animation target is set explicitly when
requesting the animation, so the animatable container can choose the
proper target according to the mode.

Bug: 196636209
Test: atest RemoteAnimationControllerTest# \
            testOpeningTaskWithTopFinishingActivity
Change-Id: I0642dabec8889e101f831465a98707caba708362
parent 5cbb831c
Loading
Loading
Loading
Loading
+6 −11
Original line number Diff line number Diff line
@@ -396,6 +396,7 @@ class RemoteAnimationController implements DeathRecipient {
        RemoteAnimationTarget mTarget;
        final WindowContainer mWindowContainer;
        final Rect mStartBounds;
        private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING;

        RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
                Rect endBounds, Rect startBounds) {
@@ -428,18 +429,12 @@ class RemoteAnimationController implements DeathRecipient {
            return mTarget;
        }

        int getMode() {
            final DisplayContent dc = mWindowContainer.getDisplayContent();
            final ActivityRecord topActivity = mWindowContainer.getTopMostActivity();
            // Note that opening/closing transitions are per-activity while changing transitions
            // are per-task.
            if (dc.mOpeningApps.contains(topActivity)) {
                return RemoteAnimationTarget.MODE_OPENING;
            } else if (dc.mChangingContainers.contains(mWindowContainer)) {
                return RemoteAnimationTarget.MODE_CHANGING;
            } else {
                return RemoteAnimationTarget.MODE_CLOSING;
        void setMode(@RemoteAnimationTarget.Mode int mode) {
            mMode = mode;
        }

        int getMode() {
            return mMode;
        }
    }

+6 −1
Original line number Diff line number Diff line
@@ -1616,7 +1616,12 @@ class TaskFragment extends WindowContainer<WindowContainer> {
    @Override
    RemoteAnimationTarget createRemoteAnimationTarget(
            RemoteAnimationController.RemoteAnimationRecord record) {
        final ActivityRecord activity = getTopMostActivity();
        final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
                // There may be a trampoline activity without window on top of the existing task
                // which is moving to front. Exclude the finishing activity so the window of next
                // activity can be chosen to create the animation target.
                ? getTopNonFinishingActivity()
                : getTopMostActivity();
        return activity != null ? activity.createRemoteAnimationTarget(record) : null;
    }

+5 −0
Original line number Diff line number Diff line
@@ -2689,6 +2689,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
            final RemoteAnimationController.RemoteAnimationRecord adapters =
                    controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
                            screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
            if (!isChanging) {
                adapters.setMode(enter
                        ? RemoteAnimationTarget.MODE_OPENING
                        : RemoteAnimationTarget.MODE_CLOSING);
            }
            resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
        } else if (isChanging) {
            final float durationScale = mWmService.getTransitionAnimationScaleLocked();
+27 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -273,6 +274,32 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
                eq(adapter));
    }

    @Test
    public void testOpeningTaskWithTopFinishingActivity() {
        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "win");
        final Task task = win.getTask();
        final ActivityRecord topFinishing = new ActivityBuilder(mAtm).setTask(task).build();
        // Now the task contains:
        //     - Activity[1] (top, finishing, no window)
        //     - Activity[0] (has window)
        topFinishing.finishing = true;
        spyOn(mDisplayContent.mAppTransition);
        doReturn(mController).when(mDisplayContent.mAppTransition).getRemoteAnimationController();
        task.applyAnimationUnchecked(null /* lp */, true /* enter */, TRANSIT_OLD_TASK_OPEN,
                false /* isVoiceInteraction */, null /* sources */);
        mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
        mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
        final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
                ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
        try {
            verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
                    appsCaptor.capture(), any(), any(), any());
        } catch (RemoteException ignored) {
        }
        assertEquals(1, appsCaptor.getValue().length);
        assertEquals(RemoteAnimationTarget.MODE_OPENING, appsCaptor.getValue()[0].mode);
    }

    @Test
    public void testChangeToSmallerSize() throws Exception {
        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");