1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
20 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
21 import static android.view.WindowManager.TRANSIT_CHANGE;
22 import static android.view.WindowManager.TRANSIT_CLOSE;
23 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
24 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
25 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
26 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
27 import static android.view.WindowManager.TRANSIT_NONE;
28 import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
29 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
30 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
31 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
32 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
33 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
34 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
35 import static android.view.WindowManager.TRANSIT_OPEN;
36 
37 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
38 
39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
45 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
46 import static com.android.server.wm.WindowContainer.POSITION_TOP;
47 
48 import static org.junit.Assert.assertEquals;
49 import static org.junit.Assert.assertFalse;
50 import static org.junit.Assert.assertNull;
51 import static org.junit.Assert.assertTrue;
52 import static org.junit.Assume.assumeFalse;
53 import static org.mockito.ArgumentMatchers.any;
54 import static org.mockito.ArgumentMatchers.anyBoolean;
55 import static org.mockito.Mockito.mock;
56 import static org.mockito.Mockito.never;
57 
58 import android.graphics.Rect;
59 import android.os.Binder;
60 import android.os.IBinder;
61 import android.os.RemoteException;
62 import android.platform.test.annotations.Presubmit;
63 import android.util.ArraySet;
64 import android.view.Display;
65 import android.view.IRemoteAnimationFinishedCallback;
66 import android.view.IRemoteAnimationRunner;
67 import android.view.RemoteAnimationAdapter;
68 import android.view.RemoteAnimationTarget;
69 import android.view.SurfaceControl;
70 import android.view.WindowManager;
71 import android.view.animation.Animation;
72 import android.window.ITaskFragmentOrganizer;
73 import android.window.TaskFragmentOrganizer;
74 
75 import androidx.test.filters.SmallTest;
76 
77 import com.android.internal.policy.TransitionAnimation;
78 
79 import org.junit.Before;
80 import org.junit.Test;
81 import org.junit.runner.RunWith;
82 
83 /**
84  * Test class for {@link AppTransition}.
85  *
86  * Build/Install/Run:
87  *  atest WmTests:AppTransitionTests
88  */
89 @SmallTest
90 @Presubmit
91 @RunWith(WindowTestRunner.class)
92 public class AppTransitionTests extends WindowTestsBase {
93     private DisplayContent mDc;
94 
95     @Before
setUp()96     public void setUp() throws Exception {
97         doNothing().when(mWm.mRoot).performSurfacePlacement();
98         mDc = mWm.getDefaultDisplayContentLocked();
99     }
100 
101     @Test
testKeyguardOverride()102     public void testKeyguardOverride() {
103         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
104         final ActivityRecord activity = createActivityRecord(dc);
105 
106         mDc.prepareAppTransition(TRANSIT_OPEN);
107         mDc.prepareAppTransition(TRANSIT_KEYGUARD_OCCLUDE);
108         mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY);
109         mDc.mOpeningApps.add(activity);
110         assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
111                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
112                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
113                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
114                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
115     }
116 
117     @Test
testKeyguardUnoccludeOcclude()118     public void testKeyguardUnoccludeOcclude() {
119         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
120         final ActivityRecord activity = createActivityRecord(dc);
121 
122         mDc.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE);
123         mDc.prepareAppTransition(TRANSIT_KEYGUARD_OCCLUDE);
124         mDc.mOpeningApps.add(activity);
125         assertEquals(TRANSIT_NONE,
126                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
127                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
128                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
129                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
130 
131     }
132 
133     @Test
testKeyguardKeep()134     public void testKeyguardKeep() {
135         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
136         final ActivityRecord activity = createActivityRecord(dc);
137 
138         mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY);
139         mDc.prepareAppTransition(TRANSIT_OPEN);
140         mDc.mOpeningApps.add(activity);
141         assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
142                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
143                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
144                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
145                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
146     }
147 
148     @Test
testCrashing()149     public void testCrashing() {
150         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
151         final ActivityRecord activity = createActivityRecord(dc);
152 
153         mDc.prepareAppTransition(TRANSIT_OPEN);
154         mDc.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
155         mDc.mClosingApps.add(activity);
156         assertEquals(TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE,
157                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
158                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
159                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
160                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
161     }
162 
163     @Test
testKeepKeyguard_withCrashing()164     public void testKeepKeyguard_withCrashing() {
165         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
166         final ActivityRecord activity = createActivityRecord(dc);
167 
168         mDc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY);
169         mDc.prepareAppTransition(TRANSIT_CLOSE, TRANSIT_FLAG_APP_CRASHED);
170         mDc.mClosingApps.add(activity);
171         assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
172                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
173                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
174                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
175                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
176     }
177 
178     @Test
testSkipTransitionAnimation()179     public void testSkipTransitionAnimation() {
180         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
181         final ActivityRecord activity = createActivityRecord(dc);
182 
183         mDc.prepareAppTransition(TRANSIT_OPEN);
184         mDc.prepareAppTransition(TRANSIT_CLOSE);
185         mDc.mClosingApps.add(activity);
186         assertEquals(TRANSIT_OLD_UNSET,
187                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
188                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
189                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
190                         null /* oldWallpaper */, true /*skipAppTransitionAnimation*/));
191     }
192 
193     @Test
testTaskChangeWindowingMode()194     public void testTaskChangeWindowingMode() {
195         final ActivityRecord activity = createActivityRecord(mDc);
196 
197         mDc.prepareAppTransition(TRANSIT_OPEN);
198         mDc.prepareAppTransition(TRANSIT_CHANGE);
199         mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority
200         mDc.mChangingContainers.add(activity.getTask());
201 
202         assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
203                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
204                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
205                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
206                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
207     }
208 
209     @Test
testTaskFragmentChange()210     public void testTaskFragmentChange() {
211         final ActivityRecord activity = createActivityRecord(mDc);
212         final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(),
213                 true /* createdByOrganizer */, true /* isEmbedded */);
214         activity.getTask().addChild(taskFragment, POSITION_TOP);
215         activity.reparent(taskFragment, POSITION_TOP);
216 
217         mDc.prepareAppTransition(TRANSIT_OPEN);
218         mDc.prepareAppTransition(TRANSIT_CHANGE);
219         mDc.mOpeningApps.add(activity); // Make sure TRANSIT_CHANGE has the priority
220         mDc.mChangingContainers.add(taskFragment);
221 
222         assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CHANGE,
223                 AppTransitionController.getTransitCompatType(mDc.mAppTransition,
224                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
225                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
226                         null /* oldWallpaper */, false /*skipAppTransitionAnimation*/));
227     }
228 
229     @Test
testTaskFragmentOpeningTransition()230     public void testTaskFragmentOpeningTransition() {
231         final ActivityRecord activity = createHierarchyForTaskFragmentTest();
232         activity.setVisible(false);
233 
234         mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
235         mDisplayContent.mOpeningApps.add(activity);
236         assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN,
237                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
238                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
239                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
240                         null /* oldWallpaper */, false /* skipAppTransitionAnimation */));
241     }
242 
243     @Test
testTaskFragmentClosingTransition()244     public void testTaskFragmentClosingTransition() {
245         final ActivityRecord activity = createHierarchyForTaskFragmentTest();
246         activity.setVisible(true);
247 
248         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
249         mDisplayContent.mClosingApps.add(activity);
250         assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
251                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
252                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
253                         mDisplayContent.mChangingContainers, null /* wallpaperTarget */,
254                         null /* oldWallpaper */, false /* skipAppTransitionAnimation */));
255     }
256 
257     /**
258      * Creates a {@link Task} with two {@link TaskFragment TaskFragments}.
259      * The bottom TaskFragment is to prevent
260      * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) the animation
261      * target} to promote to Task or above.
262      *
263      * @return The Activity to be put in either opening or closing Activity
264      */
createHierarchyForTaskFragmentTest()265     private ActivityRecord createHierarchyForTaskFragmentTest() {
266         final Task parentTask = createTask(mDisplayContent);
267         final TaskFragment bottomTaskFragment = createTaskFragmentWithActivity(parentTask);
268         final ActivityRecord bottomActivity = bottomTaskFragment.getTopMostActivity();
269         bottomActivity.setOccludesParent(true);
270         bottomActivity.setVisible(true);
271 
272         final TaskFragment verifiedTaskFragment = createTaskFragmentWithActivity(parentTask);
273         final ActivityRecord activity = verifiedTaskFragment.getTopMostActivity();
274         activity.setOccludesParent(true);
275 
276         return activity;
277     }
278 
279     @Test
testAppTransitionStateForMultiDisplay()280     public void testAppTransitionStateForMultiDisplay() {
281         // Create 2 displays & presume both display the state is ON for ready to display & animate.
282         final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
283         final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
284 
285         // Create 2 app window tokens to represent 2 activity window.
286         final ActivityRecord activity1 = createActivityRecord(dc1);
287         final ActivityRecord activity2 = createActivityRecord(dc2);
288 
289         activity1.allDrawn = true;
290         activity1.startingMoved = true;
291 
292         // Simulate activity resume / finish flows to prepare app transition & set visibility,
293         // make sure transition is set as expected for each display.
294         dc1.prepareAppTransition(TRANSIT_OPEN);
295         dc2.prepareAppTransition(TRANSIT_CLOSE);
296         // One activity window is visible for resuming & the other activity window is invisible
297         // for finishing in different display.
298         activity1.setVisibility(true);
299         activity2.setVisibility(false);
300 
301         // Make sure each display is in animating stage.
302         assertTrue(dc1.mOpeningApps.size() > 0);
303         assertTrue(dc2.mClosingApps.size() > 0);
304         assertTrue(dc1.isAppTransitioning());
305         assertTrue(dc2.isAppTransitioning());
306     }
307 
308     @Test
testCleanAppTransitionWhenRootTaskReparent()309     public void testCleanAppTransitionWhenRootTaskReparent() {
310         // Create 2 displays & presume both display the state is ON for ready to display & animate.
311         final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
312         final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
313 
314         final Task rootTask1 = createTask(dc1);
315         final Task task1 = createTaskInRootTask(rootTask1, 0 /* userId */);
316         final ActivityRecord activity1 = createNonAttachedActivityRecord(dc1);
317         task1.addChild(activity1, 0);
318 
319         // Simulate same app is during opening / closing transition set stage.
320         dc1.mClosingApps.add(activity1);
321         assertTrue(dc1.mClosingApps.size() > 0);
322 
323         dc1.prepareAppTransition(TRANSIT_OPEN);
324         assertTrue(dc1.mAppTransition.containsTransitRequest(TRANSIT_OPEN));
325         assertTrue(dc1.mAppTransition.isTransitionSet());
326 
327         dc1.mOpeningApps.add(activity1);
328         assertTrue(dc1.mOpeningApps.size() > 0);
329 
330         // Move root task to another display.
331         rootTask1.reparent(dc2.getDefaultTaskDisplayArea(), true);
332 
333         // Verify if token are cleared from both pending transition list in former display.
334         assertFalse(dc1.mOpeningApps.contains(activity1));
335         assertFalse(dc1.mOpeningApps.contains(activity1));
336     }
337 
338     @Test
testLoadAnimationSafely()339     public void testLoadAnimationSafely() {
340         DisplayContent dc = createNewDisplay(Display.STATE_ON);
341         assertNull(dc.mAppTransition.loadAnimationSafely(
342                 getInstrumentation().getTargetContext(), -1));
343     }
344 
345     @Test
testCancelRemoteAnimationWhenFreeze()346     public void testCancelRemoteAnimationWhenFreeze() {
347         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
348         doReturn(false).when(dc).onDescendantOrientationChanged(any());
349         final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
350                 dc, "exiting app");
351         final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord;
352         // Wait until everything in animation handler get executed to prevent the exiting window
353         // from being removed during WindowSurfacePlacer Traversal.
354         waitUntilHandlersIdle();
355 
356         // Set a remote animator.
357         final TestRemoteAnimationRunner runner = new TestRemoteAnimationRunner();
358         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
359                 runner, 100, 50, true /* changeNeedsSnapshot */);
360         // RemoteAnimationController will tracking RemoteAnimationAdapter's caller with calling pid.
361         adapter.setCallingPidUid(123, 456);
362 
363         // Simulate activity finish flows to prepare app transition & set visibility,
364         // make sure transition is set as expected.
365         dc.prepareAppTransition(TRANSIT_CLOSE);
366         assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_CLOSE));
367         dc.mAppTransition.overridePendingAppTransitionRemote(adapter);
368         exitingActivity.setVisibility(false);
369         assertTrue(dc.mClosingApps.size() > 0);
370 
371         // Make sure window is in animating stage before freeze, and cancel after freeze.
372         assertTrue(dc.isAppTransitioning());
373         assertFalse(runner.mCancelled);
374         dc.mAppTransition.freeze();
375         assertFalse(dc.isAppTransitioning());
376         assertTrue(runner.mCancelled);
377     }
378 
379     @Test
testDelayWhileRecents()380     public void testDelayWhileRecents() {
381         final DisplayContent dc = createNewDisplay(Display.STATE_ON);
382         doReturn(false).when(dc).onDescendantOrientationChanged(any());
383         final Task task = createTask(dc);
384 
385         // Simulate activity1 launches activity2.
386         final ActivityRecord activity1 = createActivityRecord(task);
387         activity1.setVisible(true);
388         activity1.setVisibleRequested(false);
389         activity1.allDrawn = true;
390         final ActivityRecord activity2 = createActivityRecord(task);
391         activity2.setVisible(false);
392         activity2.setVisibleRequested(true);
393         activity2.allDrawn = true;
394 
395         dc.mClosingApps.add(activity1);
396         dc.mOpeningApps.add(activity2);
397         dc.prepareAppTransition(TRANSIT_OPEN);
398         assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN));
399 
400         // Wait until everything in animation handler get executed to prevent the exiting window
401         // from being removed during WindowSurfacePlacer Traversal.
402         waitUntilHandlersIdle();
403 
404         // Start recents
405         doReturn(true).when(task)
406                 .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
407 
408         dc.mAppTransitionController.handleAppTransitionReady();
409 
410         verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
411         verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
412     }
413 
414     @Test
testGetAnimationStyleResId()415     public void testGetAnimationStyleResId() {
416         // Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without
417         // specifying window type.
418         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
419         attrs.windowAnimations = 0x12345678;
420         assertEquals(attrs.windowAnimations, mDc.mAppTransition.getAnimationStyleResId(attrs));
421 
422         // Verify getAnimationStyleResId will return system resource Id when the window type is
423         // starting window.
424         attrs.type = TYPE_APPLICATION_STARTING;
425         assertEquals(mDc.mAppTransition.getDefaultWindowAnimationStyleResId(),
426                 mDc.mAppTransition.getAnimationStyleResId(attrs));
427     }
428 
429     @Test
testActivityRecordReparentedToTaskFragment()430     public void testActivityRecordReparentedToTaskFragment() {
431         final ActivityRecord activity = createActivityRecord(mDc);
432         final SurfaceControl activityLeash = mock(SurfaceControl.class);
433         doNothing().when(activity).setDropInputMode(anyInt());
434         activity.setVisibility(true);
435         activity.setSurfaceControl(activityLeash);
436         final Task task = activity.getTask();
437 
438         // Add a TaskFragment of half of the Task size.
439         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
440         final ITaskFragmentOrganizer iOrganizer =
441                 ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
442         mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
443         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
444                 .setParentTask(task)
445                 .setOrganizer(organizer)
446                 .build();
447         final Rect taskBounds = new Rect();
448         task.getBounds(taskBounds);
449         taskFragment.setBounds(0, 0, taskBounds.right / 2, taskBounds.bottom);
450         spyOn(taskFragment);
451         mockSurfaceFreezerSnapshot(taskFragment.mSurfaceFreezer);
452 
453         assertTrue(mDc.mChangingContainers.isEmpty());
454         assertFalse(mDc.mAppTransition.isTransitionSet());
455 
456         // Schedule app transition when reparent activity to a TaskFragment of different size.
457         final Rect startBounds = new Rect(activity.getBounds());
458         activity.reparent(taskFragment, POSITION_TOP);
459 
460         // It should transit at TaskFragment level with snapshot on the activity surface.
461         verify(taskFragment).initializeChangeTransition(activity.getBounds(), activityLeash);
462         assertTrue(mDc.mChangingContainers.contains(taskFragment));
463         assertTrue(mDc.mAppTransition.containsTransitRequest(TRANSIT_CHANGE));
464         assertEquals(startBounds, taskFragment.mSurfaceFreezer.mFreezeBounds);
465     }
466 
467     @Test
testGetNextAppTransitionBackgroundColor()468     public void testGetNextAppTransitionBackgroundColor() {
469         assumeFalse(WindowManagerService.sEnableShellTransitions);
470 
471         // No override by default.
472         assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor());
473 
474         // Override with a custom color.
475         mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0);
476         final int testColor = 123;
477         mDc.mAppTransition.overridePendingAppTransition("testPackage", 0 /* enterAnim */,
478                 0 /* exitAnim */, testColor, null /* startedCallback */, null /* endedCallback */,
479                 false /* overrideTaskTransaction */);
480 
481         assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor());
482         assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested());
483 
484         // Override with ActivityEmbedding remote animation. Background color should be kept.
485         mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class),
486                 false /* sync */, true /* isActivityEmbedding */);
487 
488         assertEquals(testColor, mDc.mAppTransition.getNextAppTransitionBackgroundColor());
489         assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested());
490 
491         // Background color should not be cleared anymore after #clear().
492         mDc.mAppTransition.clear();
493         assertEquals(0, mDc.mAppTransition.getNextAppTransitionBackgroundColor());
494         assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested());
495     }
496 
497     @Test
testGetNextAppRequestedAnimation()498     public void testGetNextAppRequestedAnimation() {
499         assumeFalse(WindowManagerService.sEnableShellTransitions);
500         final String packageName = "testPackage";
501         final int enterAnimResId = 1;
502         final int exitAnimResId = 2;
503         final int testColor = 123;
504         final Animation enterAnim = mock(Animation.class);
505         final Animation exitAnim = mock(Animation.class);
506         final TransitionAnimation transitionAnimation = mDc.mAppTransition.mTransitionAnimation;
507         spyOn(transitionAnimation);
508         doReturn(enterAnim).when(transitionAnimation)
509                 .loadAppTransitionAnimation(packageName, enterAnimResId);
510         doReturn(exitAnim).when(transitionAnimation)
511                 .loadAppTransitionAnimation(packageName, exitAnimResId);
512 
513         // No override by default.
514         assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */));
515         assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */));
516 
517         // Override with a custom animation.
518         mDc.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0);
519         mDc.mAppTransition.overridePendingAppTransition(packageName, enterAnimResId, exitAnimResId,
520                 testColor, null /* startedCallback */, null /* endedCallback */,
521                 false /* overrideTaskTransaction */);
522 
523         assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */));
524         assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */));
525         assertTrue(mDc.mAppTransition.isNextAppTransitionOverrideRequested());
526 
527         // Override with ActivityEmbedding remote animation. Custom animation should be kept.
528         mDc.mAppTransition.overridePendingAppTransitionRemote(mock(RemoteAnimationAdapter.class),
529                 false /* sync */, true /* isActivityEmbedding */);
530 
531         assertEquals(enterAnim, mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */));
532         assertEquals(exitAnim, mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */));
533         assertFalse(mDc.mAppTransition.isNextAppTransitionOverrideRequested());
534 
535         // Custom animation should not be cleared anymore after #clear().
536         mDc.mAppTransition.clear();
537         assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(true /* enter */));
538         assertNull(mDc.mAppTransition.getNextAppRequestedAnimation(false /* enter */));
539     }
540 
541     private class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
542         boolean mCancelled = false;
543         @Override
onAnimationStart(@indowManager.TransitionOldType int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback)544         public void onAnimationStart(@WindowManager.TransitionOldType int transit,
545                 RemoteAnimationTarget[] apps,
546                 RemoteAnimationTarget[] wallpapers,
547                 RemoteAnimationTarget[] nonApps,
548                 IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
549         }
550 
551         @Override
onAnimationCancelled()552         public void onAnimationCancelled() {
553             mCancelled = true;
554         }
555 
556         @Override
asBinder()557         public IBinder asBinder() {
558             return null;
559         }
560     }
561 }
562