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
This commit is contained in:
Riddle Hsu
2021-08-23 00:12:30 +08:00
parent 5cbb831c10
commit 6f0cd1ecca
4 changed files with 44 additions and 12 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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");