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.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
24 
25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyFloat;
27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
28 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
33 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
34 import static com.android.server.wm.WindowContainer.POSITION_TOP;
35 
36 import static org.junit.Assert.assertEquals;
37 import static org.junit.Assert.assertFalse;
38 import static org.junit.Assert.assertNotNull;
39 import static org.junit.Assert.assertNull;
40 import static org.junit.Assert.assertTrue;
41 
42 import android.content.pm.ActivityInfo;
43 import android.content.res.Configuration;
44 import android.graphics.Rect;
45 import android.os.IBinder;
46 import android.platform.test.annotations.Presubmit;
47 import android.view.SurfaceControl;
48 import android.view.SurfaceSession;
49 
50 import androidx.test.filters.SmallTest;
51 
52 import org.junit.Test;
53 import org.mockito.Mockito;
54 
55 import java.util.Comparator;
56 
57 /**
58  * Test class for {@link WindowContainer}.
59  *
60  * Build/Install/Run:
61  *  atest WmTests:WindowContainerTests
62  */
63 @SmallTest
64 @Presubmit
65 public class WindowContainerTests extends WindowTestsBase {
66 
67     @Test
testCreation()68     public void testCreation() {
69         final TestWindowContainer w = new TestWindowContainerBuilder(mWm).setLayer(0).build();
70         assertNull("window must have no parent", w.getParentWindow());
71         assertEquals("window must have no children", 0, w.getChildrenCount());
72     }
73 
74     @Test
testAdd()75     public void testAdd() {
76         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
77         final TestWindowContainer root = builder.setLayer(0).build();
78 
79         final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1));
80         final TestWindowContainer secondLayer1 = root.addChildWindow(builder.setLayer(1));
81         final TestWindowContainer layer2 = root.addChildWindow(builder.setLayer(2));
82         final TestWindowContainer layerNeg1 = root.addChildWindow(builder.setLayer(-1));
83         final TestWindowContainer layerNeg2 = root.addChildWindow(builder.setLayer(-2));
84         final TestWindowContainer secondLayerNeg1 = root.addChildWindow(builder.setLayer(-1));
85         final TestWindowContainer layer0 = root.addChildWindow(builder.setLayer(0));
86 
87         assertEquals(7, root.getChildrenCount());
88 
89         assertEquals(root, layer1.getParentWindow());
90         assertEquals(root, secondLayer1.getParentWindow());
91         assertEquals(root, layer2.getParentWindow());
92         assertEquals(root, layerNeg1.getParentWindow());
93         assertEquals(root, layerNeg2.getParentWindow());
94         assertEquals(root, secondLayerNeg1.getParentWindow());
95         assertEquals(root, layer0.getParentWindow());
96 
97         assertEquals(layerNeg2, root.getChildAt(0));
98         assertEquals(secondLayerNeg1, root.getChildAt(1));
99         assertEquals(layerNeg1, root.getChildAt(2));
100         assertEquals(layer0, root.getChildAt(3));
101         assertEquals(layer1, root.getChildAt(4));
102         assertEquals(secondLayer1, root.getChildAt(5));
103         assertEquals(layer2, root.getChildAt(6));
104 
105         assertTrue(layer1.mOnParentChangedCalled);
106         assertTrue(secondLayer1.mOnParentChangedCalled);
107         assertTrue(layer2.mOnParentChangedCalled);
108         assertTrue(layerNeg1.mOnParentChangedCalled);
109         assertTrue(layerNeg2.mOnParentChangedCalled);
110         assertTrue(secondLayerNeg1.mOnParentChangedCalled);
111         assertTrue(layer0.mOnParentChangedCalled);
112     }
113 
114     @Test
testAddChildSetsSurfacePosition()115     public void testAddChildSetsSurfacePosition() {
116         try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
117 
118             final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
119             mWm.mTransactionFactory = () -> transaction;
120 
121             WindowContainer child = new WindowContainer(mWm);
122             child.setBounds(1, 1, 10, 10);
123 
124             verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
125             top.addChild(child, 0);
126             verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
127         }
128     }
129 
130     @Test
testAdd_AlreadyHasParent()131     public void testAdd_AlreadyHasParent() {
132         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
133         final TestWindowContainer root = builder.setLayer(0).build();
134 
135         final TestWindowContainer child1 = root.addChildWindow();
136         final TestWindowContainer child2 = root.addChildWindow();
137 
138         boolean gotException = false;
139         try {
140             child1.addChildWindow(child2);
141         } catch (IllegalArgumentException e) {
142             gotException = true;
143         }
144         assertTrue(gotException);
145 
146         gotException = false;
147         try {
148             root.addChildWindow(child2);
149         } catch (IllegalArgumentException e) {
150             gotException = true;
151         }
152         assertTrue(gotException);
153     }
154 
155     @Test
testHasChild()156     public void testHasChild() {
157         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
158         final TestWindowContainer root = builder.setLayer(0).build();
159 
160         final TestWindowContainer child1 = root.addChildWindow();
161         final TestWindowContainer child2 = root.addChildWindow();
162         final TestWindowContainer child11 = child1.addChildWindow();
163         final TestWindowContainer child12 = child1.addChildWindow();
164         final TestWindowContainer child21 = child2.addChildWindow();
165 
166         assertEquals(2, root.getChildrenCount());
167         assertEquals(2, child1.getChildrenCount());
168         assertEquals(1, child2.getChildrenCount());
169 
170         assertTrue(root.hasChild(child1));
171         assertTrue(root.hasChild(child2));
172         assertTrue(root.hasChild(child11));
173         assertTrue(root.hasChild(child12));
174         assertTrue(root.hasChild(child21));
175 
176         assertTrue(child1.hasChild(child11));
177         assertTrue(child1.hasChild(child12));
178         assertFalse(child1.hasChild(child21));
179 
180         assertTrue(child2.hasChild(child21));
181         assertFalse(child2.hasChild(child11));
182         assertFalse(child2.hasChild(child12));
183     }
184 
185     @Test
testRemoveImmediately()186     public void testRemoveImmediately() {
187         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
188         final TestWindowContainer root = builder.setLayer(0).build();
189 
190         final TestWindowContainer child1 = root.addChildWindow();
191         final TestWindowContainer child2 = root.addChildWindow();
192         final TestWindowContainer child11 = child1.addChildWindow();
193         final TestWindowContainer child12 = child1.addChildWindow();
194         final TestWindowContainer child21 = child2.addChildWindow();
195 
196         assertNotNull(child12.getParentWindow());
197         child12.removeImmediately();
198         assertNull(child12.getParentWindow());
199         assertEquals(1, child1.getChildrenCount());
200         assertFalse(child1.hasChild(child12));
201         assertFalse(root.hasChild(child12));
202 
203         assertTrue(root.hasChild(child2));
204         assertNotNull(child2.getParentWindow());
205         child2.removeImmediately();
206         assertNull(child2.getParentWindow());
207         assertNull(child21.getParentWindow());
208         assertEquals(0, child2.getChildrenCount());
209         assertEquals(1, root.getChildrenCount());
210         assertFalse(root.hasChild(child2));
211         assertFalse(root.hasChild(child21));
212 
213         assertTrue(root.hasChild(child1));
214         assertTrue(root.hasChild(child11));
215 
216         root.removeImmediately();
217         assertEquals(0, root.getChildrenCount());
218     }
219 
220     @Test
testRemoveImmediately_WithController()221     public void testRemoveImmediately_WithController() {
222         final WindowContainer container = new WindowContainer(mWm);
223         final WindowContainerController controller = new WindowContainerController<>(null, mWm);
224 
225         container.setController(controller);
226         assertEquals(controller, container.getController());
227         assertEquals(container, controller.mContainer);
228 
229         container.removeImmediately();
230         assertNull(container.getController());
231         assertNull(controller.mContainer);
232     }
233 
234     @Test
testSetController()235     public void testSetController() {
236         final WindowContainerController controller = new WindowContainerController<>(null, mWm);
237         final WindowContainer container = new WindowContainer(mWm);
238 
239         container.setController(controller);
240         assertEquals(controller, container.getController());
241         assertEquals(container, controller.mContainer);
242 
243         // Assert we can't change the controller to another one once set
244         boolean gotException = false;
245         try {
246             container.setController(new WindowContainerController<>(null, mWm));
247         } catch (IllegalArgumentException e) {
248             gotException = true;
249         }
250         assertTrue(gotException);
251 
252         // Assert that we can set the controller to null.
253         container.setController(null);
254         assertNull(container.getController());
255         assertNull(controller.mContainer);
256     }
257 
258     @Test
testAddChildByIndex()259     public void testAddChildByIndex() {
260         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
261         final TestWindowContainer root = builder.setLayer(0).build();
262 
263         final TestWindowContainer child = root.addChildWindow();
264 
265         final TestWindowContainer child2 = builder.setLayer(1).build();
266         final TestWindowContainer child3 = builder.setLayer(2).build();
267         final TestWindowContainer child4 = builder.setLayer(3).build();
268 
269         // Test adding at top.
270         root.addChild(child2, POSITION_TOP);
271         assertEquals(child2, root.getChildAt(root.getChildrenCount() - 1));
272 
273         // Test adding at bottom.
274         root.addChild(child3, POSITION_BOTTOM);
275         assertEquals(child3, root.getChildAt(0));
276 
277         // Test adding in the middle.
278         root.addChild(child4, 1);
279         assertEquals(child3, root.getChildAt(0));
280         assertEquals(child4, root.getChildAt(1));
281         assertEquals(child, root.getChildAt(2));
282         assertEquals(child2, root.getChildAt(3));
283     }
284 
285     @Test
testPositionChildAt()286     public void testPositionChildAt() {
287         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
288         final TestWindowContainer root = builder.setLayer(0).build();
289 
290         final TestWindowContainer child1 = root.addChildWindow();
291         final TestWindowContainer child2 = root.addChildWindow();
292         final TestWindowContainer child3 = root.addChildWindow();
293 
294         // Test position at top.
295         root.positionChildAt(POSITION_TOP, child1, false /* includingParents */);
296         assertEquals(child1, root.getChildAt(root.getChildrenCount() - 1));
297 
298         // Test position at bottom.
299         root.positionChildAt(POSITION_BOTTOM, child1, false /* includingParents */);
300         assertEquals(child1, root.getChildAt(0));
301 
302         // Test position in the middle.
303         root.positionChildAt(1, child3, false /* includingParents */);
304         assertEquals(child1, root.getChildAt(0));
305         assertEquals(child3, root.getChildAt(1));
306         assertEquals(child2, root.getChildAt(2));
307     }
308 
309     @Test
testPositionChildAtIncludeParents()310     public void testPositionChildAtIncludeParents() {
311         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
312         final TestWindowContainer root = builder.setLayer(0).build();
313 
314         final TestWindowContainer child1 = root.addChildWindow();
315         final TestWindowContainer child2 = root.addChildWindow();
316         final TestWindowContainer child11 = child1.addChildWindow();
317         final TestWindowContainer child12 = child1.addChildWindow();
318         final TestWindowContainer child13 = child1.addChildWindow();
319         final TestWindowContainer child21 = child2.addChildWindow();
320         final TestWindowContainer child22 = child2.addChildWindow();
321         final TestWindowContainer child23 = child2.addChildWindow();
322 
323         // Test moving to top.
324         child1.positionChildAt(POSITION_TOP, child11, true /* includingParents */);
325         assertEquals(child12, child1.getChildAt(0));
326         assertEquals(child13, child1.getChildAt(1));
327         assertEquals(child11, child1.getChildAt(2));
328         assertEquals(child2, root.getChildAt(0));
329         assertEquals(child1, root.getChildAt(1));
330 
331         // Test moving to bottom.
332         child1.positionChildAt(POSITION_BOTTOM, child11, true /* includingParents */);
333         assertEquals(child11, child1.getChildAt(0));
334         assertEquals(child12, child1.getChildAt(1));
335         assertEquals(child13, child1.getChildAt(2));
336         assertEquals(child1, root.getChildAt(0));
337         assertEquals(child2, root.getChildAt(1));
338 
339         // Test moving to middle, includeParents shouldn't do anything.
340         child2.positionChildAt(1, child21, true /* includingParents */);
341         assertEquals(child11, child1.getChildAt(0));
342         assertEquals(child12, child1.getChildAt(1));
343         assertEquals(child13, child1.getChildAt(2));
344         assertEquals(child22, child2.getChildAt(0));
345         assertEquals(child21, child2.getChildAt(1));
346         assertEquals(child23, child2.getChildAt(2));
347         assertEquals(child1, root.getChildAt(0));
348         assertEquals(child2, root.getChildAt(1));
349     }
350 
351     @Test
testPositionChildAtInvalid()352     public void testPositionChildAtInvalid() {
353         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
354         final TestWindowContainer root = builder.setLayer(0).build();
355 
356         final TestWindowContainer child1 = root.addChildWindow();
357 
358         boolean gotException = false;
359         try {
360             // Check response to negative position.
361             root.positionChildAt(-1, child1, false /* includingParents */);
362         } catch (IllegalArgumentException e) {
363             gotException = true;
364         }
365         assertTrue(gotException);
366 
367         gotException = false;
368         try {
369             // Check response to position that's bigger than child number.
370             root.positionChildAt(3, child1, false /* includingParents */);
371         } catch (IllegalArgumentException e) {
372             gotException = true;
373         }
374         assertTrue(gotException);
375     }
376 
377     @Test
testIsAnimating()378     public void testIsAnimating() {
379         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
380         final TestWindowContainer root = builder.setLayer(0).build();
381 
382         final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true));
383         final TestWindowContainer child2 = root.addChildWindow();
384         final TestWindowContainer child11 = child1.addChildWindow();
385         final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
386         final TestWindowContainer child21 = child2.addChildWindow();
387 
388         assertFalse(root.isAnimating());
389         assertTrue(child1.isAnimating());
390         assertTrue(child11.isAnimating());
391         assertTrue(child12.isAnimating());
392         assertFalse(child2.isAnimating());
393         assertFalse(child21.isAnimating());
394 
395         assertTrue(root.isSelfOrChildAnimating());
396         assertTrue(child1.isSelfOrChildAnimating());
397         assertFalse(child11.isSelfOrChildAnimating());
398         assertTrue(child12.isSelfOrChildAnimating());
399         assertFalse(child2.isSelfOrChildAnimating());
400         assertFalse(child21.isSelfOrChildAnimating());
401     }
402 
403     @Test
testIsVisible()404     public void testIsVisible() {
405         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
406         final TestWindowContainer root = builder.setLayer(0).build();
407 
408         final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true));
409         final TestWindowContainer child2 = root.addChildWindow();
410         final TestWindowContainer child11 = child1.addChildWindow();
411         final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true));
412         final TestWindowContainer child21 = child2.addChildWindow();
413 
414         assertFalse(root.isVisible());
415         assertTrue(child1.isVisible());
416         assertFalse(child11.isVisible());
417         assertTrue(child12.isVisible());
418         assertFalse(child2.isVisible());
419         assertFalse(child21.isVisible());
420     }
421 
422     @Test
testOverrideConfigurationAncestorNotification()423     public void testOverrideConfigurationAncestorNotification() {
424         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
425         final TestWindowContainer grandparent = builder.setLayer(0).build();
426 
427         final TestWindowContainer parent = grandparent.addChildWindow();
428         final TestWindowContainer child = parent.addChildWindow();
429         child.onRequestedOverrideConfigurationChanged(new Configuration());
430 
431         assertTrue(grandparent.mOnDescendantOverrideCalled);
432     }
433 
434     @Test
testRemoveChild()435     public void testRemoveChild() {
436         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
437         final TestWindowContainer root = builder.setLayer(0).build();
438         final TestWindowContainer child1 = root.addChildWindow();
439         final TestWindowContainer child2 = root.addChildWindow();
440         final TestWindowContainer child11 = child1.addChildWindow();
441         final TestWindowContainer child21 = child2.addChildWindow();
442 
443         assertTrue(root.hasChild(child2));
444         assertTrue(root.hasChild(child21));
445         root.removeChild(child2);
446         assertFalse(root.hasChild(child2));
447         assertFalse(root.hasChild(child21));
448         assertNull(child2.getParentWindow());
449 
450         boolean gotException = false;
451         assertTrue(root.hasChild(child11));
452         try {
453             // Can only detach our direct children.
454             root.removeChild(child11);
455         } catch (IllegalArgumentException e) {
456             gotException = true;
457         }
458         assertTrue(gotException);
459     }
460 
461     @Test
testGetOrientation_childSpecified()462     public void testGetOrientation_childSpecified() {
463         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
464                 SCREEN_ORIENTATION_LANDSCAPE);
465         testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
466                 SCREEN_ORIENTATION_UNSPECIFIED);
467     }
468 
testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation, int expectedOrientation)469     private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
470             int expectedOrientation) {
471         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
472         final TestWindowContainer root = builder.setLayer(0).build();
473         root.setFillsParent(true);
474 
475         builder.setIsVisible(childVisible);
476 
477         if (childOrientation != SCREEN_ORIENTATION_UNSET) {
478             builder.setOrientation(childOrientation);
479         }
480 
481         final TestWindowContainer child1 = root.addChildWindow(builder);
482         child1.setFillsParent(true);
483 
484         assertEquals(expectedOrientation, root.getOrientation());
485     }
486 
487     @Test
testGetOrientation_Unset()488     public void testGetOrientation_Unset() {
489         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
490         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
491         // Unspecified well because we didn't specify anything...
492         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
493     }
494 
495     @Test
testGetOrientation_InvisibleParentUnsetVisibleChildren()496     public void testGetOrientation_InvisibleParentUnsetVisibleChildren() {
497         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
498         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
499 
500         builder.setIsVisible(false).setLayer(-1);
501         final TestWindowContainer invisible = root.addChildWindow(builder);
502         builder.setIsVisible(true).setLayer(-2);
503         final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder);
504         invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
505         // Landscape well because the container is visible and that is what we set on it above.
506         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
507         // Landscape because even though the container isn't visible it has a child that is
508         // specifying it can influence the orientation by being visible.
509         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisible.getOrientation());
510         // Landscape because the grandchild is visible and therefore can participate.
511         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
512 
513         builder.setIsVisible(true).setLayer(-3);
514         final TestWindowContainer visibleUnset = root.addChildWindow(builder);
515         visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
516         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
517         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
518     }
519 
520     @Test
testGetOrientation_setBehind()521     public void testGetOrientation_setBehind() {
522         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
523         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
524 
525         builder.setIsVisible(true).setLayer(-1);
526         final TestWindowContainer visibleUnset = root.addChildWindow(builder);
527         visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
528 
529         builder.setIsVisible(true).setLayer(-2);
530         final TestWindowContainer visibleUnsetChild1VisibleSetBehind =
531                 visibleUnset.addChildWindow(builder);
532         visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND);
533         // Setting to visible behind will be used by the parents if there isn't another other
534         // container behind this one that has an orientation set.
535         assertEquals(SCREEN_ORIENTATION_BEHIND,
536                 visibleUnsetChild1VisibleSetBehind.getOrientation());
537         assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation());
538         assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
539     }
540 
541     @Test
testGetOrientation_fillsParent()542     public void testGetOrientation_fillsParent() {
543         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
544         final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
545 
546         builder.setIsVisible(true).setLayer(-1);
547         final TestWindowContainer visibleUnset = root.addChildWindow(builder);
548         visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND);
549 
550         builder.setLayer(1).setIsVisible(true);
551         final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder);
552         visibleUnspecifiedRootChild.setFillsParent(false);
553         visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
554         // Unset because the child doesn't fill the parent. May as well be invisible...
555         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
556         // The parent uses whatever orientation is set behind this container since it doesn't fill
557         // the parent.
558         assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
559 
560         // Test case of child filling its parent, but its parent isn't filling its own parent.
561         builder.setLayer(2).setIsVisible(true);
562         final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
563                 visibleUnspecifiedRootChild.addChildWindow(builder);
564         visibleUnspecifiedRootChildChildFillsParent.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
565         assertEquals(SCREEN_ORIENTATION_PORTRAIT,
566                 visibleUnspecifiedRootChildChildFillsParent.getOrientation());
567         assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
568         assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
569 
570 
571         visibleUnspecifiedRootChild.setFillsParent(true);
572         assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation());
573         assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation());
574     }
575 
576     @Test
testCompareTo()577     public void testCompareTo() {
578         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
579         final TestWindowContainer root = builder.setLayer(0).build();
580 
581         final TestWindowContainer child1 = root.addChildWindow();
582         final TestWindowContainer child11 = child1.addChildWindow();
583         final TestWindowContainer child12 = child1.addChildWindow();
584 
585         final TestWindowContainer child2 = root.addChildWindow();
586         final TestWindowContainer child21 = child2.addChildWindow();
587         final TestWindowContainer child22 = child2.addChildWindow();
588         final TestWindowContainer child222 = child22.addChildWindow();
589         final TestWindowContainer child223 = child22.addChildWindow();
590         final TestWindowContainer child2221 = child222.addChildWindow();
591         final TestWindowContainer child2222 = child222.addChildWindow();
592         final TestWindowContainer child2223 = child222.addChildWindow();
593 
594         final TestWindowContainer root2 = builder.setLayer(0).build();
595 
596         assertEquals(0, root.compareTo(root));
597         assertEquals(-1, child1.compareTo(child2));
598         assertEquals(1, child2.compareTo(child1));
599 
600         boolean inTheSameTree = true;
601         try {
602             root.compareTo(root2);
603         } catch (IllegalArgumentException e) {
604             inTheSameTree = false;
605         }
606         assertFalse(inTheSameTree);
607 
608         assertEquals(-1, child1.compareTo(child11));
609         assertEquals(1, child21.compareTo(root));
610         assertEquals(1, child21.compareTo(child12));
611         assertEquals(-1, child11.compareTo(child2));
612         assertEquals(1, child2221.compareTo(child11));
613         assertEquals(-1, child2222.compareTo(child223));
614         assertEquals(1, child2223.compareTo(child21));
615     }
616 
617     @Test
testPrefixOrderIndex()618     public void testPrefixOrderIndex() {
619         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
620         final TestWindowContainer root = builder.build();
621 
622         final TestWindowContainer child1 = root.addChildWindow();
623 
624         final TestWindowContainer child11 = child1.addChildWindow();
625         final TestWindowContainer child12 = child1.addChildWindow();
626 
627         final TestWindowContainer child2 = root.addChildWindow();
628 
629         final TestWindowContainer child21 = child2.addChildWindow();
630         final TestWindowContainer child22 = child2.addChildWindow();
631 
632         final TestWindowContainer child221 = child22.addChildWindow();
633         final TestWindowContainer child222 = child22.addChildWindow();
634         final TestWindowContainer child223 = child22.addChildWindow();
635 
636         final TestWindowContainer child23 = child2.addChildWindow();
637 
638         assertEquals(0, root.getPrefixOrderIndex());
639         assertEquals(1, child1.getPrefixOrderIndex());
640         assertEquals(2, child11.getPrefixOrderIndex());
641         assertEquals(3, child12.getPrefixOrderIndex());
642         assertEquals(4, child2.getPrefixOrderIndex());
643         assertEquals(5, child21.getPrefixOrderIndex());
644         assertEquals(6, child22.getPrefixOrderIndex());
645         assertEquals(7, child221.getPrefixOrderIndex());
646         assertEquals(8, child222.getPrefixOrderIndex());
647         assertEquals(9, child223.getPrefixOrderIndex());
648         assertEquals(10, child23.getPrefixOrderIndex());
649     }
650 
651     @Test
testPrefixOrder_addEntireSubtree()652     public void testPrefixOrder_addEntireSubtree() {
653         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
654         final TestWindowContainer root = builder.build();
655         final TestWindowContainer subtree = builder.build();
656         final TestWindowContainer subtree2 = builder.build();
657 
658         final TestWindowContainer child1 = subtree.addChildWindow();
659         final TestWindowContainer child11 = child1.addChildWindow();
660         final TestWindowContainer child2 = subtree2.addChildWindow();
661         final TestWindowContainer child3 = subtree2.addChildWindow();
662         subtree.addChild(subtree2, 1);
663         root.addChild(subtree, 0);
664 
665         assertEquals(0, root.getPrefixOrderIndex());
666         assertEquals(1, subtree.getPrefixOrderIndex());
667         assertEquals(2, child1.getPrefixOrderIndex());
668         assertEquals(3, child11.getPrefixOrderIndex());
669         assertEquals(4, subtree2.getPrefixOrderIndex());
670         assertEquals(5, child2.getPrefixOrderIndex());
671         assertEquals(6, child3.getPrefixOrderIndex());
672     }
673 
674     @Test
testPrefixOrder_remove()675     public void testPrefixOrder_remove() {
676         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
677         final TestWindowContainer root = builder.build();
678 
679         final TestWindowContainer child1 = root.addChildWindow();
680 
681         final TestWindowContainer child11 = child1.addChildWindow();
682         final TestWindowContainer child12 = child1.addChildWindow();
683 
684         final TestWindowContainer child2 = root.addChildWindow();
685 
686         assertEquals(0, root.getPrefixOrderIndex());
687         assertEquals(1, child1.getPrefixOrderIndex());
688         assertEquals(2, child11.getPrefixOrderIndex());
689         assertEquals(3, child12.getPrefixOrderIndex());
690         assertEquals(4, child2.getPrefixOrderIndex());
691 
692         root.removeChild(child1);
693 
694         assertEquals(1, child2.getPrefixOrderIndex());
695     }
696 
697     /**
698      * Ensure children of a {@link WindowContainer} do not have
699      * {@link WindowContainer#onParentResize()} called when {@link WindowContainer#onParentResize()}
700      * is invoked with overridden bounds.
701      */
702     @Test
testOnParentResizePropagation()703     public void testOnParentResizePropagation() {
704         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
705         final TestWindowContainer root = builder.build();
706 
707         final TestWindowContainer child = root.addChildWindow();
708         child.setBounds(new Rect(1, 1, 2, 2));
709 
710         final TestWindowContainer grandChild = mock(TestWindowContainer.class);
711 
712         child.addChildWindow(grandChild);
713         root.onResize();
714 
715         // Make sure the child does not propagate resize through onParentResize when bounds are set.
716         verify(grandChild, never()).onParentResize();
717 
718         child.removeChild(grandChild);
719 
720         child.setBounds(null);
721         child.addChildWindow(grandChild);
722         root.onResize();
723 
724         // Make sure the child propagates resize through onParentResize when no bounds set.
725         verify(grandChild, times(1)).onParentResize();
726     }
727 
728     @Test
testOnDescendantOrientationRequestChangedPropagation()729     public void testOnDescendantOrientationRequestChangedPropagation() {
730         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
731         final TestWindowContainer root = spy(builder.build());
732 
733         final IBinder binder = mock(IBinder.class);
734         final ActivityRecord activityRecord = mock(ActivityRecord.class);
735         final TestWindowContainer child = root.addChildWindow();
736 
737         child.setOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED, binder, activityRecord);
738         verify(root).onDescendantOrientationChanged(binder, activityRecord);
739     }
740 
741     @Test
testHandlesOrientationChangeFromDescendantProgation()742     public void testHandlesOrientationChangeFromDescendantProgation() {
743         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
744         final TestWindowContainer root = spy(builder.build());
745 
746         final TestWindowContainer child = root.addChildWindow();
747         assertFalse(child.handlesOrientationChangeFromDescendant());
748 
749         Mockito.doReturn(true).when(root).handlesOrientationChangeFromDescendant();
750         assertTrue(child.handlesOrientationChangeFromDescendant());
751     }
752 
753     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
754     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
755         private final int mLayer;
756         private boolean mIsAnimating;
757         private boolean mIsVisible;
758         private boolean mFillsParent;
759         private Integer mOrientation;
760 
761         private boolean mOnParentChangedCalled;
762         private boolean mOnDescendantOverrideCalled;
763 
764         /**
765          * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
766          * of z-order and 1 otherwise.
767          */
768         private static final Comparator<TestWindowContainer> SUBLAYER_COMPARATOR = (w1, w2) -> {
769             final int layer1 = w1.mLayer;
770             final int layer2 = w2.mLayer;
771             if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0)) {
772                 // We insert the child window into the list ordered by the mLayer. For same layers,
773                 // the negative one should go below others; the positive one should go above others.
774                 return -1;
775             }
776             if (layer1 == layer2) return 0;
777             return 1;
778         };
779 
TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating, boolean isVisible, Integer orientation)780         TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating,
781                 boolean isVisible, Integer orientation) {
782             super(wm);
783 
784             mLayer = layer;
785             mIsAnimating = isAnimating;
786             mIsVisible = isVisible;
787             mFillsParent = true;
788             mOrientation = orientation;
789         }
790 
getParentWindow()791         TestWindowContainer getParentWindow() {
792             return (TestWindowContainer) getParent();
793         }
794 
getChildrenCount()795         int getChildrenCount() {
796             return mChildren.size();
797         }
798 
addChildWindow(TestWindowContainer child)799         TestWindowContainer addChildWindow(TestWindowContainer child) {
800             addChild(child, SUBLAYER_COMPARATOR);
801             return child;
802         }
803 
addChildWindow(TestWindowContainerBuilder childBuilder)804         TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
805             TestWindowContainer child = childBuilder.build();
806             addChild(child, SUBLAYER_COMPARATOR);
807             return child;
808         }
809 
addChildWindow()810         TestWindowContainer addChildWindow() {
811             return addChildWindow(new TestWindowContainerBuilder(mWmService).setLayer(1));
812         }
813 
814         @Override
onParentChanged()815         void onParentChanged() {
816             mOnParentChangedCalled = true;
817         }
818 
819         @Override
onDescendantOverrideConfigurationChanged()820         void onDescendantOverrideConfigurationChanged() {
821             mOnDescendantOverrideCalled = true;
822             super.onDescendantOverrideConfigurationChanged();
823         }
824 
825         @Override
isSelfAnimating()826         boolean isSelfAnimating() {
827             return mIsAnimating;
828         }
829 
830         @Override
isVisible()831         boolean isVisible() {
832             return mIsVisible;
833         }
834 
835         @Override
getOrientation(int candidate)836         int getOrientation(int candidate) {
837             return mOrientation != null ? mOrientation : super.getOrientation(candidate);
838         }
839 
840         @Override
getOrientation()841         int getOrientation() {
842             return getOrientation(super.mOrientation);
843         }
844 
845         @Override
fillsParent()846         boolean fillsParent() {
847             return mFillsParent;
848         }
849 
setFillsParent(boolean fillsParent)850         void setFillsParent(boolean fillsParent) {
851             mFillsParent = fillsParent;
852         }
853     }
854 
855     private static class TestWindowContainerBuilder {
856         private final WindowManagerService mWm;
857         private int mLayer;
858         private boolean mIsAnimating;
859         private boolean mIsVisible;
860         private Integer mOrientation;
861 
TestWindowContainerBuilder(WindowManagerService wm)862         TestWindowContainerBuilder(WindowManagerService wm) {
863             mWm = wm;
864             mLayer = 0;
865             mIsAnimating = false;
866             mIsVisible = false;
867             mOrientation = null;
868         }
869 
setLayer(int layer)870         TestWindowContainerBuilder setLayer(int layer) {
871             mLayer = layer;
872             return this;
873         }
874 
setIsAnimating(boolean isAnimating)875         TestWindowContainerBuilder setIsAnimating(boolean isAnimating) {
876             mIsAnimating = isAnimating;
877             return this;
878         }
879 
setIsVisible(boolean isVisible)880         TestWindowContainerBuilder setIsVisible(boolean isVisible) {
881             mIsVisible = isVisible;
882             return this;
883         }
884 
setOrientation(int orientation)885         TestWindowContainerBuilder setOrientation(int orientation) {
886             mOrientation = orientation;
887             return this;
888         }
889 
build()890         TestWindowContainer build() {
891             return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, mOrientation);
892         }
893     }
894 
895     private static class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer>
896             implements AutoCloseable {
897         private final SurfaceSession mSession = new SurfaceSession();
898 
MockSurfaceBuildingContainer(WindowManagerService wm)899         MockSurfaceBuildingContainer(WindowManagerService wm) {
900             super(wm);
901         }
902 
903         static class MockSurfaceBuilder extends SurfaceControl.Builder {
MockSurfaceBuilder(SurfaceSession ss)904             MockSurfaceBuilder(SurfaceSession ss) {
905                 super(ss);
906             }
907 
908             @Override
build()909             public SurfaceControl build() {
910                 return mock(SurfaceControl.class);
911             }
912         }
913 
914         @Override
makeChildSurface(WindowContainer child)915         SurfaceControl.Builder makeChildSurface(WindowContainer child) {
916             return new MockSurfaceBuilder(mSession);
917         }
918 
919         @Override
close()920         public void close() {
921             mSession.kill();
922         }
923     }
924 }
925