1 /*
2  * Copyright (C) 2018 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.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
24 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
25 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
26 import static android.view.WindowManager.TRANSIT_CHANGE;
27 import static android.view.WindowManager.TRANSIT_CLOSE;
28 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
29 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
30 import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
31 import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
32 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
33 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
34 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
35 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
36 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
37 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
38 import static android.view.WindowManager.TRANSIT_OPEN;
39 import static android.view.WindowManager.TRANSIT_TO_FRONT;
40 
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
44 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
45 
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertNull;
49 import static org.junit.Assert.assertTrue;
50 import static org.junit.Assert.fail;
51 import static org.junit.Assume.assumeFalse;
52 import static org.mockito.ArgumentMatchers.any;
53 import static org.mockito.ArgumentMatchers.anyInt;
54 import static org.mockito.Mockito.clearInvocations;
55 import static org.mockito.Mockito.mock;
56 import static org.mockito.Mockito.never;
57 import static org.mockito.Mockito.verify;
58 
59 import android.annotation.Nullable;
60 import android.graphics.Rect;
61 import android.gui.DropInputMode;
62 import android.os.Binder;
63 import android.os.IBinder;
64 import android.os.RemoteException;
65 import android.platform.test.annotations.Presubmit;
66 import android.util.ArraySet;
67 import android.view.IRemoteAnimationFinishedCallback;
68 import android.view.IRemoteAnimationRunner;
69 import android.view.RemoteAnimationAdapter;
70 import android.view.RemoteAnimationDefinition;
71 import android.view.RemoteAnimationTarget;
72 import android.view.WindowManager;
73 import android.window.ITaskFragmentOrganizer;
74 import android.window.TaskFragmentOrganizer;
75 
76 import androidx.test.filters.SmallTest;
77 
78 import org.junit.Before;
79 import org.junit.Test;
80 import org.junit.runner.RunWith;
81 
82 /**
83  * Build/Install/Run:
84  *  atest WmTests:AppTransitionControllerTest
85  */
86 @SmallTest
87 @Presubmit
88 @RunWith(WindowTestRunner.class)
89 public class AppTransitionControllerTest extends WindowTestsBase {
90 
91     private AppTransitionController mAppTransitionController;
92 
93     @Before
setUp()94     public void setUp() throws Exception {
95         assumeFalse(WindowManagerService.sEnableShellTransitions);
96         mAppTransitionController = new AppTransitionController(mWm, mDisplayContent);
97     }
98 
99     @Test
testSkipOccludedActivityCloseTransition()100     public void testSkipOccludedActivityCloseTransition() {
101         final ActivityRecord behind = createActivityRecord(mDisplayContent,
102                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
103         final ActivityRecord topOpening = createActivityRecord(behind.getTask());
104         topOpening.setOccludesParent(true);
105         topOpening.setVisible(true);
106 
107         mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
108         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
109         mDisplayContent.mClosingApps.add(behind);
110 
111         assertEquals(WindowManager.TRANSIT_OLD_UNSET,
112                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
113                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
114                         mDisplayContent.mChangingContainers, null, null, false));
115     }
116 
117     @Test
testClearTaskSkipAppExecuteTransition()118     public void testClearTaskSkipAppExecuteTransition() {
119         final ActivityRecord behind = createActivityRecord(mDisplayContent,
120                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
121         final Task task = behind.getTask();
122         final ActivityRecord top = createActivityRecord(task);
123         top.setState(ActivityRecord.State.RESUMED, "test");
124         behind.setState(ActivityRecord.State.STARTED, "test");
125         behind.setVisibleRequested(true);
126 
127         task.removeActivities("test", false /* excludingTaskOverlay */);
128         assertFalse(mDisplayContent.mAppTransition.isReady());
129     }
130 
131     @Test
testTranslucentOpen()132     public void testTranslucentOpen() {
133         final ActivityRecord behind = createActivityRecord(mDisplayContent,
134                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
135         final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
136                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
137         doReturn(false).when(translucentOpening).fillsParent();
138         translucentOpening.setVisible(false);
139         mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
140         mDisplayContent.mOpeningApps.add(behind);
141         mDisplayContent.mOpeningApps.add(translucentOpening);
142 
143         assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN,
144                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
145                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
146                         mDisplayContent.mChangingContainers, null, null, false));
147     }
148 
149     @Test
testTranslucentClose()150     public void testTranslucentClose() {
151         final ActivityRecord behind = createActivityRecord(mDisplayContent,
152                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
153         final ActivityRecord translucentClosing = createActivityRecord(mDisplayContent,
154                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
155         doReturn(false).when(translucentClosing).fillsParent();
156         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
157         mDisplayContent.mClosingApps.add(translucentClosing);
158         assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE,
159                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
160                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
161                         mDisplayContent.mChangingContainers, null, null, false));
162     }
163 
164     @Test
testDreamActivityOpenTransition()165     public void testDreamActivityOpenTransition() {
166         final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent,
167                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM);
168         mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
169         mDisplayContent.mOpeningApps.add(dreamActivity);
170 
171         assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_OPEN,
172                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
173                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
174                         mDisplayContent.mChangingContainers, null, null, false));
175     }
176 
177     @Test
testDreamActivityCloseTransition()178     public void testDreamActivityCloseTransition() {
179         final ActivityRecord dreamActivity = createActivityRecord(mDisplayContent,
180                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM);
181         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
182         mDisplayContent.mClosingApps.add(dreamActivity);
183 
184         assertEquals(TRANSIT_OLD_DREAM_ACTIVITY_CLOSE,
185                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
186                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
187                         mDisplayContent.mChangingContainers, null, null, false));
188     }
189 
190     @Test
testChangeIsNotOverwritten()191     public void testChangeIsNotOverwritten() {
192         final ActivityRecord behind = createActivityRecord(mDisplayContent,
193                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
194         final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent,
195                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
196         translucentOpening.setOccludesParent(false);
197         translucentOpening.setVisible(false);
198         mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
199         mDisplayContent.mOpeningApps.add(behind);
200         mDisplayContent.mOpeningApps.add(translucentOpening);
201         mDisplayContent.mChangingContainers.add(translucentOpening.getTask());
202         assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
203                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
204                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
205                         mDisplayContent.mChangingContainers, null, null, false));
206     }
207 
208     @Test
testTransitWithinTask()209     public void testTransitWithinTask() {
210         final ActivityRecord opening = createActivityRecord(mDisplayContent,
211                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
212         opening.setOccludesParent(false);
213         final ActivityRecord closing = createActivityRecord(mDisplayContent,
214                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
215         closing.setOccludesParent(false);
216         final Task task = opening.getTask();
217         mDisplayContent.mOpeningApps.add(opening);
218         mDisplayContent.mClosingApps.add(closing);
219         assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_ACTIVITY_OPEN, task));
220         closing.getTask().removeChild(closing);
221         task.addChild(closing, 0);
222         assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_ACTIVITY_OPEN, task));
223         assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_OLD_TASK_OPEN, task));
224     }
225 
226 
227     @Test
testIntraWallpaper_open()228     public void testIntraWallpaper_open() {
229         final ActivityRecord opening = createActivityRecord(mDisplayContent,
230                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
231         opening.setVisible(false);
232         final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams(
233                 TYPE_BASE_APPLICATION);
234         attrOpening.setTitle("WallpaperOpening");
235         attrOpening.flags |= FLAG_SHOW_WALLPAPER;
236         final TestWindowState appWindowOpening = createWindowState(attrOpening, opening);
237         opening.addWindow(appWindowOpening);
238 
239         final ActivityRecord closing = createActivityRecord(mDisplayContent,
240                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
241         final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams(
242                 TYPE_BASE_APPLICATION);
243         attrOpening.setTitle("WallpaperClosing");
244         attrClosing.flags |= FLAG_SHOW_WALLPAPER;
245         final TestWindowState appWindowClosing = createWindowState(attrClosing, closing);
246         closing.addWindow(appWindowClosing);
247 
248         mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
249         mDisplayContent.mOpeningApps.add(opening);
250         mDisplayContent.mClosingApps.add(closing);
251 
252         assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN,
253                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
254                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
255                         mDisplayContent.mChangingContainers, appWindowClosing, null, false));
256     }
257 
258     @Test
testIntraWallpaper_toFront()259     public void testIntraWallpaper_toFront() {
260         final ActivityRecord opening = createActivityRecord(mDisplayContent,
261                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
262         opening.setVisible(false);
263         final WindowManager.LayoutParams attrOpening = new WindowManager.LayoutParams(
264                 TYPE_BASE_APPLICATION);
265         attrOpening.setTitle("WallpaperOpening");
266         attrOpening.flags |= FLAG_SHOW_WALLPAPER;
267         final TestWindowState appWindowOpening = createWindowState(attrOpening, opening);
268         opening.addWindow(appWindowOpening);
269 
270         final ActivityRecord closing = createActivityRecord(mDisplayContent,
271                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
272         final WindowManager.LayoutParams attrClosing = new WindowManager.LayoutParams(
273                 TYPE_BASE_APPLICATION);
274         attrOpening.setTitle("WallpaperClosing");
275         attrClosing.flags |= FLAG_SHOW_WALLPAPER;
276         final TestWindowState appWindowClosing = createWindowState(attrClosing, closing);
277         closing.addWindow(appWindowClosing);
278 
279         mDisplayContent.prepareAppTransition(TRANSIT_TO_FRONT);
280         mDisplayContent.mOpeningApps.add(opening);
281         mDisplayContent.mClosingApps.add(closing);
282 
283         assertEquals(WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN,
284                 AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
285                         mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
286                         mDisplayContent.mChangingContainers, appWindowClosing, null, false));
287     }
288 
289     @Test
testGetAnimationTargets_visibilityAlreadyUpdated()290     public void testGetAnimationTargets_visibilityAlreadyUpdated() {
291         // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, visible)
292         //                   +- [Task2] - [ActivityRecord2] (closing, invisible)
293         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
294 
295         final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
296         activity2.setVisible(false);
297         activity2.setVisibleRequested(false);
298 
299         final ArraySet<ActivityRecord> opening = new ArraySet<>();
300         opening.add(activity1);
301         final ArraySet<ActivityRecord> closing = new ArraySet<>();
302         closing.add(activity2);
303 
304         // No animation, since visibility of the opening and closing apps are already updated
305         // outside of AppTransition framework.
306         assertEquals(
307                 new ArraySet<>(),
308                 AppTransitionController.getAnimationTargets(
309                         opening, closing, true /* visible */));
310         assertEquals(
311                 new ArraySet<>(),
312                 AppTransitionController.getAnimationTargets(
313                         opening, closing, false /* visible */));
314     }
315 
316     @Test
testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested()317     public void testGetAnimationTargets_visibilityAlreadyUpdated_butForcedTransitionRequested() {
318         // [DisplayContent] -+- [Task1] - [ActivityRecord1] (closing, invisible)
319         //                   +- [Task2] - [ActivityRecord2] (opening, visible)
320         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
321         activity1.setVisible(true);
322         activity1.setVisibleRequested(true);
323         activity1.mRequestForceTransition = true;
324 
325         final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
326         activity2.setVisible(false);
327         activity2.setVisibleRequested(false);
328         activity2.mRequestForceTransition = true;
329 
330         final ArraySet<ActivityRecord> opening = new ArraySet<>();
331         opening.add(activity1);
332         final ArraySet<ActivityRecord> closing = new ArraySet<>();
333         closing.add(activity2);
334 
335         // The visibility are already updated, but since forced transition is requested, it will
336         // be included.
337         assertEquals(
338                 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
339                 AppTransitionController.getAnimationTargets(
340                         opening, closing, true /* visible */));
341         assertEquals(
342                 new ArraySet<>(new WindowContainer[]{activity2.getRootTask()}),
343                 AppTransitionController.getAnimationTargets(
344                         opening, closing, false /* visible */));
345     }
346 
347     @Test
testGetAnimationTargets_exitingBeforeTransition()348     public void testGetAnimationTargets_exitingBeforeTransition() {
349         // Create another non-empty task so the animation target won't promote to task display area.
350         createActivityRecord(mDisplayContent);
351         final ActivityRecord activity = createActivityRecord(mDisplayContent);
352         activity.setVisible(false);
353         activity.mIsExiting = true;
354 
355         final ArraySet<ActivityRecord> closing = new ArraySet<>();
356         closing.add(activity);
357 
358         // Animate closing apps even if it's not visible when it is exiting before we had a chance
359         // to play the transition animation.
360         assertEquals(
361                 new ArraySet<>(new WindowContainer[]{activity.getRootTask()}),
362                 AppTransitionController.getAnimationTargets(
363                         new ArraySet<>(), closing, false /* visible */));
364     }
365 
366     @Test
testExitAnimationDone_beforeAppTransition()367     public void testExitAnimationDone_beforeAppTransition() {
368         final Task task = createTask(mDisplayContent);
369         final WindowState win = createAppWindow(task, ACTIVITY_TYPE_STANDARD, "Win");
370         spyOn(win);
371         win.mAnimatingExit = true;
372         mDisplayContent.mAppTransition.setTimeout();
373         mDisplayContent.mAppTransitionController.handleAppTransitionReady();
374 
375         verify(win).onExitAnimationDone();
376     }
377 
378     @Test
testGetAnimationTargets_openingClosingInDifferentTask()379     public void testGetAnimationTargets_openingClosingInDifferentTask() {
380         // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
381         //                   |           +- [ActivityRecord2] (invisible)
382         //                   |
383         //                   +- [Task2] -+- [ActivityRecord3] (closing, visible)
384         //                               +- [ActivityRecord4] (invisible)
385         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
386         activity1.setVisible(false);
387         activity1.setVisibleRequested(true);
388         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
389                 activity1.getTask());
390         activity2.setVisible(false);
391         activity2.setVisibleRequested(false);
392 
393         final ActivityRecord activity3 = createActivityRecord(mDisplayContent);
394         final ActivityRecord activity4 = createActivityRecord(mDisplayContent,
395                 activity3.getTask());
396         activity4.setVisible(false);
397         activity4.setVisibleRequested(false);
398 
399         final ArraySet<ActivityRecord> opening = new ArraySet<>();
400         opening.add(activity1);
401         final ArraySet<ActivityRecord> closing = new ArraySet<>();
402         closing.add(activity3);
403 
404         // Promote animation targets to root Task level. Invisible ActivityRecords don't affect
405         // promotion decision.
406         assertEquals(
407                 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
408                 AppTransitionController.getAnimationTargets(
409                         opening, closing, true /* visible */));
410         assertEquals(
411                 new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}),
412                 AppTransitionController.getAnimationTargets(
413                         opening, closing, false /* visible */));
414     }
415 
416     @Test
testGetAnimationTargets_openingClosingInSameTask()417     public void testGetAnimationTargets_openingClosingInSameTask() {
418         // [DisplayContent] - [Task] -+- [ActivityRecord1] (opening, invisible)
419         //                            +- [ActivityRecord2] (closing, visible)
420         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
421         activity1.setVisible(false);
422         activity1.setVisibleRequested(true);
423         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
424                 activity1.getTask());
425 
426         final ArraySet<ActivityRecord> opening = new ArraySet<>();
427         opening.add(activity1);
428         final ArraySet<ActivityRecord> closing = new ArraySet<>();
429         closing.add(activity2);
430 
431         // Don't promote an animation target to Task level, since the same task contains both
432         // opening and closing app.
433         assertEquals(
434                 new ArraySet<>(new WindowContainer[]{activity1}),
435                 AppTransitionController.getAnimationTargets(
436                         opening, closing, true /* visible */));
437         assertEquals(
438                 new ArraySet<>(new WindowContainer[]{activity2}),
439                 AppTransitionController.getAnimationTargets(
440                         opening, closing, false /* visible */));
441     }
442 
443     @Test
testGetAnimationTargets_animateOnlyTranslucentApp()444     public void testGetAnimationTargets_animateOnlyTranslucentApp() {
445         // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
446         //                   |           +- [ActivityRecord2] (visible)
447         //                   |
448         //                   +- [Task2] -+- [ActivityRecord3] (closing, visible)
449         //                               +- [ActivityRecord4] (visible)
450 
451         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
452         activity1.setVisible(false);
453         activity1.setVisibleRequested(true);
454         activity1.setOccludesParent(false);
455 
456         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
457                 activity1.getTask());
458 
459         final ActivityRecord activity3 = createActivityRecord(mDisplayContent);
460         activity3.setOccludesParent(false);
461         final ActivityRecord activity4 = createActivityRecord(mDisplayContent,
462                 activity3.getTask());
463 
464         final ArraySet<ActivityRecord> opening = new ArraySet<>();
465         opening.add(activity1);
466         final ArraySet<ActivityRecord> closing = new ArraySet<>();
467         closing.add(activity3);
468 
469         // Don't promote an animation target to Task level, since opening (closing) app is
470         // translucent and is displayed over other non-animating app.
471         assertEquals(
472                 new ArraySet<>(new WindowContainer[]{activity1}),
473                 AppTransitionController.getAnimationTargets(
474                         opening, closing, true /* visible */));
475         assertEquals(
476                 new ArraySet<>(new WindowContainer[]{activity3}),
477                 AppTransitionController.getAnimationTargets(
478                         opening, closing, false /* visible */));
479     }
480 
481     @Test
testGetAnimationTargets_animateTranslucentAndOpaqueApps()482     public void testGetAnimationTargets_animateTranslucentAndOpaqueApps() {
483         // [DisplayContent] -+- [Task1] -+- [ActivityRecord1] (opening, invisible)
484         //                   |           +- [ActivityRecord2] (opening, invisible)
485         //                   |
486         //                   +- [Task2] -+- [ActivityRecord3] (closing, visible)
487         //                               +- [ActivityRecord4] (closing, visible)
488 
489         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
490         activity1.setVisible(false);
491         activity1.setVisibleRequested(true);
492         activity1.setOccludesParent(false);
493 
494         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
495                 activity1.getTask());
496         activity2.setVisible(false);
497         activity2.setVisibleRequested(true);
498 
499         final ActivityRecord activity3 = createActivityRecord(mDisplayContent);
500         activity3.setOccludesParent(false);
501         final ActivityRecord activity4 = createActivityRecord(mDisplayContent,
502                 activity3.getTask());
503 
504         final ArraySet<ActivityRecord> opening = new ArraySet<>();
505         opening.add(activity1);
506         opening.add(activity2);
507         final ArraySet<ActivityRecord> closing = new ArraySet<>();
508         closing.add(activity3);
509         closing.add(activity4);
510 
511         // Promote animation targets to TaskStack level even though opening (closing) app is
512         // translucent as long as all visible siblings animate at the same time.
513         assertEquals(
514                 new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
515                 AppTransitionController.getAnimationTargets(
516                         opening, closing, true /* visible */));
517         assertEquals(
518                 new ArraySet<>(new WindowContainer[]{activity3.getRootTask()}),
519                 AppTransitionController.getAnimationTargets(
520                         opening, closing, false /* visible */));
521     }
522 
523     @Test
testGetAnimationTargets_taskContainsMultipleTasks()524     public void testGetAnimationTargets_taskContainsMultipleTasks() {
525         // [DisplayContent] - [Task] -+- [Task1] - [ActivityRecord1] (opening, invisible)
526         //                            +- [Task2] - [ActivityRecord2] (closing, visible)
527         final Task parentTask = createTask(mDisplayContent);
528         final ActivityRecord activity1 = createActivityRecordWithParentTask(parentTask);
529         activity1.setVisible(false);
530         activity1.setVisibleRequested(true);
531         final ActivityRecord activity2 = createActivityRecordWithParentTask(parentTask);
532 
533         final ArraySet<ActivityRecord> opening = new ArraySet<>();
534         opening.add(activity1);
535         final ArraySet<ActivityRecord> closing = new ArraySet<>();
536         closing.add(activity2);
537 
538         // Promote animation targets up to Task level, not beyond.
539         assertEquals(
540                 new ArraySet<>(new WindowContainer[]{activity1.getTask()}),
541                 AppTransitionController.getAnimationTargets(
542                         opening, closing, true /* visible */));
543         assertEquals(
544                 new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
545                 AppTransitionController.getAnimationTargets(
546                         opening, closing, false /* visible */));
547     }
548 
549     @Test
testGetAnimationTargets_splitScreenOpening()550     public void testGetAnimationTargets_splitScreenOpening() {
551         // [DisplayContent] - [Task] -+- [split task 1] -+- [Task1] - [AR1] (opening, invisible)
552         //                            +- [split task 2] -+- [Task2] - [AR2] (opening, invisible)
553         final Task singleTopRoot = createTask(mDisplayContent);
554         final TaskBuilder builder = new TaskBuilder(mSupervisor)
555                 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
556                 .setParentTask(singleTopRoot)
557                 .setCreatedByOrganizer(true);
558         final Task splitRoot1 = builder.build();
559         final Task splitRoot2 = builder.build();
560         splitRoot1.setAdjacentTaskFragment(splitRoot2);
561         final ActivityRecord activity1 = createActivityRecordWithParentTask(splitRoot1);
562         activity1.setVisible(false);
563         activity1.setVisibleRequested(true);
564         final ActivityRecord activity2 = createActivityRecordWithParentTask(splitRoot2);
565         activity2.setVisible(false);
566         activity2.setVisibleRequested(true);
567 
568         final ArraySet<ActivityRecord> opening = new ArraySet<>();
569         opening.add(activity1);
570         opening.add(activity2);
571         final ArraySet<ActivityRecord> closing = new ArraySet<>();
572 
573         // Promote animation targets up to Task level, not beyond.
574         assertEquals(
575                 new ArraySet<>(new WindowContainer[]{splitRoot1, splitRoot2}),
576                 AppTransitionController.getAnimationTargets(
577                         opening, closing, true /* visible */));
578     }
579 
580     @Test
testGetAnimationTargets_openingClosingTaskFragment()581     public void testGetAnimationTargets_openingClosingTaskFragment() {
582         // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible)
583         //                        +- [TaskFragment2] - [ActivityRecord2] (closing, visible)
584         final Task parentTask = createTask(mDisplayContent);
585         final TaskFragment taskFragment1 = createTaskFragmentWithActivity(parentTask);
586         final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
587         activity1.setVisible(false);
588         activity1.setVisibleRequested(true);
589 
590         final TaskFragment taskFragment2 = createTaskFragmentWithActivity(parentTask);
591         final ActivityRecord activity2 = taskFragment2.getTopMostActivity();
592         activity2.setVisible(true);
593         activity2.setVisibleRequested(false);
594 
595         final ArraySet<ActivityRecord> opening = new ArraySet<>();
596         opening.add(activity1);
597         final ArraySet<ActivityRecord> closing = new ArraySet<>();
598         closing.add(activity2);
599 
600         // Promote animation targets up to TaskFragment level, not beyond.
601         assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}),
602                 AppTransitionController.getAnimationTargets(
603                         opening, closing, true /* visible */));
604         assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}),
605                 AppTransitionController.getAnimationTargets(
606                         opening, closing, false /* visible */));
607     }
608 
609     @Test
testGetAnimationTargets_openingTheOnlyTaskFragmentInTask()610     public void testGetAnimationTargets_openingTheOnlyTaskFragmentInTask() {
611         // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (opening, invisible)
612         //               +- [Task2] - [ActivityRecord2] (closing, visible)
613         final Task task1 = createTask(mDisplayContent);
614         final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task1);
615         final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
616         activity1.setVisible(false);
617         activity1.setVisibleRequested(true);
618 
619         final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
620         activity2.setVisible(true);
621         activity2.setVisibleRequested(false);
622 
623         final ArraySet<ActivityRecord> opening = new ArraySet<>();
624         opening.add(activity1);
625         final ArraySet<ActivityRecord> closing = new ArraySet<>();
626         closing.add(activity2);
627 
628         // Promote animation targets up to leaf Task level because there's only one TaskFragment in
629         // the Task.
630         assertEquals(new ArraySet<>(new WindowContainer[]{task1}),
631                 AppTransitionController.getAnimationTargets(
632                         opening, closing, true /* visible */));
633         assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
634                 AppTransitionController.getAnimationTargets(
635                         opening, closing, false /* visible */));
636     }
637 
638     @Test
testGetAnimationTargets_closingTheOnlyTaskFragmentInTask()639     public void testGetAnimationTargets_closingTheOnlyTaskFragmentInTask() {
640         // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (closing, visible)
641         //               +- [Task2] - [ActivityRecord2] (opening, invisible)
642         final Task task1 = createTask(mDisplayContent);
643         final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task1);
644         final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
645         activity1.setVisible(true);
646         activity1.setVisibleRequested(false);
647 
648         final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
649         activity2.setVisible(false);
650         activity2.setVisibleRequested(true);
651 
652         final ArraySet<ActivityRecord> opening = new ArraySet<>();
653         opening.add(activity2);
654         final ArraySet<ActivityRecord> closing = new ArraySet<>();
655         closing.add(activity1);
656 
657         // Promote animation targets up to leaf Task level because there's only one TaskFragment in
658         // the Task.
659         assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
660                 AppTransitionController.getAnimationTargets(
661                         opening, closing, true /* visible */));
662         assertEquals(new ArraySet<>(new WindowContainer[]{task1}),
663                 AppTransitionController.getAnimationTargets(
664                         opening, closing, false /* visible */));
665     }
666 
667     @Test
testGetAnimationTargets_embeddedTask()668     public void testGetAnimationTargets_embeddedTask() {
669         // [DisplayContent] -+- [Task1] -            [ActivityRecord1] (opening, invisible)
670         //                   +- [Task2] (embedded) - [ActivityRecord2] (opening, invisible)
671         final ActivityRecord activity1 = createActivityRecord(mDisplayContent);
672         activity1.setVisible(false);
673         activity1.setVisibleRequested(true);
674 
675         final Task task2 = createTask(mDisplayContent);
676         task2.mRemoveWithTaskOrganizer = true;
677         final ActivityRecord activity2 = createActivityRecord(task2);
678         activity2.setVisible(false);
679         activity2.setVisibleRequested(true);
680 
681         final ArraySet<ActivityRecord> opening = new ArraySet<>();
682         opening.add(activity1);
683         opening.add(activity2);
684         final ArraySet<ActivityRecord> closing = new ArraySet<>();
685 
686         // No animation on the embedded task.
687         assertEquals(
688                 new ArraySet<>(new WindowContainer[]{activity1.getTask()}),
689                 AppTransitionController.getAnimationTargets(
690                         opening, closing, true /* visible */));
691         assertEquals(
692                 new ArraySet<>(),
693                 AppTransitionController.getAnimationTargets(
694                         opening, closing, false /* visible */));
695     }
696 
697 
698     @Test
testGetAnimationTargets_activityInEmbeddedTask()699     public void testGetAnimationTargets_activityInEmbeddedTask() {
700         // [DisplayContent] - [Task] (embedded)-+- [ActivityRecord1] (opening, invisible)
701         //                                      +- [ActivityRecord2] (closing, visible)
702         final Task task = createTask(mDisplayContent);
703         task.mRemoveWithTaskOrganizer = true;
704 
705         final ActivityRecord activity1 = createActivityRecord(task);
706         activity1.setVisible(false);
707         activity1.setVisibleRequested(true);
708         final ActivityRecord activity2 = createActivityRecord(task);
709 
710         final ArraySet<ActivityRecord> opening = new ArraySet<>();
711         opening.add(activity1);
712         final ArraySet<ActivityRecord> closing = new ArraySet<>();
713         closing.add(activity2);
714 
715         // Even though embedded task itself doesn't animate, activities in an embedded task
716         // animate.
717         assertEquals(
718                 new ArraySet<>(new WindowContainer[]{activity1}),
719                 AppTransitionController.getAnimationTargets(
720                         opening, closing, true /* visible */));
721         assertEquals(
722                 new ArraySet<>(new WindowContainer[]{activity2}),
723                 AppTransitionController.getAnimationTargets(
724                         opening, closing, false /* visible */));
725     }
726 
727     static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
728         private IRemoteAnimationFinishedCallback mFinishedCallback;
729 
730         @Override
onAnimationStart(int transit, RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback)731         public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
732                 RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
733                 IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
734             mFinishedCallback = finishedCallback;
735         }
736 
737         @Override
onAnimationCancelled()738         public void onAnimationCancelled() throws RemoteException {
739             mFinishedCallback = null;
740         }
741 
742         @Override
asBinder()743         public IBinder asBinder() {
744             return new Binder();
745         }
746 
isAnimationStarted()747         boolean isAnimationStarted() {
748             return mFinishedCallback != null;
749         }
750 
finishAnimation()751         void finishAnimation() {
752             try {
753                 mFinishedCallback.onAnimationFinished();
754             } catch (RemoteException e) {
755                 fail();
756             }
757         }
758     }
759 
760     @Test
testGetRemoteAnimationOverrideEmpty()761     public void testGetRemoteAnimationOverrideEmpty() {
762         final ActivityRecord activity = createActivityRecord(mDisplayContent);
763         assertNull(mAppTransitionController.getRemoteAnimationOverride(activity,
764                 TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
765     }
766 
767     @Test
testGetRemoteAnimationOverrideWindowContainer()768     public void testGetRemoteAnimationOverrideWindowContainer() {
769         final ActivityRecord activity = createActivityRecord(mDisplayContent);
770         final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
771         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
772                 new TestRemoteAnimationRunner(), 10, 1);
773         definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
774         activity.registerRemoteAnimations(definition);
775 
776         assertEquals(adapter,
777                 mAppTransitionController.getRemoteAnimationOverride(
778                         activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
779         assertNull(mAppTransitionController.getRemoteAnimationOverride(
780                         null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
781     }
782 
783     @Test
testGetRemoteAnimationOverrideTransitionController()784     public void testGetRemoteAnimationOverrideTransitionController() {
785         final ActivityRecord activity = createActivityRecord(mDisplayContent);
786         final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
787         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
788                 new TestRemoteAnimationRunner(), 10, 1);
789         definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
790         mAppTransitionController.registerRemoteAnimations(definition);
791 
792         assertEquals(adapter,
793                 mAppTransitionController.getRemoteAnimationOverride(
794                         activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
795         assertEquals(adapter,
796                 mAppTransitionController.getRemoteAnimationOverride(
797                         null, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
798     }
799 
800     @Test
testGetRemoteAnimationOverrideBoth()801     public void testGetRemoteAnimationOverrideBoth() {
802         final ActivityRecord activity = createActivityRecord(mDisplayContent);
803         final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition();
804         final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter(
805                 new TestRemoteAnimationRunner(), 10, 1);
806         definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1);
807         activity.registerRemoteAnimations(definition1);
808 
809         final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition();
810         final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter(
811                 new TestRemoteAnimationRunner(), 10, 1);
812         definition2.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE, adapter2);
813         mAppTransitionController.registerRemoteAnimations(definition2);
814 
815         assertEquals(adapter2,
816                 mAppTransitionController.getRemoteAnimationOverride(
817                         activity, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>()));
818         assertEquals(adapter2,
819                 mAppTransitionController.getRemoteAnimationOverride(
820                         null, TRANSIT_OLD_KEYGUARD_UNOCCLUDE, new ArraySet<Integer>()));
821     }
822 
823     @Test
testGetRemoteAnimationOverrideWindowContainerHasPriority()824     public void testGetRemoteAnimationOverrideWindowContainerHasPriority() {
825         final ActivityRecord activity = createActivityRecord(mDisplayContent);
826         final RemoteAnimationDefinition definition1 = new RemoteAnimationDefinition();
827         final RemoteAnimationAdapter adapter1 = new RemoteAnimationAdapter(
828                 new TestRemoteAnimationRunner(), 10, 1);
829         definition1.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter1);
830         activity.registerRemoteAnimations(definition1);
831 
832         final RemoteAnimationDefinition definition2 = new RemoteAnimationDefinition();
833         final RemoteAnimationAdapter adapter2 = new RemoteAnimationAdapter(
834                 new TestRemoteAnimationRunner(), 10, 1);
835         definition2.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter2);
836         mAppTransitionController.registerRemoteAnimations(definition2);
837 
838         assertEquals(adapter1,
839                 mAppTransitionController.getRemoteAnimationOverride(
840                         activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
841     }
842 
843     @Test
testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity()844     public void testOverrideTaskFragmentAdapter_overrideWithEmbeddedActivity() {
845         final Task task = createTask(mDisplayContent);
846         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
847         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
848         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
849 
850         // Create a TaskFragment with embedded activity.
851         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
852         final ActivityRecord activity = taskFragment.getTopMostActivity();
853         prepareActivityForAppTransition(activity);
854         spyOn(mDisplayContent.mAppTransition);
855 
856         // Prepare and start transition.
857         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
858         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
859 
860         // Animation run by the remote handler.
861         assertTrue(remoteAnimationRunner.isAnimationStarted());
862     }
863 
864     @Test
testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask()865     public void testOverrideTaskFragmentAdapter_noOverrideWithOnlyTaskFragmentFillingTask() {
866         final Task task = createTask(mDisplayContent);
867         final ActivityRecord closingActivity = createActivityRecord(task);
868         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
869         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
870         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
871 
872         // Create a TaskFragment with embedded activity.
873         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
874 
875         // Make sure the TaskFragment is not embedded.
876         assertFalse(taskFragment.isEmbeddedWithBoundsOverride());
877         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
878         prepareActivityForAppTransition(closingActivity);
879         prepareActivityForAppTransition(openingActivity);
880         final int uid = 12345;
881         closingActivity.info.applicationInfo.uid = uid;
882         openingActivity.info.applicationInfo.uid = uid;
883         task.effectiveUid = uid;
884         spyOn(mDisplayContent.mAppTransition);
885 
886         // Prepare and start transition.
887         prepareAndTriggerAppTransition(openingActivity, closingActivity,
888                 null /* changingTaskFragment */);
889         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
890 
891         // Animation is not run by the remote handler because the activity is filling the Task.
892         assertFalse(remoteAnimationRunner.isAnimationStarted());
893     }
894 
895     @Test
testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask()896     public void testOverrideTaskFragmentAdapter_overrideWithTaskFragmentNotFillingTask() {
897         final Task task = createTask(mDisplayContent);
898         final ActivityRecord closingActivity = createActivityRecord(task);
899         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
900         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
901         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
902 
903         // Create a TaskFragment with embedded activity.
904         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
905 
906         // Make sure the TaskFragment is embedded.
907         taskFragment.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
908         final Rect embeddedBounds = new Rect(task.getBounds());
909         embeddedBounds.right = embeddedBounds.left + embeddedBounds.width() / 2;
910         taskFragment.setBounds(embeddedBounds);
911         assertTrue(taskFragment.isEmbeddedWithBoundsOverride());
912         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
913         prepareActivityForAppTransition(closingActivity);
914         prepareActivityForAppTransition(openingActivity);
915         final int uid = 12345;
916         closingActivity.info.applicationInfo.uid = uid;
917         openingActivity.info.applicationInfo.uid = uid;
918         task.effectiveUid = uid;
919         spyOn(mDisplayContent.mAppTransition);
920 
921         // Prepare and start transition.
922         prepareAndTriggerAppTransition(openingActivity, closingActivity,
923                 null /* changingTaskFragment */);
924         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
925 
926         // Animation run by the remote handler.
927         assertTrue(remoteAnimationRunner.isAnimationStarted());
928     }
929 
930     @Test
testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity()931     public void testOverrideTaskFragmentAdapter_overrideWithNonEmbeddedActivity() {
932         final Task task = createTask(mDisplayContent);
933         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
934         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
935         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
936 
937         // Closing non-embedded activity.
938         final ActivityRecord closingActivity = createActivityRecord(task);
939         prepareActivityForAppTransition(closingActivity);
940         // Opening TaskFragment with embedded activity.
941         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
942         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
943         prepareActivityForAppTransition(openingActivity);
944         task.effectiveUid = openingActivity.getUid();
945         spyOn(mDisplayContent.mAppTransition);
946 
947         // Prepare and start transition.
948         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
949         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
950 
951         // Animation run by the remote handler.
952         assertTrue(remoteAnimationRunner.isAnimationStarted());
953     }
954 
955     @Test
testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid()956     public void testOverrideTaskFragmentAdapter_overrideEmbeddedActivityWithDiffUid() {
957         final Task task = createTask(mDisplayContent);
958         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
959         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
960         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
961 
962         // Closing TaskFragment with embedded activity.
963         final TaskFragment taskFragment1 = createTaskFragmentWithEmbeddedActivity(task, organizer);
964         final ActivityRecord closingActivity = taskFragment1.getTopMostActivity();
965         prepareActivityForAppTransition(closingActivity);
966         closingActivity.info.applicationInfo.uid = 12345;
967         // Opening TaskFragment with embedded activity with different UID.
968         final TaskFragment taskFragment2 = createTaskFragmentWithEmbeddedActivity(task, organizer);
969         final ActivityRecord openingActivity = taskFragment2.getTopMostActivity();
970         prepareActivityForAppTransition(openingActivity);
971         openingActivity.info.applicationInfo.uid = 54321;
972         spyOn(mDisplayContent.mAppTransition);
973 
974         // Prepare and start transition.
975         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment1);
976         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
977 
978         // Animation run by the remote handler.
979         assertTrue(remoteAnimationRunner.isAnimationStarted());
980     }
981 
982     @Test
testOverrideTaskFragmentAdapter_noOverrideWithTwoApps()983     public void testOverrideTaskFragmentAdapter_noOverrideWithTwoApps() {
984         final Task task = createTask(mDisplayContent);
985         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
986         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
987         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
988 
989         // Closing activity in Task1.
990         final ActivityRecord closingActivity = createActivityRecord(mDisplayContent);
991         prepareActivityForAppTransition(closingActivity);
992         // Opening TaskFragment with embedded activity in Task2.
993         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
994         final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
995         prepareActivityForAppTransition(openingActivity);
996         spyOn(mDisplayContent.mAppTransition);
997 
998         // Prepare and start transition.
999         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
1000         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
1001 
1002         // Animation not run by the remote handler.
1003         assertFalse(remoteAnimationRunner.isAnimationStarted());
1004     }
1005 
1006     @Test
testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid()1007     public void testOverrideTaskFragmentAdapter_noOverrideNonEmbeddedActivityWithDiffUid() {
1008         final Task task = createTask(mDisplayContent);
1009         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1010         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
1011         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
1012 
1013         // Closing TaskFragment with embedded activity.
1014         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
1015         final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
1016         prepareActivityForAppTransition(closingActivity);
1017         closingActivity.info.applicationInfo.uid = 12345;
1018         task.effectiveUid = closingActivity.getUid();
1019         // Opening non-embedded activity with different UID.
1020         final ActivityRecord openingActivity = createActivityRecord(task);
1021         prepareActivityForAppTransition(openingActivity);
1022         openingActivity.info.applicationInfo.uid = 54321;
1023         spyOn(mDisplayContent.mAppTransition);
1024 
1025         // Prepare and start transition.
1026         prepareAndTriggerAppTransition(openingActivity, closingActivity, taskFragment);
1027         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
1028 
1029         // Animation should not run by the remote handler when there are non-embedded activities of
1030         // different UID.
1031         assertFalse(remoteAnimationRunner.isAnimationStarted());
1032     }
1033 
1034     @Test
testOverrideTaskFragmentAdapter_noOverrideWithWallpaper()1035     public void testOverrideTaskFragmentAdapter_noOverrideWithWallpaper() {
1036         final Task task = createTask(mDisplayContent);
1037         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1038         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
1039         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
1040 
1041         // Create a TaskFragment with embedded activity.
1042         final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
1043         final ActivityRecord activity = taskFragment.getTopMostActivity();
1044         prepareActivityForAppTransition(activity);
1045         // Set wallpaper as visible.
1046         final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
1047                 mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */);
1048         spyOn(mDisplayContent.mWallpaperController);
1049         doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
1050         spyOn(mDisplayContent.mAppTransition);
1051 
1052         // Prepare and start transition.
1053         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
1054         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
1055 
1056         // Animation should not run by the remote handler when there is wallpaper in the transition.
1057         assertFalse(remoteAnimationRunner.isAnimationStarted());
1058     }
1059 
1060     @Test
testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation()1061     public void testOverrideTaskFragmentAdapter_inputProtectedForUntrustedAnimation() {
1062         final Task task = createTask(mDisplayContent);
1063         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1064         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
1065         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
1066 
1067         // Create a TaskFragment with embedded activities, one is trusted embedded, and the other
1068         // one is untrusted embedded.
1069         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1070                 .setParentTask(task)
1071                 .createActivityCount(2)
1072                 .setOrganizer(organizer)
1073                 .build();
1074         final ActivityRecord activity0 = taskFragment.getChildAt(0).asActivityRecord();
1075         final ActivityRecord activity1 = taskFragment.getChildAt(1).asActivityRecord();
1076         // Also create a non-embedded activity in the Task.
1077         final ActivityRecord activity2 = new ActivityBuilder(mAtm).build();
1078         task.addChild(activity2, POSITION_BOTTOM);
1079         prepareActivityForAppTransition(activity0);
1080         prepareActivityForAppTransition(activity1);
1081         prepareActivityForAppTransition(activity2);
1082         doReturn(false).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity0);
1083         doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity1);
1084         spyOn(mDisplayContent.mAppTransition);
1085 
1086         // Prepare and start transition.
1087         prepareAndTriggerAppTransition(activity1, null /* closingActivity */, taskFragment);
1088         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
1089 
1090         // The animation will be animated remotely by client and all activities are input disabled
1091         // for untrusted animation.
1092         assertTrue(remoteAnimationRunner.isAnimationStarted());
1093         verify(activity0).setDropInputForAnimation(true);
1094         verify(activity1).setDropInputForAnimation(true);
1095         verify(activity2).setDropInputForAnimation(true);
1096         verify(activity0).setDropInputMode(DropInputMode.ALL);
1097         verify(activity1).setDropInputMode(DropInputMode.ALL);
1098         verify(activity2).setDropInputMode(DropInputMode.ALL);
1099 
1100         // Reset input after animation is finished.
1101         clearInvocations(activity0);
1102         clearInvocations(activity1);
1103         clearInvocations(activity2);
1104         remoteAnimationRunner.finishAnimation();
1105 
1106         verify(activity0).setDropInputForAnimation(false);
1107         verify(activity1).setDropInputForAnimation(false);
1108         verify(activity2).setDropInputForAnimation(false);
1109         verify(activity0).setDropInputMode(DropInputMode.OBSCURED);
1110         verify(activity1).setDropInputMode(DropInputMode.NONE);
1111         verify(activity2).setDropInputMode(DropInputMode.NONE);
1112     }
1113 
1114     /**
1115      * Since we don't have any use case to rely on handling input during animation, disable it even
1116      * if it is trusted embedding so that it could cover some edge-cases when a previously trusted
1117      * host starts doing something bad.
1118      */
1119     @Test
testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation()1120     public void testOverrideTaskFragmentAdapter_inputProtectedForTrustedAnimation() {
1121         final Task task = createTask(mDisplayContent);
1122         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1123         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
1124         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
1125 
1126         // Create a TaskFragment with only trusted embedded activity
1127         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1128                 .setParentTask(task)
1129                 .createActivityCount(1)
1130                 .setOrganizer(organizer)
1131                 .build();
1132         final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
1133         prepareActivityForAppTransition(activity);
1134         doReturn(true).when(taskFragment).isAllowedToEmbedActivityInTrustedMode(activity);
1135         spyOn(mDisplayContent.mAppTransition);
1136 
1137         // Prepare and start transition.
1138         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
1139         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
1140 
1141         // The animation will be animated remotely by client and all activities are input disabled
1142         // for untrusted animation.
1143         assertTrue(remoteAnimationRunner.isAnimationStarted());
1144         verify(activity).setDropInputForAnimation(true);
1145         verify(activity).setDropInputMode(DropInputMode.ALL);
1146 
1147         // Reset input after animation is finished.
1148         clearInvocations(activity);
1149         remoteAnimationRunner.finishAnimation();
1150 
1151         verify(activity).setDropInputForAnimation(false);
1152         verify(activity).setDropInputMode(DropInputMode.NONE);
1153     }
1154 
1155     /**
1156      * We don't need to drop input for fully trusted embedding (system app, and embedding in the
1157      * same app). This will allow users to do fast tapping.
1158      */
1159     @Test
testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation()1160     public void testOverrideTaskFragmentAdapter_noInputProtectedForFullyTrustedAnimation() {
1161         final Task task = createTask(mDisplayContent);
1162         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1163         final TestRemoteAnimationRunner remoteAnimationRunner = new TestRemoteAnimationRunner();
1164         setupTaskFragmentRemoteAnimation(organizer, remoteAnimationRunner);
1165 
1166         // Create a TaskFragment with only trusted embedded activity
1167         final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
1168                 .setParentTask(task)
1169                 .createActivityCount(1)
1170                 .setOrganizer(organizer)
1171                 .build();
1172         final ActivityRecord activity = taskFragment.getChildAt(0).asActivityRecord();
1173         prepareActivityForAppTransition(activity);
1174         final int uid = mAtm.mTaskFragmentOrganizerController.getTaskFragmentOrganizerUid(
1175                 getITaskFragmentOrganizer(organizer));
1176         doReturn(true).when(task).isFullyTrustedEmbedding(uid);
1177         spyOn(mDisplayContent.mAppTransition);
1178 
1179         // Prepare and start transition.
1180         prepareAndTriggerAppTransition(activity, null /* closingActivity */, taskFragment);
1181         mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
1182 
1183         // The animation will be animated remotely by client, but input should not be dropped for
1184         // fully trusted.
1185         assertTrue(remoteAnimationRunner.isAnimationStarted());
1186         verify(activity, never()).setDropInputForAnimation(true);
1187         verify(activity, never()).setDropInputMode(DropInputMode.ALL);
1188     }
1189 
1190     @Test
testTransitionGoodToGoForTaskFragments()1191     public void testTransitionGoodToGoForTaskFragments() {
1192         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1193         final Task task = createTask(mDisplayContent);
1194         final TaskFragment changeTaskFragment =
1195                 createTaskFragmentWithEmbeddedActivity(task, organizer);
1196         final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm)
1197                 .setParentTask(task)
1198                 .setOrganizer(organizer)
1199                 .build();
1200         prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity());
1201         spyOn(mDisplayContent.mAppTransition);
1202         spyOn(emptyTaskFragment);
1203 
1204         prepareAndTriggerAppTransition(
1205                 null /* openingActivity */, null /* closingActivity*/, changeTaskFragment);
1206 
1207         // Transition not ready because there is an empty non-finishing TaskFragment.
1208         verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any());
1209 
1210         doReturn(true).when(emptyTaskFragment).hasChild();
1211         emptyTaskFragment.remove(false /* withTransition */, "test");
1212 
1213         mDisplayContent.mAppTransitionController.handleAppTransitionReady();
1214 
1215         // Transition ready because the empty (no running activity) TaskFragment is requested to be
1216         // removed.
1217         verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
1218     }
1219 
1220     @Test
testTransitionGoodToGoForTaskFragments_detachedApp()1221     public void testTransitionGoodToGoForTaskFragments_detachedApp() {
1222         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
1223         final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer);
1224         mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
1225         final Task task = createTask(mDisplayContent);
1226         final TaskFragment changeTaskFragment =
1227                 createTaskFragmentWithEmbeddedActivity(task, organizer);
1228         final TaskFragment emptyTaskFragment = new TaskFragmentBuilder(mAtm)
1229                 .setParentTask(task)
1230                 .setOrganizer(organizer)
1231                 .build();
1232         prepareActivityForAppTransition(changeTaskFragment.getTopMostActivity());
1233         // To make sure that having a detached activity won't cause any issue.
1234         final ActivityRecord detachedActivity = createActivityRecord(task);
1235         detachedActivity.removeImmediately();
1236         assertNull(detachedActivity.getRootTask());
1237         spyOn(mDisplayContent.mAppTransition);
1238         spyOn(emptyTaskFragment);
1239 
1240         prepareAndTriggerAppTransition(
1241                 null /* openingActivity */, detachedActivity, changeTaskFragment);
1242 
1243         // Transition not ready because there is an empty non-finishing TaskFragment.
1244         verify(mDisplayContent.mAppTransition, never()).goodToGo(anyInt(), any());
1245 
1246         doReturn(true).when(emptyTaskFragment).hasChild();
1247         emptyTaskFragment.remove(false /* withTransition */, "test");
1248 
1249         mDisplayContent.mAppTransitionController.handleAppTransitionReady();
1250 
1251         // Transition ready because the empty (no running activity) TaskFragment is requested to be
1252         // removed.
1253         verify(mDisplayContent.mAppTransition).goodToGo(anyInt(), any());
1254     }
1255 
1256     /** Registers remote animation for the organizer. */
setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer, TestRemoteAnimationRunner remoteAnimationRunner)1257     private void setupTaskFragmentRemoteAnimation(TaskFragmentOrganizer organizer,
1258             TestRemoteAnimationRunner remoteAnimationRunner) {
1259         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
1260                 remoteAnimationRunner, 10, 1);
1261         final ITaskFragmentOrganizer iOrganizer = getITaskFragmentOrganizer(organizer);
1262         final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
1263         definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
1264         definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, adapter);
1265         definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, adapter);
1266         definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_OPEN, adapter);
1267         definition.addRemoteAnimation(TRANSIT_OLD_ACTIVITY_CLOSE, adapter);
1268         mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
1269         mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
1270     }
1271 
getITaskFragmentOrganizer( TaskFragmentOrganizer organizer)1272     private static ITaskFragmentOrganizer getITaskFragmentOrganizer(
1273             TaskFragmentOrganizer organizer) {
1274         return ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
1275     }
1276 
prepareAndTriggerAppTransition(@ullable ActivityRecord openingActivity, @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment)1277     private void prepareAndTriggerAppTransition(@Nullable ActivityRecord openingActivity,
1278             @Nullable ActivityRecord closingActivity, @Nullable TaskFragment changingTaskFragment) {
1279         if (openingActivity != null) {
1280             mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_OPEN, 0);
1281             mDisplayContent.mOpeningApps.add(openingActivity);
1282         }
1283         if (closingActivity != null) {
1284             mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CLOSE, 0);
1285             mDisplayContent.mClosingApps.add(closingActivity);
1286         }
1287         if (changingTaskFragment != null) {
1288             mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0);
1289             mDisplayContent.mChangingContainers.add(changingTaskFragment);
1290         }
1291         mDisplayContent.mAppTransitionController.handleAppTransitionReady();
1292     }
1293 
prepareActivityForAppTransition(ActivityRecord activity)1294     private static void prepareActivityForAppTransition(ActivityRecord activity) {
1295         // Transition will wait until all participated activities to be drawn.
1296         activity.allDrawn = true;
1297         // Skip manipulate the SurfaceControl.
1298         doNothing().when(activity).setDropInputMode(anyInt());
1299         // Assume the activity contains a window.
1300         doReturn(true).when(activity).hasChild();
1301         // Make sure activity can create remote animation target.
1302         doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget(
1303                 any());
1304     }
1305 }