From 6f0cd1ecca8f839ac9d730dd509071ddd7a2b6d9 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 23 Aug 2021 00:12:30 +0800 Subject: [PATCH] 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 --- .../server/wm/RemoteAnimationController.java | 17 +++++------- .../com/android/server/wm/TaskFragment.java | 7 ++++- .../android/server/wm/WindowContainer.java | 5 ++++ .../wm/RemoteAnimationControllerTest.java | 27 +++++++++++++++++++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index 1a429f88fe2e6..6b57ede1cd262 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -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; } + void setMode(@RemoteAnimationTarget.Mode int mode) { + mMode = mode; + } + 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; - } + return mMode; } } diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 6e4792bdbd31a..766b874e04acd 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -1616,7 +1616,12 @@ class TaskFragment extends 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; } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index c48e9d1b4dea6..136f418b3387e 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2689,6 +2689,11 @@ class 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(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java index b6cfa8e96a4c2..89ae5ed9b4251 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java @@ -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 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");