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