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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
25 import static android.view.WindowInsets.Type.systemOverlays;
26 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
27 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
28 import static android.view.WindowManager.TRANSIT_CLOSE;
29 import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
30 import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
31 import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
32 import static android.view.WindowManager.TRANSIT_OPEN;
33 import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
34 
35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
46 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
47 import static com.android.server.wm.DisplayArea.Type.ANY;
48 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
49 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
50 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;
51 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
52 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
53 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
54 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
55 import static com.android.server.wm.WindowContainer.POSITION_TOP;
56 
57 import static com.google.common.truth.Truth.assertThat;
58 
59 import static org.junit.Assert.assertEquals;
60 import static org.junit.Assert.assertFalse;
61 import static org.junit.Assert.assertNotEquals;
62 import static org.junit.Assert.assertNotNull;
63 import static org.junit.Assert.assertNull;
64 import static org.junit.Assert.assertTrue;
65 import static org.mockito.Mockito.clearInvocations;
66 
67 import android.annotation.NonNull;
68 import android.annotation.Nullable;
69 import android.content.pm.ActivityInfo;
70 import android.content.res.Configuration;
71 import android.graphics.Rect;
72 import android.os.Binder;
73 import android.os.DeadObjectException;
74 import android.os.IBinder;
75 import android.os.IInterface;
76 import android.os.Parcel;
77 import android.os.RemoteException;
78 import android.os.ResultReceiver;
79 import android.os.ShellCallback;
80 import android.platform.test.annotations.Presubmit;
81 import android.view.IRemoteAnimationFinishedCallback;
82 import android.view.IRemoteAnimationRunner;
83 import android.view.InsetsFrameProvider;
84 import android.view.InsetsSource;
85 import android.view.RemoteAnimationAdapter;
86 import android.view.RemoteAnimationTarget;
87 import android.view.SurfaceControl;
88 import android.view.SurfaceSession;
89 import android.view.WindowInsets;
90 import android.view.WindowManager;
91 
92 import androidx.test.filters.SmallTest;
93 
94 import org.junit.Test;
95 import org.junit.runner.RunWith;
96 import org.mockito.ArgumentCaptor;
97 import org.mockito.Mockito;
98 
99 import java.io.FileDescriptor;
100 import java.util.ArrayList;
101 import java.util.Comparator;
102 import java.util.NoSuchElementException;
103 
104 
105 /**
106  * Test class for {@link WindowContainer}.
107  *
108  * Build/Install/Run:
109  *  atest WmTests:WindowContainerTests
110  */
111 @SmallTest
112 @Presubmit
113 @RunWith(WindowTestRunner.class)
114 public class WindowContainerTests extends WindowTestsBase {
115 
116     @Test
testCreation()117     public void testCreation() {
118         final TestWindowContainer w = new TestWindowContainerBuilder(mWm).setLayer(0).build();
119         assertNull("window must have no parent", w.getParentWindow());
120         assertEquals("window must have no children", 0, w.getChildrenCount());
121     }
122 
123     @Test
testAdd()124     public void testAdd() {
125         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
126         final TestWindowContainer root = builder.setLayer(0).build();
127 
128         final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1));
129         final TestWindowContainer secondLayer1 = root.addChildWindow(builder.setLayer(1));
130         final TestWindowContainer layer2 = root.addChildWindow(builder.setLayer(2));
131         final TestWindowContainer layerNeg1 = root.addChildWindow(builder.setLayer(-1));
132         final TestWindowContainer layerNeg2 = root.addChildWindow(builder.setLayer(-2));
133         final TestWindowContainer secondLayerNeg1 = root.addChildWindow(builder.setLayer(-1));
134         final TestWindowContainer layer0 = root.addChildWindow(builder.setLayer(0));
135 
136         assertEquals(7, root.getChildrenCount());
137 
138         assertEquals(root, layer1.getParentWindow());
139         assertEquals(root, secondLayer1.getParentWindow());
140         assertEquals(root, layer2.getParentWindow());
141         assertEquals(root, layerNeg1.getParentWindow());
142         assertEquals(root, layerNeg2.getParentWindow());
143         assertEquals(root, secondLayerNeg1.getParentWindow());
144         assertEquals(root, layer0.getParentWindow());
145 
146         assertEquals(layerNeg2, root.getChildAt(0));
147         assertEquals(secondLayerNeg1, root.getChildAt(1));
148         assertEquals(layerNeg1, root.getChildAt(2));
149         assertEquals(layer0, root.getChildAt(3));
150         assertEquals(layer1, root.getChildAt(4));
151         assertEquals(secondLayer1, root.getChildAt(5));
152         assertEquals(layer2, root.getChildAt(6));
153 
154         assertTrue(layer1.mOnParentChangedCalled);
155         assertTrue(secondLayer1.mOnParentChangedCalled);
156         assertTrue(layer2.mOnParentChangedCalled);
157         assertTrue(layerNeg1.mOnParentChangedCalled);
158         assertTrue(layerNeg2.mOnParentChangedCalled);
159         assertTrue(secondLayerNeg1.mOnParentChangedCalled);
160         assertTrue(layer0.mOnParentChangedCalled);
161     }
162 
163     @Test
testAddChildSetsSurfacePosition()164     public void testAddChildSetsSurfacePosition() {
165         reset(mTransaction);
166         try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
167             WindowContainer child = new WindowContainer(mWm);
168             child.setBounds(1, 1, 10, 10);
169 
170             verify(mTransaction, never()).setPosition(any(), anyFloat(), anyFloat());
171             top.addChild(child, 0);
172             verify(mTransaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
173         }
174     }
175 
176     @Test
testAdd_AlreadyHasParent()177     public void testAdd_AlreadyHasParent() {
178         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
179         final TestWindowContainer root = builder.setLayer(0).build();
180 
181         final TestWindowContainer child1 = root.addChildWindow();
182         final TestWindowContainer child2 = root.addChildWindow();
183 
184         boolean gotException = false;
185         try {
186             child1.addChildWindow(child2);
187         } catch (IllegalArgumentException e) {
188             gotException = true;
189         }
190         assertTrue(gotException);
191 
192         gotException = false;
193         try {
194             root.addChildWindow(child2);
195         } catch (IllegalArgumentException e) {
196             gotException = true;
197         }
198         assertTrue(gotException);
199     }
200 
201     @Test
testHasChild()202     public void testHasChild() {
203         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
204         final TestWindowContainer root = builder.setLayer(0).build();
205 
206         final TestWindowContainer child1 = root.addChildWindow();
207         final TestWindowContainer child2 = root.addChildWindow();
208         final TestWindowContainer child11 = child1.addChildWindow();
209         final TestWindowContainer child12 = child1.addChildWindow();
210         final TestWindowContainer child21 = child2.addChildWindow();
211 
212         assertEquals(2, root.getChildrenCount());
213         assertEquals(2, child1.getChildrenCount());
214         assertEquals(1, child2.getChildrenCount());
215 
216         assertTrue(root.hasChild(child1));
217         assertTrue(root.hasChild(child2));
218         assertTrue(root.hasChild(child11));
219         assertTrue(root.hasChild(child12));
220         assertTrue(root.hasChild(child21));
221 
222         assertTrue(child1.hasChild(child11));
223         assertTrue(child1.hasChild(child12));
224         assertFalse(child1.hasChild(child21));
225 
226         assertTrue(child2.hasChild(child21));
227         assertFalse(child2.hasChild(child11));
228         assertFalse(child2.hasChild(child12));
229     }
230 
231     @Test
testRemoveImmediately()232     public void testRemoveImmediately() {
233         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
234         final TestWindowContainer root = builder.setLayer(0).build();
235 
236         final TestWindowContainer child1 = root.addChildWindow();
237         final TestWindowContainer child2 = root.addChildWindow();
238         final TestWindowContainer child11 = child1.addChildWindow();
239         final TestWindowContainer child12 = child1.addChildWindow();
240         final TestWindowContainer child21 = child2.addChildWindow();
241 
242         assertNotNull(child12.getParentWindow());
243         child12.removeImmediately();
244         assertNull(child12.getParentWindow());
245         assertEquals(1, child1.getChildrenCount());
246         assertFalse(child1.hasChild(child12));
247         assertFalse(root.hasChild(child12));
248 
249         assertTrue(root.hasChild(child2));
250         assertNotNull(child2.getParentWindow());
251         child2.removeImmediately();
252         assertNull(child2.getParentWindow());
253         assertNull(child21.getParentWindow());
254         assertEquals(0, child2.getChildrenCount());
255         assertEquals(1, root.getChildrenCount());
256         assertFalse(root.hasChild(child2));
257         assertFalse(root.hasChild(child21));
258 
259         assertTrue(root.hasChild(child1));
260         assertTrue(root.hasChild(child11));
261 
262         root.removeImmediately();
263         assertEquals(0, root.getChildrenCount());
264     }
265 
266     @Test
testRemoveImmediatelyClearsLastSurfacePosition()267     public void testRemoveImmediatelyClearsLastSurfacePosition() {
268         reset(mTransaction);
269         try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
270             final WindowContainer<WindowContainer> child1 = new WindowContainer(mWm);
271             child1.setBounds(1, 1, 10, 10);
272 
273             top.addChild(child1, 0);
274             assertEquals(1, child1.getLastSurfacePosition().x);
275             assertEquals(1, child1.getLastSurfacePosition().y);
276 
277             WindowContainer child11 = new WindowContainer(mWm);
278             child1.addChild(child11, 0);
279 
280             child1.setBounds(2, 2, 20, 20);
281             assertEquals(2, child1.getLastSurfacePosition().x);
282             assertEquals(2, child1.getLastSurfacePosition().y);
283 
284             child1.removeImmediately();
285             assertEquals(0, child1.getLastSurfacePosition().x);
286             assertEquals(0, child1.getLastSurfacePosition().y);
287             assertEquals(0, child11.getLastSurfacePosition().x);
288             assertEquals(0, child11.getLastSurfacePosition().y);
289         }
290     }
291 
292     @Test
testRemoveImmediatelyClearsLeash()293     public void testRemoveImmediatelyClearsLeash() {
294         final AnimationAdapter animAdapter = mock(AnimationAdapter.class);
295         final WindowToken token = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent);
296         final SurfaceControl.Transaction t = token.getPendingTransaction();
297         token.startAnimation(t, animAdapter, false /* hidden */,
298                 SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
299         final ArgumentCaptor<SurfaceControl> leashCaptor =
300                 ArgumentCaptor.forClass(SurfaceControl.class);
301         verify(animAdapter).startAnimation(leashCaptor.capture(), eq(t), anyInt(), any());
302         assertTrue(token.mSurfaceAnimator.hasLeash());
303         token.removeImmediately();
304         assertFalse(token.mSurfaceAnimator.hasLeash());
305         verify(t).remove(eq(leashCaptor.getValue()));
306     }
307 
308     @Test
testAddChildByIndex()309     public void testAddChildByIndex() {
310         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
311         final TestWindowContainer root = builder.setLayer(0).build();
312 
313         final TestWindowContainer child = root.addChildWindow();
314 
315         final TestWindowContainer child2 = builder.setLayer(1).build();
316         final TestWindowContainer child3 = builder.setLayer(2).build();
317         final TestWindowContainer child4 = builder.setLayer(3).build();
318 
319         // Test adding at top.
320         root.addChild(child2, POSITION_TOP);
321         assertEquals(child2, root.getChildAt(root.getChildrenCount() - 1));
322 
323         // Test adding at bottom.
324         root.addChild(child3, POSITION_BOTTOM);
325         assertEquals(child3, root.getChildAt(0));
326 
327         // Test adding in the middle.
328         root.addChild(child4, 1);
329         assertEquals(child3, root.getChildAt(0));
330         assertEquals(child4, root.getChildAt(1));
331         assertEquals(child, root.getChildAt(2));
332         assertEquals(child2, root.getChildAt(3));
333     }
334 
335     @Test
testPositionChildAt()336     public void testPositionChildAt() {
337         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
338         final TestWindowContainer root = builder.setLayer(0).build();
339 
340         final TestWindowContainer child1 = root.addChildWindow();
341         final TestWindowContainer child2 = root.addChildWindow();
342         final TestWindowContainer child3 = root.addChildWindow();
343 
344         // Test position at top.
345         root.positionChildAt(POSITION_TOP, child1, false /* includingParents */);
346         assertEquals(child1, root.getChildAt(root.getChildrenCount() - 1));
347 
348         // Test position at bottom.
349         root.positionChildAt(POSITION_BOTTOM, child1, false /* includingParents */);
350         assertEquals(child1, root.getChildAt(0));
351 
352         // Test position in the middle.
353         root.positionChildAt(1, child3, false /* includingParents */);
354         assertEquals(child1, root.getChildAt(0));
355         assertEquals(child3, root.getChildAt(1));
356         assertEquals(child2, root.getChildAt(2));
357     }
358 
359     @Test
testPositionChildAtIncludeParents()360     public void testPositionChildAtIncludeParents() {
361         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
362         final TestWindowContainer root = builder.setLayer(0).build();
363 
364         final TestWindowContainer child1 = root.addChildWindow();
365         final TestWindowContainer child2 = root.addChildWindow();
366         final TestWindowContainer child11 = child1.addChildWindow();
367         final TestWindowContainer child12 = child1.addChildWindow();
368         final TestWindowContainer child13 = child1.addChildWindow();
369         final TestWindowContainer child21 = child2.addChildWindow();
370         final TestWindowContainer child22 = child2.addChildWindow();
371         final TestWindowContainer child23 = child2.addChildWindow();
372 
373         // Test moving to top.
374         child1.positionChildAt(POSITION_TOP, child11, true /* includingParents */);
375         assertEquals(child12, child1.getChildAt(0));
376         assertEquals(child13, child1.getChildAt(1));
377         assertEquals(child11, child1.getChildAt(2));
378         assertEquals(child2, root.getChildAt(0));
379         assertEquals(child1, root.getChildAt(1));
380 
381         // Test moving to bottom.
382         child1.positionChildAt(POSITION_BOTTOM, child11, true /* includingParents */);
383         assertEquals(child11, child1.getChildAt(0));
384         assertEquals(child12, child1.getChildAt(1));
385         assertEquals(child13, child1.getChildAt(2));
386         assertEquals(child1, root.getChildAt(0));
387         assertEquals(child2, root.getChildAt(1));
388 
389         // Test moving to middle, includeParents shouldn't do anything.
390         child2.positionChildAt(1, child21, true /* includingParents */);
391         assertEquals(child11, child1.getChildAt(0));
392         assertEquals(child12, child1.getChildAt(1));
393         assertEquals(child13, child1.getChildAt(2));
394         assertEquals(child22, child2.getChildAt(0));
395         assertEquals(child21, child2.getChildAt(1));
396         assertEquals(child23, child2.getChildAt(2));
397         assertEquals(child1, root.getChildAt(0));
398         assertEquals(child2, root.getChildAt(1));
399     }
400 
401     @Test
testIsAnimating_TransitionFlag()402     public void testIsAnimating_TransitionFlag() {
403         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
404         final TestWindowContainer root = builder.setLayer(0).build();
405         final TestWindowContainer child1 = root.addChildWindow(
406                 builder.setWaitForTransitionStart(true));
407 
408         assertFalse(root.isAnimating(TRANSITION));
409         assertTrue(child1.isAnimating(TRANSITION));
410     }
411 
412     @Test
testIsAnimating_ParentsFlag()413     public void testIsAnimating_ParentsFlag() {
414         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
415         final TestWindowContainer root = builder.setLayer(0).build();
416         final TestWindowContainer child1 = root.addChildWindow(builder);
417         final TestWindowContainer child2 = root.addChildWindow(builder.setIsAnimating(true));
418         final TestWindowContainer child21 = child2.addChildWindow(builder.setIsAnimating(false));
419 
420         assertFalse(root.isAnimating());
421         assertFalse(child1.isAnimating());
422         assertFalse(child1.isAnimating(PARENTS));
423         assertTrue(child2.isAnimating());
424         assertTrue(child2.isAnimating(PARENTS));
425         assertFalse(child21.isAnimating());
426         assertTrue(child21.isAnimating(PARENTS));
427     }
428 
429     @Test
testIsAnimating_ChildrenFlag()430     public void testIsAnimating_ChildrenFlag() {
431         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
432         final TestWindowContainer root = builder.setLayer(0).build();
433         final TestWindowContainer child1 = root.addChildWindow(builder);
434         final TestWindowContainer child2 = root.addChildWindow(builder.setIsAnimating(true));
435         final TestWindowContainer child11 = child1.addChildWindow(builder.setIsAnimating(true));
436 
437         assertFalse(root.isAnimating());
438         assertTrue(root.isAnimating(CHILDREN));
439         assertFalse(child1.isAnimating());
440         assertTrue(child1.isAnimating(CHILDREN));
441         assertTrue(child2.isAnimating());
442         assertTrue(child2.isAnimating(CHILDREN));
443         assertTrue(child11.isAnimating());
444         assertTrue(child11.isAnimating(CHILDREN));
445     }
446 
447     @Test
testIsAnimating_combineFlags()448     public void testIsAnimating_combineFlags() {
449         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
450         final TestWindowContainer root = builder.setLayer(0).build();
451 
452         final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true));
453         final TestWindowContainer child2 = root.addChildWindow();
454         final TestWindowContainer child11 = child1.addChildWindow();
455         final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
456         final TestWindowContainer child21 = child2.addChildWindow();
457 
458         assertFalse(root.isAnimating(TRANSITION | PARENTS));
459         assertTrue(child1.isAnimating(TRANSITION | PARENTS));
460         assertTrue(child11.isAnimating(TRANSITION | PARENTS));
461         assertTrue(child12.isAnimating(TRANSITION | PARENTS));
462         assertFalse(child2.isAnimating(TRANSITION | PARENTS));
463         assertFalse(child21.isAnimating(TRANSITION | PARENTS));
464 
465         assertTrue(root.isAnimating(TRANSITION | CHILDREN));
466         assertTrue(child1.isAnimating(TRANSITION | CHILDREN));
467         assertFalse(child11.isAnimating(TRANSITION | CHILDREN));
468         assertTrue(child12.isAnimating(TRANSITION | CHILDREN));
469         assertFalse(child2.isAnimating(TRANSITION | CHILDREN));
470         assertFalse(child21.isAnimating(TRANSITION | CHILDREN));
471     }
472 
473     @Test
testIsAnimating_typesToCheck()474     public void testIsAnimating_typesToCheck() {
475         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
476         final TestWindowContainer window = builder.setIsAnimating(true).setLayer(0).build();
477 
478         assertTrue(window.isAnimating());
479         assertFalse(window.isAnimating(0, ANIMATION_TYPE_SCREEN_ROTATION));
480         assertTrue(window.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION));
481         assertFalse(window.isAnimating(0, ANIMATION_TYPE_ALL & ~ANIMATION_TYPE_APP_TRANSITION));
482 
483         final TestWindowContainer child = window.addChildWindow();
484         assertFalse(child.isAnimating());
485         assertTrue(child.isAnimating(PARENTS));
486         assertTrue(child.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
487         assertFalse(child.isAnimating(PARENTS, ANIMATION_TYPE_SCREEN_ROTATION));
488 
489         final WindowState windowState = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
490                 mDisplayContent, "TestWindowState");
491         WindowContainer parent = windowState.getParent();
492         spyOn(windowState.mSurfaceAnimator);
493         doReturn(true).when(windowState.mSurfaceAnimator).isAnimating();
494         doReturn(ANIMATION_TYPE_APP_TRANSITION).when(
495                 windowState.mSurfaceAnimator).getAnimationType();
496         assertTrue(parent.isAnimating(CHILDREN));
497 
498         windowState.setControllableInsetProvider(mock(InsetsSourceProvider.class));
499         assertFalse(parent.isAnimating(CHILDREN));
500     }
501 
502     @Test
testIsVisible()503     public void testIsVisible() {
504         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
505         final TestWindowContainer root = builder.setLayer(0).build();
506 
507         final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true));
508         final TestWindowContainer child2 = root.addChildWindow();
509         final TestWindowContainer child11 = child1.addChildWindow();
510         final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true));
511         final TestWindowContainer child21 = child2.addChildWindow();
512 
513         assertFalse(root.isVisible());
514         assertTrue(child1.isVisible());
515         assertFalse(child11.isVisible());
516         assertTrue(child12.isVisible());
517         assertFalse(child2.isVisible());
518         assertFalse(child21.isVisible());
519     }
520 
521     @Test
testOverrideConfigurationAncestorNotification()522     public void testOverrideConfigurationAncestorNotification() {
523         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
524         final TestWindowContainer grandparent = builder.setLayer(0).build();
525 
526         final TestWindowContainer parent = grandparent.addChildWindow();
527         final TestWindowContainer child = parent.addChildWindow();
528         child.onRequestedOverrideConfigurationChanged(new Configuration());
529 
530         assertTrue(grandparent.mOnDescendantOverrideCalled);
531     }
532 
533     @Test
testRemoveChild()534     public void testRemoveChild() {
535         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
536         final TestWindowContainer root = builder.setLayer(0).build();
537         final TestWindowContainer child1 = root.addChildWindow();
538         final TestWindowContainer child2 = root.addChildWindow();
539         final TestWindowContainer child11 = child1.addChildWindow();
540         final TestWindowContainer child21 = child2.addChildWindow();
541 
542         assertTrue(root.hasChild(child2));
543         assertTrue(root.hasChild(child21));
544         root.removeChild(child2);
545         assertFalse(root.hasChild(child2));
546         assertFalse(root.hasChild(child21));
547         assertNull(child2.getParentWindow());
548 
549         boolean gotException = false;
550         assertTrue(root.hasChild(child11));
551         try {
552             // Can only detach our direct children.
553             root.removeChild(child11);
554         } catch (IllegalArgumentException e) {
555             gotException = true;
556         }
557         assertTrue(gotException);
558     }
559 
560     @Test
testGetOrientation_childSpecified()561     public void testGetOrientation_childSpecified() {
562         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
563                 SCREEN_ORIENTATION_LANDSCAPE);
564         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
565                 SCREEN_ORIENTATION_UNSPECIFIED);
566     }
567 
testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation, int expectedOrientation)568     private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
569             int expectedOrientation) {
570         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
571         final TestWindowContainer root = builder.setLayer(0).build();
572         root.setFillsParent(true);
573 
574         builder.setIsVisible(childVisible);
575 
576         if (childOrientation != SCREEN_ORIENTATION_UNSET) {
577             builder.setOrientation(childOrientation);
578         }
579 
580         final TestWindowContainer child1 = root.addChildWindow(builder);
581         child1.setFillsParent(true);
582 
583         assertEquals(expectedOrientation, root.getOrientation());
584     }
585 
586     @Test
testGetOrientation_Unset()587     public void testGetOrientation_Unset() {
588         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
589         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
590         // Unspecified well because we didn't specify anything...
591         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
592     }
593 
594     @Test
testGetOrientation_InvisibleParentUnsetVisibleChildren()595     public void testGetOrientation_InvisibleParentUnsetVisibleChildren() {
596         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
597         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
598 
599         builder.setIsVisible(false).setLayer(-1);
600         final TestWindowContainer invisible = root.addChildWindow(builder);
601         builder.setIsVisible(true).setLayer(-2);
602         final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder);
603         invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
604         // Landscape well because the container is visible and that is what we set on it above.
605         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
606         // Landscape because even though the container isn't visible it has a child that is
607         // specifying it can influence the orientation by being visible.
608         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisible.getOrientation());
609         // Landscape because the grandchild is visible and therefore can participate.
610         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
611 
612         builder.setIsVisible(true).setLayer(-3);
613         final TestWindowContainer visibleUnset = root.addChildWindow(builder);
614         visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
615         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
616         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
617     }
618 
619     @Test
testGetOrientation_setBehind()620     public void testGetOrientation_setBehind() {
621         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
622         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
623 
624         builder.setIsVisible(true).setLayer(-1);
625         final TestWindowContainer visibleUnset = root.addChildWindow(builder);
626         visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
627 
628         builder.setIsVisible(true).setLayer(-2);
629         final TestWindowContainer visibleUnsetChild1VisibleSetBehind =
630                 visibleUnset.addChildWindow(builder);
631         visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND);
632         // Setting to visible behind will be used by the parents if there isn't another other
633         // container behind this one that has an orientation set.
634         assertEquals(SCREEN_ORIENTATION_BEHIND,
635                 visibleUnsetChild1VisibleSetBehind.getOrientation());
636         assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation());
637         assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
638     }
639 
640     @Test
testGetOrientation_fillsParent()641     public void testGetOrientation_fillsParent() {
642         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
643         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
644 
645         builder.setIsVisible(true).setLayer(-1);
646         final TestWindowContainer visibleUnset = root.addChildWindow(builder);
647         visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND);
648 
649         builder.setLayer(1).setIsVisible(true);
650         final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder);
651         visibleUnspecifiedRootChild.setFillsParent(false);
652         visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
653         // Unset because the child doesn't fill the parent. May as well be invisible...
654         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
655         // The parent uses whatever orientation is set behind this container since it doesn't fill
656         // the parent.
657         assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
658 
659         // Test case of child filling its parent, but its parent isn't filling its own parent.
660         builder.setLayer(2).setIsVisible(true);
661         final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
662                 visibleUnspecifiedRootChild.addChildWindow(builder);
663         visibleUnspecifiedRootChildChildFillsParent.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
664         assertEquals(SCREEN_ORIENTATION_PORTRAIT,
665                 visibleUnspecifiedRootChildChildFillsParent.getOrientation());
666         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
667         assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
668 
669 
670         visibleUnspecifiedRootChild.setFillsParent(true);
671         assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation());
672         assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation());
673     }
674 
675     @Test
testSetVisibleRequested()676     public void testSetVisibleRequested() {
677         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer(
678                 0).build());
679         assertThat(root.isVisibleRequested()).isFalse();
680         final TestWindowContainerListener listener = new TestWindowContainerListener();
681         root.registerWindowContainerListener(listener);
682 
683         assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse();
684         assertThat(root.isVisibleRequested()).isFalse();
685 
686         assertThat(root.setVisibleRequested(/* isVisible= */ true)).isTrue();
687         assertThat(root.isVisibleRequested()).isTrue();
688         assertThat(listener.mIsVisibleRequested).isTrue();
689     }
690 
691     @Test
testSetVisibleRequested_childRequestsVisible()692     public void testSetVisibleRequested_childRequestsVisible() {
693         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer(
694                 0).build());
695         final TestWindowContainer child1 = root.addChildWindow();
696         assertThat(child1.isVisibleRequested()).isFalse();
697         final TestWindowContainerListener listener = new TestWindowContainerListener();
698         root.registerWindowContainerListener(listener);
699 
700         // Hidden root and child request hidden.
701         assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse();
702         assertThat(listener.mIsVisibleRequested).isFalse();
703         assertThat(child1.isVisibleRequested()).isFalse();
704 
705         // Child requests to be visible, so child and root request visible.
706         assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue();
707         assertThat(root.isVisibleRequested()).isTrue();
708         assertThat(listener.mIsVisibleRequested).isTrue();
709         assertThat(child1.isVisibleRequested()).isTrue();
710         // Visible request didn't change.
711         assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isFalse();
712         verify(root, times(2)).onChildVisibleRequestedChanged(child1);
713     }
714 
715     @Test
testSetVisibleRequested_childRequestsHidden()716     public void testSetVisibleRequested_childRequestsHidden() {
717         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer(
718                 0).build());
719         final TestWindowContainer child1 = root.addChildWindow();
720         assertThat(child1.isVisibleRequested()).isFalse();
721         final TestWindowContainerListener listener = new TestWindowContainerListener();
722         root.registerWindowContainerListener(listener);
723 
724         // Root and child requests visible.
725         assertThat(root.setVisibleRequested(/* isVisible= */ true)).isTrue();
726         assertThat(listener.mIsVisibleRequested).isTrue();
727         assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue();
728         assertThat(child1.isVisibleRequested()).isTrue();
729 
730         // Child requests hidden, so child and root request hidden.
731         assertThat(child1.setVisibleRequested(/* isVisible= */ false)).isTrue();
732         assertThat(root.isVisibleRequested()).isFalse();
733         assertThat(listener.mIsVisibleRequested).isFalse();
734         assertThat(child1.isVisibleRequested()).isFalse();
735         // Visible request didn't change.
736         assertThat(child1.setVisibleRequested(/* isVisible= */ false)).isFalse();
737         verify(root, times(3)).onChildVisibleRequestedChanged(child1);
738     }
739 
740     @Test
testOnChildVisibleRequestedChanged_bothVisible()741     public void testOnChildVisibleRequestedChanged_bothVisible() {
742         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer(
743                 0).build());
744         final TestWindowContainer child1 = root.addChildWindow();
745 
746         // Child and root request visible.
747         assertThat(root.setVisibleRequested(/* isVisible= */ true)).isTrue();
748         assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue();
749 
750         // Visible request already updated on root when child requested.
751         assertThat(root.onChildVisibleRequestedChanged(child1)).isFalse();
752     }
753 
754     @Test
testOnChildVisibleRequestedChanged_childVisible()755     public void testOnChildVisibleRequestedChanged_childVisible() {
756         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer(
757                 0).build());
758         final TestWindowContainer child1 = root.addChildWindow();
759 
760         assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse();
761         assertThat(child1.setVisibleRequested(/* isVisible= */ true)).isTrue();
762 
763         // Visible request already updated on root when child requested.
764         assertThat(root.onChildVisibleRequestedChanged(child1)).isFalse();
765     }
766 
767     @Test
testOnChildVisibleRequestedChanged_childHidden()768     public void testOnChildVisibleRequestedChanged_childHidden() {
769         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).setLayer(
770                 0).build());
771         final TestWindowContainer child1 = root.addChildWindow();
772 
773         assertThat(root.setVisibleRequested(/* isVisible= */ false)).isFalse();
774         assertThat(child1.setVisibleRequested(/* isVisible= */ false)).isFalse();
775 
776         // Visible request did not change.
777         assertThat(root.onChildVisibleRequestedChanged(child1)).isFalse();
778     }
779 
780     @Test
testSetOrientation()781     public void testSetOrientation() {
782         final TestWindowContainer root = spy(new TestWindowContainerBuilder(mWm).build());
783         final TestWindowContainer child = spy(root.addChildWindow());
784         doReturn(true).when(root).handlesOrientationChangeFromDescendant(anyInt());
785         child.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
786         child.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
787         // The ancestor should decide whether to dispatch the configuration change.
788         verify(child, never()).onConfigurationChanged(any());
789 
790         doReturn(false).when(root).handlesOrientationChangeFromDescendant(anyInt());
791         child.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
792         // The ancestor doesn't handle the request so the descendant applies the change directly.
793         verify(child).onConfigurationChanged(any());
794     }
795 
796     @Test
testCompareTo()797     public void testCompareTo() {
798         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
799         final TestWindowContainer root = builder.setLayer(0).build();
800 
801         final TestWindowContainer child1 = root.addChildWindow();
802         final TestWindowContainer child11 = child1.addChildWindow();
803         final TestWindowContainer child12 = child1.addChildWindow();
804 
805         final TestWindowContainer child2 = root.addChildWindow();
806         final TestWindowContainer child21 = child2.addChildWindow();
807         final TestWindowContainer child22 = child2.addChildWindow();
808         final TestWindowContainer child222 = child22.addChildWindow();
809         final TestWindowContainer child223 = child22.addChildWindow();
810         final TestWindowContainer child2221 = child222.addChildWindow();
811         final TestWindowContainer child2222 = child222.addChildWindow();
812         final TestWindowContainer child2223 = child222.addChildWindow();
813 
814         final TestWindowContainer root2 = builder.setLayer(0).build();
815 
816         assertEquals(0, root.compareTo(root));
817         assertEquals(-1, child1.compareTo(child2));
818         assertEquals(1, child2.compareTo(child1));
819 
820         boolean inTheSameTree = true;
821         try {
822             root.compareTo(root2);
823         } catch (IllegalArgumentException e) {
824             inTheSameTree = false;
825         }
826         assertFalse(inTheSameTree);
827 
828         assertEquals(-1, child1.compareTo(child11));
829         assertEquals(1, child21.compareTo(root));
830         assertEquals(1, child21.compareTo(child12));
831         assertEquals(-1, child11.compareTo(child2));
832         assertEquals(1, child2221.compareTo(child11));
833         assertEquals(-1, child2222.compareTo(child223));
834         assertEquals(1, child2223.compareTo(child21));
835     }
836 
837     @Test
testPrefixOrderIndex()838     public void testPrefixOrderIndex() {
839         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
840         final TestWindowContainer root = builder.build();
841 
842         final TestWindowContainer child1 = root.addChildWindow();
843 
844         final TestWindowContainer child11 = child1.addChildWindow();
845         final TestWindowContainer child12 = child1.addChildWindow();
846 
847         final TestWindowContainer child2 = root.addChildWindow();
848 
849         final TestWindowContainer child21 = child2.addChildWindow();
850         final TestWindowContainer child22 = child2.addChildWindow();
851 
852         final TestWindowContainer child221 = child22.addChildWindow();
853         final TestWindowContainer child222 = child22.addChildWindow();
854         final TestWindowContainer child223 = child22.addChildWindow();
855 
856         final TestWindowContainer child23 = child2.addChildWindow();
857 
858         assertEquals(0, root.getPrefixOrderIndex());
859         assertEquals(1, child1.getPrefixOrderIndex());
860         assertEquals(2, child11.getPrefixOrderIndex());
861         assertEquals(3, child12.getPrefixOrderIndex());
862         assertEquals(4, child2.getPrefixOrderIndex());
863         assertEquals(5, child21.getPrefixOrderIndex());
864         assertEquals(6, child22.getPrefixOrderIndex());
865         assertEquals(7, child221.getPrefixOrderIndex());
866         assertEquals(8, child222.getPrefixOrderIndex());
867         assertEquals(9, child223.getPrefixOrderIndex());
868         assertEquals(10, child23.getPrefixOrderIndex());
869     }
870 
871     @Test
testPrefixOrder_addEntireSubtree()872     public void testPrefixOrder_addEntireSubtree() {
873         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
874         final TestWindowContainer root = builder.build();
875         final TestWindowContainer subtree = builder.build();
876         final TestWindowContainer subtree2 = builder.build();
877 
878         final TestWindowContainer child1 = subtree.addChildWindow();
879         final TestWindowContainer child11 = child1.addChildWindow();
880         final TestWindowContainer child2 = subtree2.addChildWindow();
881         final TestWindowContainer child3 = subtree2.addChildWindow();
882         subtree.addChild(subtree2, 1);
883         root.addChild(subtree, 0);
884 
885         assertEquals(0, root.getPrefixOrderIndex());
886         assertEquals(1, subtree.getPrefixOrderIndex());
887         assertEquals(2, child1.getPrefixOrderIndex());
888         assertEquals(3, child11.getPrefixOrderIndex());
889         assertEquals(4, subtree2.getPrefixOrderIndex());
890         assertEquals(5, child2.getPrefixOrderIndex());
891         assertEquals(6, child3.getPrefixOrderIndex());
892     }
893 
894     @Test
testPrefixOrder_remove()895     public void testPrefixOrder_remove() {
896         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
897         final TestWindowContainer root = builder.build();
898 
899         final TestWindowContainer child1 = root.addChildWindow();
900 
901         final TestWindowContainer child11 = child1.addChildWindow();
902         final TestWindowContainer child12 = child1.addChildWindow();
903 
904         final TestWindowContainer child2 = root.addChildWindow();
905 
906         assertEquals(0, root.getPrefixOrderIndex());
907         assertEquals(1, child1.getPrefixOrderIndex());
908         assertEquals(2, child11.getPrefixOrderIndex());
909         assertEquals(3, child12.getPrefixOrderIndex());
910         assertEquals(4, child2.getPrefixOrderIndex());
911 
912         root.removeChild(child1);
913 
914         assertEquals(1, child2.getPrefixOrderIndex());
915     }
916 
917     /**
918      * Ensure children of a {@link WindowContainer} do not have
919      * {@link WindowContainer#onParentResize()} called when {@link WindowContainer#onParentResize()}
920      * is invoked with overridden bounds.
921      */
922     @Test
testOnParentResizePropagation()923     public void testOnParentResizePropagation() {
924         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
925         final TestWindowContainer root = builder.build();
926 
927         final TestWindowContainer child = root.addChildWindow();
928         child.setBounds(new Rect(1, 1, 2, 2));
929 
930         final TestWindowContainer grandChild = mock(TestWindowContainer.class);
931 
932         child.addChildWindow(grandChild);
933         root.onResize();
934 
935         // Make sure the child does not propagate resize through onParentResize when bounds are set.
936         verify(grandChild, never()).onParentResize();
937 
938         child.removeChild(grandChild);
939 
940         child.setBounds(null);
941         child.addChildWindow(grandChild);
942         root.onResize();
943 
944         // Make sure the child propagates resize through onParentResize when no bounds set.
945         verify(grandChild, times(1)).onParentResize();
946     }
947 
948     @Test
testOnDescendantOrientationRequestChangedPropagation()949     public void testOnDescendantOrientationRequestChangedPropagation() {
950         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
951         final TestWindowContainer root = spy(builder.build());
952 
953         final ActivityRecord activityRecord = mock(ActivityRecord.class);
954         final TestWindowContainer child = root.addChildWindow();
955 
956         child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, activityRecord);
957         verify(root).onDescendantOrientationChanged(activityRecord);
958     }
959 
960     @Test
testHandlesOrientationChangeFromDescendantProgation()961     public void testHandlesOrientationChangeFromDescendantProgation() {
962         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
963         final TestWindowContainer root = spy(builder.build());
964 
965         // We use an orientation that is not an exception for the ignoreOrientationRequest flag
966         final int orientation = SCREEN_ORIENTATION_PORTRAIT;
967 
968         final TestWindowContainer child = root.addChildWindow();
969         assertFalse(child.handlesOrientationChangeFromDescendant(orientation));
970 
971         Mockito.doReturn(true).when(root).handlesOrientationChangeFromDescendant(anyInt());
972         assertTrue(child.handlesOrientationChangeFromDescendant(orientation));
973     }
974 
975     @Test
testOnDisplayChanged()976     public void testOnDisplayChanged() {
977         final Task rootTask = createTask(mDisplayContent);
978         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
979         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
980 
981         final DisplayContent newDc = createNewDisplay();
982         rootTask.getDisplayArea().removeRootTask(rootTask);
983         newDc.getDefaultTaskDisplayArea().addChild(rootTask, POSITION_TOP);
984 
985         verify(rootTask).onDisplayChanged(newDc);
986         verify(task).onDisplayChanged(newDc);
987         verify(activity).onDisplayChanged(newDc);
988         assertEquals(newDc, rootTask.mDisplayContent);
989         assertEquals(newDc, task.mDisplayContent);
990         assertEquals(newDc, activity.mDisplayContent);
991     }
992 
993     @Test
testOnDisplayChanged_cleanupChanging()994     public void testOnDisplayChanged_cleanupChanging() {
995         final Task task = createTask(mDisplayContent);
996         spyOn(task.mSurfaceFreezer);
997         mDisplayContent.mChangingContainers.add(task);
998 
999         // Don't remove the changing transition of this window when it is still the old display.
1000         // This happens on display info changed.
1001         task.onDisplayChanged(mDisplayContent);
1002 
1003         assertTrue(mDisplayContent.mChangingContainers.contains(task));
1004         verify(task.mSurfaceFreezer, never()).unfreeze(any());
1005 
1006         // Remove the changing transition of this window when it is moved or reparented from the old
1007         // display.
1008         final DisplayContent newDc = createNewDisplay();
1009         task.onDisplayChanged(newDc);
1010 
1011         assertFalse(mDisplayContent.mChangingContainers.contains(task));
1012         verify(task.mSurfaceFreezer).unfreeze(any());
1013     }
1014 
1015     @Test
testHandleCompleteDeferredRemoval()1016     public void testHandleCompleteDeferredRemoval() {
1017         final DisplayContent displayContent = createNewDisplay();
1018         // Do not reparent activity to default display when removing the display.
1019         doReturn(true).when(displayContent).shouldDestroyContentOnRemove();
1020 
1021         // An animating window with mRemoveOnExit can be removed by handleCompleteDeferredRemoval
1022         // once it no longer animates.
1023         final WindowState exitingWindow = createWindow(null, TYPE_APPLICATION_OVERLAY,
1024                 displayContent, "exiting window");
1025         exitingWindow.startAnimation(exitingWindow.getPendingTransaction(),
1026                 mock(AnimationAdapter.class), false /* hidden */,
1027                 SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
1028         exitingWindow.mRemoveOnExit = true;
1029         exitingWindow.handleCompleteDeferredRemoval();
1030         // The animation has not finished so the window is not removed.
1031         assertTrue(exitingWindow.isAnimating());
1032         assertTrue(exitingWindow.isAttached());
1033         exitingWindow.cancelAnimation();
1034         // The window is removed because the animation is gone.
1035         exitingWindow.handleCompleteDeferredRemoval();
1036         assertFalse(exitingWindow.isAttached());
1037 
1038         final ActivityRecord r = new TaskBuilder(mSupervisor).setCreateActivity(true)
1039                 .setDisplay(displayContent).build().getTopMostActivity();
1040         // Add a window and make the activity animating so the removal of activity is deferred.
1041         createWindow(null, TYPE_BASE_APPLICATION, r, "win");
1042         doReturn(true).when(r).isAnimating(anyInt(), anyInt());
1043 
1044         displayContent.remove();
1045         // Ensure that ActivityRecord#onRemovedFromDisplay is called.
1046         r.destroyed("test");
1047         // The removal is deferred, so the activity is still in the display.
1048         assertEquals(r, displayContent.getTopMostActivity());
1049 
1050         // Assume the animation is done so the deferred removal can continue.
1051         doReturn(false).when(r).isAnimating(anyInt(), anyInt());
1052 
1053         assertFalse(displayContent.handleCompleteDeferredRemoval());
1054         assertFalse(displayContent.hasChild());
1055         assertFalse(r.hasChild());
1056     }
1057 
1058     @Test
testTaskCanApplyAnimation()1059     public void testTaskCanApplyAnimation() {
1060         final Task rootTask = createTask(mDisplayContent);
1061         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
1062         final ActivityRecord activity2 = createActivityRecord(mDisplayContent, task);
1063         final ActivityRecord activity1 = createActivityRecord(mDisplayContent, task);
1064         verifyWindowContainerApplyAnimation(task, activity1, activity2);
1065     }
1066 
1067     @Test
testRootTaskCanApplyAnimation()1068     public void testRootTaskCanApplyAnimation() {
1069         final Task rootTask = createTask(mDisplayContent);
1070         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
1071                 createTaskInRootTask(rootTask, 0 /* userId */));
1072         final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
1073                 createTaskInRootTask(rootTask, 0 /* userId */));
1074         verifyWindowContainerApplyAnimation(rootTask, activity1, activity2);
1075     }
1076 
1077     @Test
testGetDisplayArea()1078     public void testGetDisplayArea() {
1079         // WindowContainer
1080         final WindowContainer windowContainer = new WindowContainer(mWm);
1081 
1082         assertNull(windowContainer.getDisplayArea());
1083 
1084         // Task > WindowContainer
1085         final Task task = createTask(mDisplayContent);
1086         task.addChild(windowContainer, 0);
1087         task.setParent(null);
1088 
1089         assertNull(windowContainer.getDisplayArea());
1090         assertNull(task.getDisplayArea());
1091 
1092         // TaskDisplayArea > Task > WindowContainer
1093         final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(
1094                 mDisplayContent, mWm, "TaskDisplayArea", FEATURE_DEFAULT_TASK_CONTAINER);
1095         taskDisplayArea.addChild(task, 0);
1096 
1097         assertEquals(taskDisplayArea, windowContainer.getDisplayArea());
1098         assertEquals(taskDisplayArea, task.getDisplayArea());
1099         assertEquals(taskDisplayArea, taskDisplayArea.getDisplayArea());
1100 
1101         // DisplayArea
1102         final DisplayArea displayArea = new DisplayArea(mWm, ANY, "DisplayArea");
1103 
1104         assertEquals(displayArea, displayArea.getDisplayArea());
1105     }
1106 
verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act, ActivityRecord act2)1107     private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act,
1108             ActivityRecord act2) {
1109         // Initial remote animation for app transition.
1110         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
1111                 new IRemoteAnimationRunner.Stub() {
1112                     @Override
1113                     public void onAnimationStart(@WindowManager.TransitionOldType int transit,
1114                             RemoteAnimationTarget[] apps,
1115                             RemoteAnimationTarget[] wallpapers,
1116                             RemoteAnimationTarget[] nonApps,
1117                             IRemoteAnimationFinishedCallback finishedCallback) {
1118                         try {
1119                             finishedCallback.onAnimationFinished();
1120                         } catch (RemoteException e) {
1121                             e.printStackTrace();
1122                         }
1123                     }
1124 
1125                     @Override
1126                     public void onAnimationCancelled() {
1127                     }
1128                 }, 0, 0, false);
1129         adapter.setCallingPidUid(123, 456);
1130         wc.getDisplayContent().prepareAppTransition(TRANSIT_OPEN);
1131         wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter);
1132         spyOn(wc);
1133         doReturn(true).when(wc).okToAnimate();
1134 
1135         // Make sure animating state is as expected after applied animation.
1136 
1137         // Animation target is promoted from act to wc. act2 is a descendant of wc, but not a source
1138         // of the animation.
1139         ArrayList<WindowContainer<WindowState>> sources = new ArrayList<>();
1140         sources.add(act);
1141         assertTrue(wc.applyAnimation(null, TRANSIT_OLD_TASK_OPEN, true, false, sources));
1142 
1143         assertEquals(act, wc.getTopMostActivity());
1144         assertTrue(wc.isAnimating());
1145         assertTrue(wc.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION));
1146         assertTrue(wc.getAnimationSources().contains(act));
1147         assertFalse(wc.getAnimationSources().contains(act2));
1148         assertTrue(act.isAnimating(PARENTS));
1149         assertTrue(act.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
1150         assertEquals(wc, act.getAnimatingContainer(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
1151 
1152         // Make sure animation finish callback will be received and reset animating state after
1153         // animation finish.
1154         wc.getDisplayContent().mAppTransition.goodToGo(TRANSIT_OLD_TASK_OPEN, act);
1155         verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any());
1156         assertFalse(wc.isAnimating());
1157         assertFalse(act.isAnimating(PARENTS));
1158     }
1159 
1160     @Test
testRegisterWindowContainerListener()1161     public void testRegisterWindowContainerListener() {
1162         final WindowContainer container = new WindowContainer(mWm);
1163         container.mDisplayContent = mDisplayContent;
1164         final TestWindowContainerListener listener = new TestWindowContainerListener();
1165         Configuration config = container.getConfiguration();
1166         Rect bounds = new Rect(0, 0, 10, 10);
1167         config.windowConfiguration.setBounds(bounds);
1168         config.densityDpi = 100;
1169         container.onRequestedOverrideConfigurationChanged(config);
1170         container.registerWindowContainerListener(listener);
1171 
1172         assertEquals(mDisplayContent, listener.mDisplayContent);
1173         assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds());
1174         assertEquals(100, listener.mConfiguration.densityDpi);
1175 
1176         container.onDisplayChanged(mDefaultDisplay);
1177         assertEquals(listener.mDisplayContent, mDefaultDisplay);
1178 
1179         config = new Configuration();
1180         bounds = new Rect(0, 0, 20, 20);
1181         config.windowConfiguration.setBounds(bounds);
1182         config.densityDpi = 200;
1183 
1184         container.onRequestedOverrideConfigurationChanged(config);
1185 
1186         assertEquals(bounds, listener.mConfiguration.windowConfiguration.getBounds());
1187         assertEquals(200, listener.mConfiguration.densityDpi);
1188     }
1189 
1190     @Test
testFreezeInsets()1191     public void testFreezeInsets() {
1192         final Task task = createTask(mDisplayContent);
1193         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
1194         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
1195 
1196         // Set visibility to false, verify the main window of the task will be set the frozen
1197         // insets state immediately.
1198         activity.setVisibility(false);
1199         assertNotNull(win.getFrozenInsetsState());
1200 
1201         // Now make it visible again, verify that the insets are immediately unfrozen.
1202         activity.setVisibility(true);
1203         assertNull(win.getFrozenInsetsState());
1204     }
1205 
1206     @Test
testFreezeInsetsStateWhenAppTransition()1207     public void testFreezeInsetsStateWhenAppTransition() {
1208         final Task rootTask = createTask(mDisplayContent);
1209         final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
1210         final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
1211         final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
1212         task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE);
1213         spyOn(win);
1214         doReturn(true).when(task).okToAnimate();
1215         ArrayList<WindowContainer> sources = new ArrayList<>();
1216         sources.add(activity);
1217 
1218         // Simulate the task applying the exit transition, verify the main window of the task
1219         // will be set the frozen insets state before the animation starts
1220         activity.setVisibility(false);
1221         task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */,
1222                 false /* isVoiceInteraction */, sources);
1223         verify(win).freezeInsetsState();
1224 
1225         // Simulate the task transition finished.
1226         activity.commitVisibility(false, false);
1227         task.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION,
1228                 task.mSurfaceAnimator.getAnimation());
1229 
1230         // Now make it visible again, verify that the insets are immediately unfrozen even before
1231         // transition starts.
1232         activity.setVisibility(true);
1233         verify(win).clearFrozenInsetsState();
1234     }
1235 
1236     @Test
testAssignRelativeLayer()1237     public void testAssignRelativeLayer() {
1238         final WindowContainer container = new WindowContainer(mWm);
1239         container.mSurfaceControl = mock(SurfaceControl.class);
1240         final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
1241         final SurfaceControl relativeParent = mock(SurfaceControl.class);
1242         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
1243         spyOn(container);
1244         spyOn(surfaceAnimator);
1245 
1246         // Trigger for first relative layer call.
1247         container.assignRelativeLayer(t, relativeParent, 1 /* layer */);
1248         verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
1249 
1250         // Not trigger for the same relative layer call.
1251         clearInvocations(surfaceAnimator);
1252         container.assignRelativeLayer(t, relativeParent, 1 /* layer */);
1253         verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */);
1254 
1255         // Trigger for the same relative layer call if forceUpdate=true
1256         container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */);
1257         verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
1258     }
1259 
1260     @Test
testAssignAnimationLayer()1261     public void testAssignAnimationLayer() {
1262         final WindowContainer container = new WindowContainer(mWm);
1263         container.mSurfaceControl = mock(SurfaceControl.class);
1264         final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
1265         final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
1266         final SurfaceControl relativeParent = mock(SurfaceControl.class);
1267         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
1268         spyOn(container);
1269         spyOn(surfaceAnimator);
1270         spyOn(surfaceFreezer);
1271 
1272         container.setLayer(t, 1);
1273         container.setRelativeLayer(t, relativeParent, 2);
1274 
1275         // Set through surfaceAnimator if surfaceFreezer doesn't have leash.
1276         verify(surfaceAnimator).setLayer(t, 1);
1277         verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 2);
1278         verify(surfaceFreezer, never()).setLayer(any(), anyInt());
1279         verify(surfaceFreezer, never()).setRelativeLayer(any(), any(), anyInt());
1280 
1281         clearInvocations(surfaceAnimator);
1282         clearInvocations(surfaceFreezer);
1283         doReturn(true).when(surfaceFreezer).hasLeash();
1284 
1285         container.setLayer(t, 1);
1286         container.setRelativeLayer(t, relativeParent, 2);
1287 
1288         // Set through surfaceFreezer if surfaceFreezer has leash.
1289         verify(surfaceFreezer).setLayer(t, 1);
1290         verify(surfaceFreezer).setRelativeLayer(t, relativeParent, 2);
1291         verify(surfaceAnimator, never()).setLayer(any(), anyInt());
1292         verify(surfaceAnimator, never()).setRelativeLayer(any(), any(), anyInt());
1293     }
1294 
1295     @Test
testStartChangeTransitionWhenPreviousIsNotFinished()1296     public void testStartChangeTransitionWhenPreviousIsNotFinished() {
1297         final WindowContainer container = createTaskFragmentWithActivity(
1298                 createTask(mDisplayContent));
1299         container.mSurfaceControl = mock(SurfaceControl.class);
1300         final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
1301         final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
1302         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
1303         spyOn(container);
1304         spyOn(surfaceAnimator);
1305         mockSurfaceFreezerSnapshot(surfaceFreezer);
1306         doReturn(t).when(container).getPendingTransaction();
1307         doReturn(t).when(container).getSyncTransaction();
1308 
1309         // Leash and snapshot created for change transition.
1310         container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
1311 
1312         assertNotNull(surfaceFreezer.mLeash);
1313         assertNotNull(surfaceFreezer.mSnapshot);
1314         assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
1315 
1316         // Start animation: surfaceAnimator take over the leash and snapshot from surfaceFreezer.
1317         container.applyAnimationUnchecked(null /* lp */, true /* enter */,
1318                 TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */,
1319                 null /* sources */);
1320 
1321         assertNull(surfaceFreezer.mLeash);
1322         assertNull(surfaceFreezer.mSnapshot);
1323         assertNotNull(surfaceAnimator.mLeash);
1324         assertNotNull(surfaceAnimator.mSnapshot);
1325         final SurfaceControl prevLeash = surfaceAnimator.mLeash;
1326         final SurfaceFreezer.Snapshot prevSnapshot = surfaceAnimator.mSnapshot;
1327 
1328         // Prepare another change transition.
1329         container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
1330 
1331         assertNotNull(surfaceFreezer.mLeash);
1332         assertNotNull(surfaceFreezer.mSnapshot);
1333         assertEquals(surfaceFreezer.mLeash, container.getAnimationLeash());
1334         assertNotEquals(prevLeash, container.getAnimationLeash());
1335 
1336         // Start another animation before the previous one is finished, it should reset the previous
1337         // one, but not change the current one.
1338         container.applyAnimationUnchecked(null /* lp */, true /* enter */,
1339                 TRANSIT_OLD_TASK_FRAGMENT_CHANGE, false /* isVoiceInteraction */,
1340                 null /* sources */);
1341 
1342         verify(container, never()).onAnimationLeashLost(any());
1343         verify(surfaceFreezer, never()).unfreeze(any());
1344         assertNotNull(surfaceAnimator.mLeash);
1345         assertNotNull(surfaceAnimator.mSnapshot);
1346         assertEquals(surfaceAnimator.mLeash, container.getAnimationLeash());
1347         assertNotEquals(prevLeash, surfaceAnimator.mLeash);
1348         assertNotEquals(prevSnapshot, surfaceAnimator.mSnapshot);
1349 
1350         // Clean up after animation finished.
1351         surfaceAnimator.mInnerAnimationFinishedCallback.onAnimationFinished(
1352                 ANIMATION_TYPE_APP_TRANSITION, surfaceAnimator.getAnimation());
1353 
1354         verify(container).onAnimationLeashLost(any());
1355         assertNull(surfaceAnimator.mLeash);
1356         assertNull(surfaceAnimator.mSnapshot);
1357     }
1358 
1359     @Test
testUnfreezeWindow_removeWindowFromChanging()1360     public void testUnfreezeWindow_removeWindowFromChanging() {
1361         final WindowContainer container = createTaskFragmentWithActivity(
1362                 createTask(mDisplayContent));
1363         mockSurfaceFreezerSnapshot(container.mSurfaceFreezer);
1364         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
1365 
1366         container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
1367 
1368         assertTrue(mDisplayContent.mChangingContainers.contains(container));
1369 
1370         container.mSurfaceFreezer.unfreeze(t);
1371 
1372         assertFalse(mDisplayContent.mChangingContainers.contains(container));
1373     }
1374 
1375     @Test
testFailToTaskSnapshot_unfreezeWindow()1376     public void testFailToTaskSnapshot_unfreezeWindow() {
1377         final WindowContainer container = createTaskFragmentWithActivity(
1378                 createTask(mDisplayContent));
1379         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
1380         spyOn(container.mSurfaceFreezer);
1381 
1382         container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
1383 
1384         verify(container.mSurfaceFreezer).freeze(any(), any(), any(), any());
1385         verify(container.mSurfaceFreezer).unfreeze(any());
1386         assertTrue(mDisplayContent.mChangingContainers.isEmpty());
1387     }
1388 
1389     @Test
testRemoveUnstartedFreezeSurfaceWhenFreezeAgain()1390     public void testRemoveUnstartedFreezeSurfaceWhenFreezeAgain() {
1391         final WindowContainer container = createTaskFragmentWithActivity(
1392                 createTask(mDisplayContent));
1393         container.mSurfaceControl = mock(SurfaceControl.class);
1394         final SurfaceFreezer surfaceFreezer = container.mSurfaceFreezer;
1395         mockSurfaceFreezerSnapshot(surfaceFreezer);
1396         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
1397         spyOn(container);
1398         doReturn(t).when(container).getPendingTransaction();
1399         doReturn(t).when(container).getSyncTransaction();
1400 
1401         // Leash and snapshot created for change transition.
1402         container.initializeChangeTransition(new Rect(0, 0, 1000, 2000));
1403 
1404         assertNotNull(surfaceFreezer.mLeash);
1405         assertNotNull(surfaceFreezer.mSnapshot);
1406 
1407         final SurfaceControl prevLeash = surfaceFreezer.mLeash;
1408         final SurfaceFreezer.Snapshot prevSnapshot = surfaceFreezer.mSnapshot;
1409         spyOn(prevSnapshot);
1410 
1411         container.initializeChangeTransition(new Rect(0, 0, 1500, 2500));
1412 
1413         verify(t).remove(prevLeash);
1414         verify(prevSnapshot).destroy(t);
1415     }
1416 
1417     @Test
testAddLocalInsetsFrameProvider()1418     public void testAddLocalInsetsFrameProvider() {
1419          /*
1420                 ___ rootTask _______________________________________________
1421                |        |                |                                  |
1422           activity0    container     navigationBarInsetsProvider1    navigationBarInsetsProvider2
1423                        /       \
1424                activity1    activity2
1425          */
1426         final Task rootTask = createTask(mDisplayContent);
1427 
1428         final ActivityRecord activity0 = createActivityRecord(mDisplayContent,
1429                 createTaskInRootTask(rootTask, 0 /* userId */));
1430         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
1431                 TYPE_BASE_APPLICATION);
1432         attrs.setTitle("AppWindow0");
1433         activity0.addWindow(createWindowState(attrs, activity0));
1434 
1435         final Task container = createTaskInRootTask(rootTask, 0);
1436         final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
1437                 createTaskInRootTask(container, 0 /* userId */));
1438         final WindowManager.LayoutParams attrs1 = new WindowManager.LayoutParams(
1439                 TYPE_BASE_APPLICATION);
1440         attrs1.setTitle("AppWindow1");
1441         activity1.addWindow(createWindowState(attrs1, activity1));
1442 
1443         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
1444                 createTaskInRootTask(container, 0 /* userId */));
1445         final WindowManager.LayoutParams attrs2 = new WindowManager.LayoutParams(
1446                 TYPE_BASE_APPLICATION);
1447         attrs2.setTitle("AppWindow2");
1448         activity2.addWindow(createWindowState(attrs2, activity2));
1449         final Binder owner = new Binder();
1450         Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
1451         Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200);
1452         final InsetsFrameProvider provider1 =
1453                 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
1454                         .setArbitraryRectangle(genericOverlayInsetsRect1);
1455         final InsetsFrameProvider provider2 =
1456                 new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays())
1457                         .setArbitraryRectangle(genericOverlayInsetsRect2);
1458         final int sourceId1 = provider1.getId();
1459         final int sourceId2 = provider2.getId();
1460 
1461         rootTask.addLocalInsetsFrameProvider(provider1, owner);
1462         container.addLocalInsetsFrameProvider(provider2, owner);
1463 
1464         InsetsSource genericOverlayInsetsProvider1Source = new InsetsSource(
1465                 sourceId1, systemOverlays());
1466         genericOverlayInsetsProvider1Source.setFrame(genericOverlayInsetsRect1);
1467         genericOverlayInsetsProvider1Source.setVisible(true);
1468         InsetsSource genericOverlayInsetsProvider2Source = new InsetsSource(
1469                 sourceId2, systemOverlays());
1470         genericOverlayInsetsProvider2Source.setFrame(genericOverlayInsetsRect2);
1471         genericOverlayInsetsProvider2Source.setVisible(true);
1472 
1473         activity0.forAllWindows(window -> {
1474             assertEquals(genericOverlayInsetsRect1,
1475                     window.getInsetsState().peekSource(sourceId1).getFrame());
1476             assertEquals(null,
1477                     window.getInsetsState().peekSource(sourceId2));
1478         }, true);
1479         activity1.forAllWindows(window -> {
1480             assertEquals(genericOverlayInsetsRect1,
1481                     window.getInsetsState().peekSource(sourceId1).getFrame());
1482             assertEquals(genericOverlayInsetsRect2,
1483                     window.getInsetsState().peekSource(sourceId2).getFrame());
1484         }, true);
1485         activity2.forAllWindows(window -> {
1486             assertEquals(genericOverlayInsetsRect1,
1487                     window.getInsetsState().peekSource(sourceId1).getFrame());
1488             assertEquals(genericOverlayInsetsRect2,
1489                     window.getInsetsState().peekSource(sourceId2).getFrame());
1490         }, true);
1491     }
1492 
1493     @Test
testAddLocalInsetsFrameProvider_sameType_replacesInsets()1494     public void testAddLocalInsetsFrameProvider_sameType_replacesInsets() {
1495          /*
1496                 ___ rootTask ________________________________________
1497                |                  |                                  |
1498           activity0      genericOverlayInsetsProvider1    genericOverlayInsetsProvider2
1499          */
1500         final Task rootTask = createTask(mDisplayContent);
1501 
1502         final ActivityRecord activity0 = createActivityRecord(mDisplayContent,
1503                 createTaskInRootTask(rootTask, 0 /* userId */));
1504         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
1505                 TYPE_BASE_APPLICATION);
1506         attrs.setTitle("AppWindow0");
1507         activity0.addWindow(createWindowState(attrs, activity0));
1508 
1509         final Binder owner = new Binder();
1510         final Rect genericOverlayInsetsRect1 = new Rect(0, 200, 1080, 700);
1511         final Rect genericOverlayInsetsRect2 = new Rect(0, 0, 1080, 200);
1512         final InsetsFrameProvider provider1 =
1513                 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
1514                         .setArbitraryRectangle(genericOverlayInsetsRect1);
1515         final InsetsFrameProvider provider2 =
1516                 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
1517                         .setArbitraryRectangle(genericOverlayInsetsRect2);
1518         final int sourceId1 = provider1.getId();
1519         final int sourceId2 = provider2.getId();
1520 
1521         rootTask.addLocalInsetsFrameProvider(provider1, owner);
1522         activity0.forAllWindows(window -> {
1523             assertEquals(genericOverlayInsetsRect1,
1524                     window.getInsetsState().peekSource(sourceId1).getFrame());
1525         }, true);
1526 
1527         rootTask.addLocalInsetsFrameProvider(provider2, owner);
1528 
1529         activity0.forAllWindows(window -> {
1530             assertEquals(genericOverlayInsetsRect2,
1531                     window.getInsetsState().peekSource(sourceId2).getFrame());
1532         }, true);
1533     }
1534 
1535     @Test
testRemoveLocalInsetsFrameProvider()1536     public void testRemoveLocalInsetsFrameProvider() {
1537          /*
1538                 ___ rootTask _______________________________________________
1539                |        |                |                                  |
1540           activity0    container    navigationBarInsetsProvider1     navigationBarInsetsProvider2
1541                        /       \
1542                activity1    activity2
1543          */
1544         final Task rootTask = createTask(mDisplayContent);
1545 
1546         final ActivityRecord activity0 = createActivityRecord(mDisplayContent,
1547                 createTaskInRootTask(rootTask, 0 /* userId */));
1548         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
1549                 TYPE_BASE_APPLICATION);
1550         attrs.setTitle("AppWindow0");
1551         activity0.addWindow(createWindowState(attrs, activity0));
1552 
1553         final Task container = createTaskInRootTask(rootTask, 0);
1554         final ActivityRecord activity1 = createActivityRecord(mDisplayContent,
1555                 createTaskInRootTask(container, 0 /* userId */));
1556         final WindowManager.LayoutParams attrs1 = new WindowManager.LayoutParams(
1557                 TYPE_BASE_APPLICATION);
1558         attrs1.setTitle("AppWindow1");
1559         activity1.addWindow(createWindowState(attrs1, activity1));
1560 
1561         final ActivityRecord activity2 = createActivityRecord(mDisplayContent,
1562                 createTaskInRootTask(container, 0 /* userId */));
1563         final WindowManager.LayoutParams attrs2 = new WindowManager.LayoutParams(
1564                 TYPE_BASE_APPLICATION);
1565         attrs2.setTitle("AppWindow2");
1566         activity2.addWindow(createWindowState(attrs2, activity2));
1567 
1568         activity2.addWindow(createWindowState(attrs2, activity2));
1569 
1570         final Binder owner = new Binder();
1571         final Rect navigationBarInsetsRect1 = new Rect(0, 200, 1080, 700);
1572         final Rect navigationBarInsetsRect2 = new Rect(0, 0, 1080, 200);
1573         final InsetsFrameProvider provider1 =
1574                 new InsetsFrameProvider(owner, 1, WindowInsets.Type.systemOverlays())
1575                         .setArbitraryRectangle(navigationBarInsetsRect1);
1576         final InsetsFrameProvider provider2 =
1577                 new InsetsFrameProvider(owner, 2, WindowInsets.Type.systemOverlays())
1578                         .setArbitraryRectangle(navigationBarInsetsRect2);
1579         final int sourceId1 = provider1.getId();
1580         final int sourceId2 = provider2.getId();
1581 
1582         rootTask.addLocalInsetsFrameProvider(provider1, owner);
1583         container.addLocalInsetsFrameProvider(provider2, owner);
1584         mDisplayContent.getInsetsStateController().onPostLayout();
1585         rootTask.removeLocalInsetsFrameProvider(provider1, owner);
1586         mDisplayContent.getInsetsStateController().onPostLayout();
1587 
1588         activity0.forAllWindows(window -> {
1589             assertEquals(null,
1590                     window.getInsetsState().peekSource(sourceId1));
1591             assertEquals(null,
1592                     window.getInsetsState().peekSource(sourceId2));
1593         }, true);
1594         activity1.forAllWindows(window -> {
1595             assertEquals(null,
1596                     window.getInsetsState().peekSource(sourceId1));
1597             assertEquals(navigationBarInsetsRect2,
1598                     window.getInsetsState().peekSource(sourceId2)
1599                                     .getFrame());
1600         }, true);
1601         activity2.forAllWindows(window -> {
1602             assertEquals(null,
1603                     window.getInsetsState().peekSource(sourceId1));
1604             assertEquals(navigationBarInsetsRect2,
1605                     window.getInsetsState().peekSource(sourceId2)
1606                             .getFrame());
1607         }, true);
1608     }
1609 
1610     @Test
testAddLocalInsetsFrameProvider_ownerDiesAfterAdding()1611     public void testAddLocalInsetsFrameProvider_ownerDiesAfterAdding() {
1612         final Task task = createTask(mDisplayContent);
1613         final TestBinder owner = new TestBinder();
1614         final InsetsFrameProvider provider =
1615                 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
1616                         .setArbitraryRectangle(new Rect());
1617         task.addLocalInsetsFrameProvider(provider, owner);
1618 
1619         assertTrue("The death recipient must exist.", owner.hasDeathRecipient());
1620         assertTrue("The source must be added.", hasLocalSource(task, provider.getId()));
1621 
1622         // The owner dies after adding the source.
1623         owner.die();
1624 
1625         assertFalse("The death recipient must be removed.", owner.hasDeathRecipient());
1626         assertFalse("The source must be removed.", hasLocalSource(task, provider.getId()));
1627     }
1628 
1629     @Test
testAddLocalInsetsFrameProvider_ownerDiesBeforeAdding()1630     public void testAddLocalInsetsFrameProvider_ownerDiesBeforeAdding() {
1631         final Task task = createTask(mDisplayContent);
1632         final TestBinder owner = new TestBinder();
1633 
1634         // The owner dies before adding the source.
1635         owner.die();
1636 
1637         final InsetsFrameProvider provider =
1638                 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
1639                         .setArbitraryRectangle(new Rect());
1640         task.addLocalInsetsFrameProvider(provider, owner);
1641 
1642         assertFalse("The death recipient must not exist.", owner.hasDeathRecipient());
1643         assertFalse("The source must not be added.", hasLocalSource(task, provider.getId()));
1644     }
1645 
1646     @Test
testRemoveLocalInsetsFrameProvider_removeDeathRecipient()1647     public void testRemoveLocalInsetsFrameProvider_removeDeathRecipient() {
1648         final Task task = createTask(mDisplayContent);
1649         final TestBinder owner = new TestBinder();
1650         final InsetsFrameProvider provider =
1651                 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemOverlays())
1652                         .setArbitraryRectangle(new Rect());
1653         task.addLocalInsetsFrameProvider(provider, owner);
1654 
1655         assertTrue("The death recipient must exist.", owner.hasDeathRecipient());
1656         assertTrue("The source must be added.", hasLocalSource(task, provider.getId()));
1657 
1658         task.removeLocalInsetsFrameProvider(provider, owner);
1659 
1660         assertFalse("The death recipient must be removed.", owner.hasDeathRecipient());
1661         assertFalse("The source must be removed.", hasLocalSource(task, provider.getId()));
1662     }
1663 
hasLocalSource(WindowContainer container, int sourceId)1664     private static boolean hasLocalSource(WindowContainer container, int sourceId) {
1665         if (container.mLocalInsetsSources == null) {
1666             return false;
1667         }
1668         return container.mLocalInsetsSources.contains(sourceId);
1669     }
1670 
1671     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
1672     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
1673         private final int mLayer;
1674         private boolean mIsAnimating;
1675         private boolean mIsVisible;
1676         private boolean mFillsParent;
1677         private boolean mWaitForTransitStart;
1678         private Integer mOrientation;
1679 
1680         private boolean mOnParentChangedCalled;
1681         private boolean mOnDescendantOverrideCalled;
1682 
1683         /**
1684          * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
1685          * of z-order and 1 otherwise.
1686          */
1687         private static final Comparator<TestWindowContainer> SUBLAYER_COMPARATOR = (w1, w2) -> {
1688             final int layer1 = w1.mLayer;
1689             final int layer2 = w2.mLayer;
1690             if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0)) {
1691                 // We insert the child window into the list ordered by the mLayer. For same layers,
1692                 // the negative one should go below others; the positive one should go above others.
1693                 return -1;
1694             }
1695             if (layer1 == layer2) return 0;
1696             return 1;
1697         };
1698 
TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating, boolean isVisible, boolean waitTransitStart, Integer orientation)1699         TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating,
1700                 boolean isVisible, boolean waitTransitStart, Integer orientation) {
1701             super(wm);
1702 
1703             mLayer = layer;
1704             mIsAnimating = isAnimating;
1705             mIsVisible = isVisible;
1706             mFillsParent = true;
1707             mOrientation = orientation;
1708             mWaitForTransitStart = waitTransitStart;
1709             spyOn(mSurfaceAnimator);
1710             doReturn(mIsAnimating).when(mSurfaceAnimator).isAnimating();
1711             doReturn(ANIMATION_TYPE_APP_TRANSITION).when(mSurfaceAnimator).getAnimationType();
1712         }
1713 
getParentWindow()1714         TestWindowContainer getParentWindow() {
1715             return (TestWindowContainer) getParent();
1716         }
1717 
getChildrenCount()1718         int getChildrenCount() {
1719             return mChildren.size();
1720         }
1721 
addChildWindow(TestWindowContainer child)1722         TestWindowContainer addChildWindow(TestWindowContainer child) {
1723             addChild(child, SUBLAYER_COMPARATOR);
1724             return child;
1725         }
1726 
addChildWindow(TestWindowContainerBuilder childBuilder)1727         TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
1728             TestWindowContainer child = childBuilder.build();
1729             addChild(child, SUBLAYER_COMPARATOR);
1730             return child;
1731         }
1732 
addChildWindow()1733         TestWindowContainer addChildWindow() {
1734             return addChildWindow(new TestWindowContainerBuilder(mWmService).setLayer(1));
1735         }
1736 
1737         @Override
onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)1738         void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
1739             mOnParentChangedCalled = true;
1740         }
1741 
1742         @Override
onDescendantOverrideConfigurationChanged()1743         void onDescendantOverrideConfigurationChanged() {
1744             mOnDescendantOverrideCalled = true;
1745             super.onDescendantOverrideConfigurationChanged();
1746         }
1747 
1748         @Override
isVisible()1749         boolean isVisible() {
1750             return mIsVisible;
1751         }
1752 
1753         @Override
getOrientation(int candidate)1754         int getOrientation(int candidate) {
1755             return mOrientation != null ? mOrientation : super.getOrientation(candidate);
1756         }
1757 
1758         @Override
getOrientation()1759         int getOrientation() {
1760             return getOrientation(super.getOverrideOrientation());
1761         }
1762 
1763         @Override
fillsParent()1764         boolean fillsParent() {
1765             return mFillsParent;
1766         }
1767 
setFillsParent(boolean fillsParent)1768         void setFillsParent(boolean fillsParent) {
1769             mFillsParent = fillsParent;
1770         }
1771 
1772         @Override
isWaitingForTransitionStart()1773         boolean isWaitingForTransitionStart() {
1774             return mWaitForTransitStart;
1775         }
1776     }
1777 
1778     private static class TestWindowContainerBuilder {
1779         private final WindowManagerService mWm;
1780         private int mLayer;
1781         private boolean mIsAnimating;
1782         private boolean mIsVisible;
1783         private boolean mIsWaitTransitStart;
1784         private Integer mOrientation;
1785 
TestWindowContainerBuilder(WindowManagerService wm)1786         TestWindowContainerBuilder(WindowManagerService wm) {
1787             mWm = wm;
1788             mLayer = 0;
1789             mIsAnimating = false;
1790             mIsVisible = false;
1791             mOrientation = null;
1792         }
1793 
setLayer(int layer)1794         TestWindowContainerBuilder setLayer(int layer) {
1795             mLayer = layer;
1796             return this;
1797         }
1798 
setIsAnimating(boolean isAnimating)1799         TestWindowContainerBuilder setIsAnimating(boolean isAnimating) {
1800             mIsAnimating = isAnimating;
1801             return this;
1802         }
1803 
setIsVisible(boolean isVisible)1804         TestWindowContainerBuilder setIsVisible(boolean isVisible) {
1805             mIsVisible = isVisible;
1806             return this;
1807         }
1808 
setOrientation(int orientation)1809         TestWindowContainerBuilder setOrientation(int orientation) {
1810             mOrientation = orientation;
1811             return this;
1812         }
1813 
setWaitForTransitionStart(boolean waitTransitStart)1814         TestWindowContainerBuilder setWaitForTransitionStart(boolean waitTransitStart) {
1815             mIsWaitTransitStart = waitTransitStart;
1816             return this;
1817         }
1818 
build()1819         TestWindowContainer build() {
1820             return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible,
1821                     mIsWaitTransitStart, mOrientation);
1822         }
1823     }
1824 
1825     private static class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer>
1826             implements AutoCloseable {
1827         private final SurfaceSession mSession = new SurfaceSession();
1828 
MockSurfaceBuildingContainer(WindowManagerService wm)1829         MockSurfaceBuildingContainer(WindowManagerService wm) {
1830             super(wm);
1831         }
1832 
1833         static class MockSurfaceBuilder extends SurfaceControl.Builder {
MockSurfaceBuilder(SurfaceSession ss)1834             MockSurfaceBuilder(SurfaceSession ss) {
1835                 super(ss);
1836             }
1837 
1838             @Override
build()1839             public SurfaceControl build() {
1840                 return mock(SurfaceControl.class);
1841             }
1842         }
1843 
1844         @Override
makeChildSurface(WindowContainer child)1845         SurfaceControl.Builder makeChildSurface(WindowContainer child) {
1846             return new MockSurfaceBuilder(mSession);
1847         }
1848 
1849         @Override
close()1850         public void close() {
1851             mSession.kill();
1852         }
1853     }
1854 
1855     private static class TestWindowContainerListener implements WindowContainerListener {
1856         private Configuration mConfiguration = new Configuration();
1857         private DisplayContent mDisplayContent;
1858         private boolean mIsVisibleRequested;
1859 
1860         @Override
onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration)1861         public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
1862             mConfiguration.setTo(overrideConfiguration);
1863         }
1864 
1865         @Override
onDisplayChanged(DisplayContent dc)1866         public void onDisplayChanged(DisplayContent dc) {
1867             mDisplayContent = dc;
1868         }
1869 
1870         @Override
onVisibleRequestedChanged(boolean isVisibleRequested)1871         public void onVisibleRequestedChanged(boolean isVisibleRequested) {
1872             mIsVisibleRequested = isVisibleRequested;
1873         }
1874     }
1875 
1876     private static class TestBinder implements IBinder {
1877 
1878         private boolean mDead;
1879         private final ArrayList<IBinder.DeathRecipient> mDeathRecipients = new ArrayList<>();
1880 
die()1881         public void die() {
1882             mDead = true;
1883             for (int i = mDeathRecipients.size() - 1; i >= 0; i--) {
1884                 final DeathRecipient recipient = mDeathRecipients.get(i);
1885                 recipient.binderDied(this);
1886             }
1887         }
1888 
hasDeathRecipient()1889         public boolean hasDeathRecipient() {
1890             return !mDeathRecipients.isEmpty();
1891         }
1892 
1893         @Override
linkToDeath(@onNull DeathRecipient recipient, int flags)1894         public void linkToDeath(@NonNull DeathRecipient recipient, int flags)
1895                 throws RemoteException {
1896             if (mDead) {
1897                 throw new DeadObjectException();
1898             }
1899             mDeathRecipients.add(recipient);
1900         }
1901 
1902         @Override
unlinkToDeath(@onNull DeathRecipient recipient, int flags)1903         public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
1904             final boolean successes = mDeathRecipients.remove(recipient);
1905             if (successes || mDead) {
1906                 return successes;
1907             }
1908             throw new NoSuchElementException("Given recipient has not been registered.");
1909         }
1910 
1911         @Override
isBinderAlive()1912         public boolean isBinderAlive() {
1913             return !mDead;
1914         }
1915 
1916         @Override
pingBinder()1917         public boolean pingBinder() {
1918             return !mDead;
1919         }
1920 
1921         @Nullable
1922         @Override
getInterfaceDescriptor()1923         public String getInterfaceDescriptor() throws RemoteException {
1924             return null;
1925         }
1926 
1927         @Nullable
1928         @Override
queryLocalInterface(@onNull String descriptor)1929         public IInterface queryLocalInterface(@NonNull String descriptor) {
1930             return null;
1931         }
1932 
1933         @Override
dump(@onNull FileDescriptor fd, @Nullable String[] args)1934         public void dump(@NonNull FileDescriptor fd, @Nullable String[] args)
1935                 throws RemoteException { }
1936 
1937         @Override
dumpAsync(@onNull FileDescriptor fd, @Nullable String[] args)1938         public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args)
1939                 throws RemoteException { }
1940 
1941         @Override
shellCommand(@ullable FileDescriptor in, @Nullable FileDescriptor out, @Nullable FileDescriptor err, @NonNull String[] args, @Nullable ShellCallback shellCallback, @NonNull ResultReceiver resultReceiver)1942         public void shellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
1943                 @Nullable FileDescriptor err, @NonNull String[] args,
1944                 @Nullable ShellCallback shellCallback,
1945                 @NonNull ResultReceiver resultReceiver) throws RemoteException { }
1946 
1947         @Override
transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)1948         public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
1949                 throws RemoteException {
1950             return false;
1951         }
1952     }
1953 }
1954