Use visible activity for remote animation target if available.

When creating a remote animation target for recents animation, the old
logic choose an activity which becomes visible soon (i.e.
ActivityRecord#mVisibleRequested=true). However, in the following
scenario, activity_b is to-be-visible soon, but doesn't have window yet.

1. activity_a launches activity_b
2. immediately after this, a user starts recents.

In this case, we should use activity_a whose window is already displayed
on the screen even though the activity is to-be-invisible soon.

Bug: 223499269
Bug: 231711212
Test: atest RecentsAnimationControllerTest
Change-Id: Ifeb0a18fe386d1d604e3092728e660ffaf0e6f27
This commit is contained in:
Issei Suzuki
2022-05-10 15:36:18 +00:00
parent d49b5d442d
commit e267f46e02
3 changed files with 44 additions and 5 deletions

View File

@@ -1197,7 +1197,10 @@ public class RecentsAnimationController implements DeathRecipient {
* this is the target task, CLOSING otherwise).
*/
RemoteAnimationTarget createRemoteAnimationTarget(int overrideTaskId, int overrideMode) {
final ActivityRecord topApp = mTask.getTopVisibleActivity();
ActivityRecord topApp = mTask.getTopRealVisibleActivity();
if (topApp == null) {
topApp = mTask.getTopVisibleActivity();
}
final WindowState mainWindow = topApp != null
? topApp.findMainWindow()
: null;

View File

@@ -3070,11 +3070,22 @@ class Task extends TaskFragment {
});
}
/**
* Return the top visible requested activity. The activity has been requested to be visible,
* but it's possible that the activity has just been created, so no window is yet attached to
* this activity.
*/
ActivityRecord getTopVisibleActivity() {
return getActivity((r) -> {
// skip hidden (or about to hide) apps
return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
});
return getActivity((r) -> !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested);
}
/**
* Return the top visible activity. The activity has a window on which contents are drawn.
* However it's possible that the activity has already been requested to be invisible, but the
* visibility is not yet committed.
*/
ActivityRecord getTopRealVisibleActivity() {
return getActivity((r) -> !r.mIsExiting && r.isClientVisible() && r.isVisible());
}
ActivityRecord getTopWaitSplashScreenActivity() {

View File

@@ -61,6 +61,7 @@ import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationRunner;
import android.view.SurfaceControl;
import android.view.WindowManager.LayoutParams;
import android.window.TaskSnapshot;
import androidx.test.filters.SmallTest;
@@ -161,6 +162,30 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertFalse(mController.isAnimatingTask(hiddenActivity.getTask()));
}
@Test
public void testLaunchAndStartRecents_expectTargetAndVisible() throws Exception {
mWm.setRecentsAnimationController(mController);
final ActivityRecord homeActivity = createHomeActivity();
final Task task = createTask(mDefaultDisplay);
// Emulate that activity1 has just launched activity2, but app transition has not yet been
// executed.
final ActivityRecord activity1 = createActivityRecord(task);
activity1.setVisible(true);
activity1.mVisibleRequested = false;
activity1.addWindow(createWindowState(new LayoutParams(TYPE_BASE_APPLICATION), activity1));
final ActivityRecord activity2 = createActivityRecord(task);
activity2.setVisible(false);
activity2.mVisibleRequested = true;
mDefaultDisplay.getConfiguration().windowConfiguration.setRotation(
mDefaultDisplay.getRotation());
initializeRecentsAnimationController(mController, homeActivity);
mController.startAnimation();
verify(mMockRunner, never()).onAnimationCanceled(null /* taskIds */,
null /* taskSnapshots */);
}
@Test
public void testWallpaperIncluded_expectTarget() throws Exception {
mWm.setRecentsAnimationController(mController);