Loading core/res/res/values/config.xml +5 −0 Original line number Diff line number Diff line Loading @@ -3345,6 +3345,11 @@ <!-- The duration in which a recent task is considered in session and should be visible. --> <integer name="config_activeTaskDurationHours">6</integer> <!-- Whether this device prefers to show snapshot or splash screen on back predict target. When set true, there will create windowless starting surface for the preview target, so it won't affect activity's lifecycle. This should only be disabled on low-ram device. --> <bool name="config_predictShowStartingSurface">true</bool> <!-- default window ShowCircularMask property --> <bool name="config_windowShowCircularMask">false</bool> Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,7 @@ <java-symbol type="integer" name="config_maxNumVisibleRecentTasks" /> <java-symbol type="integer" name="config_activeTaskDurationHours" /> <java-symbol type="bool" name="config_windowShowCircularMask" /> <java-symbol type="bool" name="config_predictShowStartingSurface" /> <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" /> <java-symbol type="bool" name="config_supportMicNearUltrasound" /> <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" /> Loading services/core/java/com/android/server/wm/BackNavigationController.java +43 −34 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.ResourceId; import android.graphics.Point; import android.graphics.Rect; Loading Loading @@ -75,7 +76,7 @@ class BackNavigationController { private Runnable mPendingAnimation; private final NavigationMonitor mNavigationMonitor = new NavigationMonitor(); private AnimationHandler mAnimationHandler; AnimationHandler mAnimationHandler; private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); Loading Loading @@ -651,7 +652,8 @@ class BackNavigationController { /** * Create and handling animations status for an open/close animation targets. */ private static class AnimationHandler { static class AnimationHandler { private final boolean mShowWindowlessSurface; private final WindowManagerService mWindowManagerService; private BackWindowAnimationAdaptor mCloseAdaptor; private BackWindowAnimationAdaptor mOpenAdaptor; Loading @@ -670,6 +672,9 @@ class BackNavigationController { AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; final Context context = wms.mContext; mShowWindowlessSurface = context.getResources().getBoolean( com.android.internal.R.bool.config_predictShowStartingSurface); } private static final int UNKNOWN = 0; private static final int TASK_SWITCH = 1; Loading Loading @@ -714,7 +719,8 @@ class BackNavigationController { } } boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { private boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { clearBackAnimateTarget(null /* cleanupTransaction */); if (close == null || open == null) { Slog.e(TAG, "reset animation with null target close: " Loading Loading @@ -998,21 +1004,20 @@ class BackNavigationController { case BackNavigationInfo.TYPE_CROSS_ACTIVITY: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentActivity, previousActivity) .setOpeningSnapshot(getActivitySnapshot(previousActivity)); .setIsLaunchBehind(false); case BackNavigationInfo.TYPE_CROSS_TASK: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentTask, previousTask) .setOpeningSnapshot(getTaskSnapshot(previousTask)); .setIsLaunchBehind(false); } return null; } private class ScheduleAnimationBuilder { class ScheduleAnimationBuilder { final int mType; final BackAnimationAdapter mBackAnimationAdapter; WindowContainer mCloseTarget; WindowContainer mOpenTarget; TaskSnapshot mOpenSnapshot; boolean mIsLaunchBehind; ScheduleAnimationBuilder(int type, BackAnimationAdapter backAnimationAdapter) { Loading @@ -1026,11 +1031,6 @@ class BackNavigationController { return this; } ScheduleAnimationBuilder setOpeningSnapshot(TaskSnapshot snapshot) { mOpenSnapshot = snapshot; return this; } ScheduleAnimationBuilder setIsLaunchBehind(boolean launchBehind) { mIsLaunchBehind = launchBehind; return this; Loading @@ -1041,17 +1041,32 @@ class BackNavigationController { || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget); } /** * Apply preview strategy on the opening target * @param open The opening target. * @param visibleOpenActivity The visible activity in opening target. * @return If the preview strategy is launch behind, returns the Activity that has * launchBehind set, or null otherwise. */ private ActivityRecord applyPreviewStrategy(WindowContainer open, ActivityRecord visibleOpenActivity) { if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { createStartingSurface(getSnapshot(open)); return null; } setLaunchBehind(visibleOpenActivity); return visibleOpenActivity; } Runnable build() { if (mOpenTarget == null || mCloseTarget == null) { return null; } final boolean shouldLaunchBehind = mIsLaunchBehind || !isSupportWindowlessSurface(); final ActivityRecord launchBehindActivity = !shouldLaunchBehind ? null : mOpenTarget.asTask() != null final ActivityRecord openActivity = mOpenTarget.asTask() != null ? mOpenTarget.asTask().getTopNonFinishingActivity() : mOpenTarget.asActivityRecord() != null ? mOpenTarget.asActivityRecord() : null; if (shouldLaunchBehind && launchBehindActivity == null) { if (openActivity == null) { Slog.e(TAG, "No opening activity"); return null; } Loading @@ -1059,11 +1074,8 @@ class BackNavigationController { if (!composeAnimations(mCloseTarget, mOpenTarget)) { return null; } if (launchBehindActivity != null) { setLaunchBehind(launchBehindActivity); } else { createStartingSurface(mOpenSnapshot); } final ActivityRecord launchBehindActivity = applyPreviewStrategy(mOpenTarget, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback( launchBehindActivity != null ? triggerBack -> { Loading Loading @@ -1186,25 +1198,22 @@ class BackNavigationController { mPendingAnimationBuilder = null; } private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) { static TaskSnapshot getSnapshot(@NonNull WindowContainer w) { if (!isScreenshotEnabled()) { return null; } // Check if we have a screenshot of the previous activity, indexed by its // component name. // TODO return TaskSnapshot when feature complete. // final HardwareBuffer hw = r.getTask().getSnapshotForActivityRecord(r); return null; if (w.asTask() != null) { final Task task = w.asTask(); return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); } private static TaskSnapshot getTaskSnapshot(Task task) { if (!isScreenshotEnabled()) { if (w.asActivityRecord() != null) { // TODO (b/259497289) return TaskSnapshot when feature complete. return null; } // Don't read from disk!! return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); return null; } void setWindowManager(WindowManagerService wm) { Loading services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +77 −0 Original line number Diff line number Diff line Loading @@ -26,25 +26,31 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.window.BackNavigationInfo.typeToString; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.content.res.Resources; import android.os.Bundle; import android.os.RemoteCallback; import android.os.RemoteException; Loading @@ -58,6 +64,7 @@ import android.window.IOnBackInvokedCallback; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.OnBackInvokedDispatcher; import android.window.TaskSnapshot; import android.window.WindowOnBackInvokedDispatcher; import com.android.server.LocalServices; Loading @@ -66,6 +73,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; Loading Loading @@ -408,6 +417,25 @@ public class BackNavigationControllerTests extends WindowTestsBase { 0, navigationObserver.getCount()); } /** * Test with * config_predictShowStartingSurface = true */ @Test public void testEnableWindowlessSurface() { testPrepareAnimation(true); } /** * Test with * config_predictShowStartingSurface = false */ @Test public void testDisableWindowlessSurface() { testPrepareAnimation(false); } private IOnBackInvokedCallback withSystemCallback(Task task) { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo( Loading Loading @@ -492,6 +520,55 @@ public class BackNavigationControllerTests extends WindowTestsBase { doReturn(true).when(kc).isDisplayOccluded(anyInt()); } private void testPrepareAnimation(boolean preferWindowlessSurface) { final TaskSnapshot taskSnapshot = mock(TaskSnapshot.class); final ContextWrapper contextSpy = Mockito.spy(new ContextWrapper(mWm.mContext)); final Resources resourcesSpy = Mockito.spy(contextSpy.getResources()); when(contextSpy.getResources()).thenReturn(resourcesSpy); MockitoSession mockitoSession = mockitoSession().mockStatic(BackNavigationController.class) .strictness(Strictness.LENIENT).startMocking(); doReturn(taskSnapshot).when(() -> BackNavigationController.getSnapshot(any())); when(resourcesSpy.getBoolean( com.android.internal.R.bool.config_predictShowStartingSurface)) .thenReturn(preferWindowlessSurface); final BackNavigationController.AnimationHandler animationHandler = Mockito.spy(new BackNavigationController.AnimationHandler(mWm)); doReturn(true).when(animationHandler).isSupportWindowlessSurface(); testWithConfig(animationHandler, preferWindowlessSurface); mockitoSession.finishMocking(); } private void testWithConfig(BackNavigationController.AnimationHandler animationHandler, boolean preferWindowlessSurface) { final Task task = createTask(mDefaultDisplay); final ActivityRecord bottomActivity = createActivityRecord(task); final ActivityRecord homeActivity = mRootHomeTask.getTopNonFinishingActivity(); final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toHomeBuilder = animationHandler.prepareAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME, mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, homeActivity); assertTrue(toHomeBuilder.mIsLaunchBehind); toHomeBuilder.build(); verify(animationHandler, never()).createStartingSurface(any()); // Back to ACTIVITY and TASK have the same logic, just with different target. final ActivityRecord topActivity = createActivityRecord(task); final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toActivityBuilder = animationHandler.prepareAnimation( BackNavigationInfo.TYPE_CROSS_ACTIVITY, mBackAnimationAdapter, task, task, topActivity, bottomActivity); assertFalse(toActivityBuilder.mIsLaunchBehind); toActivityBuilder.build(); if (preferWindowlessSurface) { verify(animationHandler).createStartingSurface(any()); } else { verify(animationHandler, never()).createStartingSurface(any()); } } @NonNull private Task createTopTaskWithActivity() { Task task = createTask(mDefaultDisplay); Loading Loading
core/res/res/values/config.xml +5 −0 Original line number Diff line number Diff line Loading @@ -3345,6 +3345,11 @@ <!-- The duration in which a recent task is considered in session and should be visible. --> <integer name="config_activeTaskDurationHours">6</integer> <!-- Whether this device prefers to show snapshot or splash screen on back predict target. When set true, there will create windowless starting surface for the preview target, so it won't affect activity's lifecycle. This should only be disabled on low-ram device. --> <bool name="config_predictShowStartingSurface">true</bool> <!-- default window ShowCircularMask property --> <bool name="config_windowShowCircularMask">false</bool> Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -393,6 +393,7 @@ <java-symbol type="integer" name="config_maxNumVisibleRecentTasks" /> <java-symbol type="integer" name="config_activeTaskDurationHours" /> <java-symbol type="bool" name="config_windowShowCircularMask" /> <java-symbol type="bool" name="config_predictShowStartingSurface" /> <java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" /> <java-symbol type="bool" name="config_supportMicNearUltrasound" /> <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" /> Loading
services/core/java/com/android/server/wm/BackNavigationController.java +43 −34 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_PREDICT_BACK; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.ResourceId; import android.graphics.Point; import android.graphics.Rect; Loading Loading @@ -75,7 +76,7 @@ class BackNavigationController { private Runnable mPendingAnimation; private final NavigationMonitor mNavigationMonitor = new NavigationMonitor(); private AnimationHandler mAnimationHandler; AnimationHandler mAnimationHandler; private final ArrayList<WindowContainer> mTmpOpenApps = new ArrayList<>(); private final ArrayList<WindowContainer> mTmpCloseApps = new ArrayList<>(); Loading Loading @@ -651,7 +652,8 @@ class BackNavigationController { /** * Create and handling animations status for an open/close animation targets. */ private static class AnimationHandler { static class AnimationHandler { private final boolean mShowWindowlessSurface; private final WindowManagerService mWindowManagerService; private BackWindowAnimationAdaptor mCloseAdaptor; private BackWindowAnimationAdaptor mOpenAdaptor; Loading @@ -670,6 +672,9 @@ class BackNavigationController { AnimationHandler(WindowManagerService wms) { mWindowManagerService = wms; final Context context = wms.mContext; mShowWindowlessSurface = context.getResources().getBoolean( com.android.internal.R.bool.config_predictShowStartingSurface); } private static final int UNKNOWN = 0; private static final int TASK_SWITCH = 1; Loading Loading @@ -714,7 +719,8 @@ class BackNavigationController { } } boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { private boolean composeAnimations(@NonNull WindowContainer close, @NonNull WindowContainer open) { clearBackAnimateTarget(null /* cleanupTransaction */); if (close == null || open == null) { Slog.e(TAG, "reset animation with null target close: " Loading Loading @@ -998,21 +1004,20 @@ class BackNavigationController { case BackNavigationInfo.TYPE_CROSS_ACTIVITY: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentActivity, previousActivity) .setOpeningSnapshot(getActivitySnapshot(previousActivity)); .setIsLaunchBehind(false); case BackNavigationInfo.TYPE_CROSS_TASK: return new ScheduleAnimationBuilder(backType, adapter) .setComposeTarget(currentTask, previousTask) .setOpeningSnapshot(getTaskSnapshot(previousTask)); .setIsLaunchBehind(false); } return null; } private class ScheduleAnimationBuilder { class ScheduleAnimationBuilder { final int mType; final BackAnimationAdapter mBackAnimationAdapter; WindowContainer mCloseTarget; WindowContainer mOpenTarget; TaskSnapshot mOpenSnapshot; boolean mIsLaunchBehind; ScheduleAnimationBuilder(int type, BackAnimationAdapter backAnimationAdapter) { Loading @@ -1026,11 +1031,6 @@ class BackNavigationController { return this; } ScheduleAnimationBuilder setOpeningSnapshot(TaskSnapshot snapshot) { mOpenSnapshot = snapshot; return this; } ScheduleAnimationBuilder setIsLaunchBehind(boolean launchBehind) { mIsLaunchBehind = launchBehind; return this; Loading @@ -1041,17 +1041,32 @@ class BackNavigationController { || wc.hasChild(mOpenTarget) || wc.hasChild(mCloseTarget); } /** * Apply preview strategy on the opening target * @param open The opening target. * @param visibleOpenActivity The visible activity in opening target. * @return If the preview strategy is launch behind, returns the Activity that has * launchBehind set, or null otherwise. */ private ActivityRecord applyPreviewStrategy(WindowContainer open, ActivityRecord visibleOpenActivity) { if (isSupportWindowlessSurface() && mShowWindowlessSurface && !mIsLaunchBehind) { createStartingSurface(getSnapshot(open)); return null; } setLaunchBehind(visibleOpenActivity); return visibleOpenActivity; } Runnable build() { if (mOpenTarget == null || mCloseTarget == null) { return null; } final boolean shouldLaunchBehind = mIsLaunchBehind || !isSupportWindowlessSurface(); final ActivityRecord launchBehindActivity = !shouldLaunchBehind ? null : mOpenTarget.asTask() != null final ActivityRecord openActivity = mOpenTarget.asTask() != null ? mOpenTarget.asTask().getTopNonFinishingActivity() : mOpenTarget.asActivityRecord() != null ? mOpenTarget.asActivityRecord() : null; if (shouldLaunchBehind && launchBehindActivity == null) { if (openActivity == null) { Slog.e(TAG, "No opening activity"); return null; } Loading @@ -1059,11 +1074,8 @@ class BackNavigationController { if (!composeAnimations(mCloseTarget, mOpenTarget)) { return null; } if (launchBehindActivity != null) { setLaunchBehind(launchBehindActivity); } else { createStartingSurface(mOpenSnapshot); } final ActivityRecord launchBehindActivity = applyPreviewStrategy(mOpenTarget, openActivity); final IBackAnimationFinishedCallback callback = makeAnimationFinishedCallback( launchBehindActivity != null ? triggerBack -> { Loading Loading @@ -1186,25 +1198,22 @@ class BackNavigationController { mPendingAnimationBuilder = null; } private static TaskSnapshot getActivitySnapshot(@NonNull ActivityRecord r) { static TaskSnapshot getSnapshot(@NonNull WindowContainer w) { if (!isScreenshotEnabled()) { return null; } // Check if we have a screenshot of the previous activity, indexed by its // component name. // TODO return TaskSnapshot when feature complete. // final HardwareBuffer hw = r.getTask().getSnapshotForActivityRecord(r); return null; if (w.asTask() != null) { final Task task = w.asTask(); return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); } private static TaskSnapshot getTaskSnapshot(Task task) { if (!isScreenshotEnabled()) { if (w.asActivityRecord() != null) { // TODO (b/259497289) return TaskSnapshot when feature complete. return null; } // Don't read from disk!! return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( task.mTaskId, task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */); return null; } void setWindowManager(WindowManagerService wm) { Loading
services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +77 −0 Original line number Diff line number Diff line Loading @@ -26,25 +26,31 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.window.BackNavigationInfo.typeToString; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityOptions; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.content.res.Resources; import android.os.Bundle; import android.os.RemoteCallback; import android.os.RemoteException; Loading @@ -58,6 +64,7 @@ import android.window.IOnBackInvokedCallback; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedCallbackInfo; import android.window.OnBackInvokedDispatcher; import android.window.TaskSnapshot; import android.window.WindowOnBackInvokedDispatcher; import com.android.server.LocalServices; Loading @@ -66,6 +73,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; Loading Loading @@ -408,6 +417,25 @@ public class BackNavigationControllerTests extends WindowTestsBase { 0, navigationObserver.getCount()); } /** * Test with * config_predictShowStartingSurface = true */ @Test public void testEnableWindowlessSurface() { testPrepareAnimation(true); } /** * Test with * config_predictShowStartingSurface = false */ @Test public void testDisableWindowlessSurface() { testPrepareAnimation(false); } private IOnBackInvokedCallback withSystemCallback(Task task) { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo( Loading Loading @@ -492,6 +520,55 @@ public class BackNavigationControllerTests extends WindowTestsBase { doReturn(true).when(kc).isDisplayOccluded(anyInt()); } private void testPrepareAnimation(boolean preferWindowlessSurface) { final TaskSnapshot taskSnapshot = mock(TaskSnapshot.class); final ContextWrapper contextSpy = Mockito.spy(new ContextWrapper(mWm.mContext)); final Resources resourcesSpy = Mockito.spy(contextSpy.getResources()); when(contextSpy.getResources()).thenReturn(resourcesSpy); MockitoSession mockitoSession = mockitoSession().mockStatic(BackNavigationController.class) .strictness(Strictness.LENIENT).startMocking(); doReturn(taskSnapshot).when(() -> BackNavigationController.getSnapshot(any())); when(resourcesSpy.getBoolean( com.android.internal.R.bool.config_predictShowStartingSurface)) .thenReturn(preferWindowlessSurface); final BackNavigationController.AnimationHandler animationHandler = Mockito.spy(new BackNavigationController.AnimationHandler(mWm)); doReturn(true).when(animationHandler).isSupportWindowlessSurface(); testWithConfig(animationHandler, preferWindowlessSurface); mockitoSession.finishMocking(); } private void testWithConfig(BackNavigationController.AnimationHandler animationHandler, boolean preferWindowlessSurface) { final Task task = createTask(mDefaultDisplay); final ActivityRecord bottomActivity = createActivityRecord(task); final ActivityRecord homeActivity = mRootHomeTask.getTopNonFinishingActivity(); final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toHomeBuilder = animationHandler.prepareAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME, mBackAnimationAdapter, task, mRootHomeTask, bottomActivity, homeActivity); assertTrue(toHomeBuilder.mIsLaunchBehind); toHomeBuilder.build(); verify(animationHandler, never()).createStartingSurface(any()); // Back to ACTIVITY and TASK have the same logic, just with different target. final ActivityRecord topActivity = createActivityRecord(task); final BackNavigationController.AnimationHandler.ScheduleAnimationBuilder toActivityBuilder = animationHandler.prepareAnimation( BackNavigationInfo.TYPE_CROSS_ACTIVITY, mBackAnimationAdapter, task, task, topActivity, bottomActivity); assertFalse(toActivityBuilder.mIsLaunchBehind); toActivityBuilder.build(); if (preferWindowlessSurface) { verify(animationHandler).createStartingSurface(any()); } else { verify(animationHandler, never()).createStartingSurface(any()); } } @NonNull private Task createTopTaskWithActivity() { Task task = createTask(mDefaultDisplay); Loading