WindowContainerTests.java revision f0a6fdbf53882949db0a141693dd33302b42d51b
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
17package com.android.server.wm;
18
19import org.junit.Test;
20import org.junit.runner.RunWith;
21
22import android.content.res.Configuration;
23import android.platform.test.annotations.Presubmit;
24import android.support.test.filters.SmallTest;
25import android.support.test.runner.AndroidJUnit4;
26
27import java.util.Comparator;
28
29import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
30import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
31import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
32import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
33import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
34import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
35import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
36
37import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
38import static com.android.server.wm.WindowContainer.POSITION_TOP;
39
40import static org.junit.Assert.assertEquals;
41import static org.junit.Assert.assertFalse;
42import static org.junit.Assert.assertNotNull;
43import static org.junit.Assert.assertNull;
44import 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)
55public class WindowContainerTests extends WindowTestsBase {
56
57    @Test
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
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
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
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
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
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
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
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
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
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
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
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
364    public void testRemoveChild() throws Exception {
365        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
366        final TestWindowContainer root = builder.setLayer(0).build();
367        final TestWindowContainer child1 = root.addChildWindow();
368        final TestWindowContainer child2 = root.addChildWindow();
369        final TestWindowContainer child11 = child1.addChildWindow();
370        final TestWindowContainer child21 = child2.addChildWindow();
371
372        assertTrue(root.hasChild(child2));
373        assertTrue(root.hasChild(child21));
374        root.removeChild(child2);
375        assertFalse(root.hasChild(child2));
376        assertFalse(root.hasChild(child21));
377        assertNull(child2.getParentWindow());
378
379        boolean gotException = false;
380        assertTrue(root.hasChild(child11));
381        try {
382            // Can only detach our direct children.
383            root.removeChild(child11);
384        } catch (IllegalArgumentException e) {
385            gotException = true;
386        }
387        assertTrue(gotException);
388    }
389
390    @Test
391    public void testGetOrientation_childSpecified() throws Exception {
392        testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
393            SCREEN_ORIENTATION_LANDSCAPE);
394        testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
395            SCREEN_ORIENTATION_UNSET);
396    }
397
398    private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
399        int expectedOrientation) {
400        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
401        final TestWindowContainer root = builder.setLayer(0).build();
402        root.setFillsParent(true);
403
404        builder.setIsVisible(childVisible);
405
406        if (childOrientation != SCREEN_ORIENTATION_UNSET) {
407            builder.setOrientation(childOrientation);
408        }
409
410        final TestWindowContainer child1 = root.addChildWindow(builder);
411        child1.setFillsParent(true);
412
413        assertTrue(root.getOrientation() == expectedOrientation);
414    }
415
416    @Test
417    public void testGetOrientation_Unset() throws Exception {
418        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
419        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
420        // Unspecified well because we didn't specify anything...
421        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
422    }
423
424    @Test
425    public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception {
426        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
427        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
428
429        builder.setIsVisible(false).setLayer(-1);
430        final TestWindowContainer invisible = root.addChildWindow(builder);
431        builder.setIsVisible(true).setLayer(-2);
432        final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder);
433        invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
434        // Landscape well because the container is visible and that is what we set on it above.
435        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
436        // Landscape because even though the container isn't visible it has a child that is
437        // specifying it can influence the orientation by being visible.
438        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisible.getOrientation());
439        // Landscape because the grandchild is visible and therefore can participate.
440        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
441
442        builder.setIsVisible(true).setLayer(-3);
443        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
444        visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
445        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
446        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
447
448    }
449
450    @Test
451    public void testGetOrientation_setBehind() throws Exception {
452        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
453        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
454
455        builder.setIsVisible(true).setLayer(-1);
456        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
457        visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
458
459        builder.setIsVisible(true).setLayer(-2);
460        final TestWindowContainer visibleUnsetChild1VisibleSetBehind =
461                visibleUnset.addChildWindow(builder);
462        visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND);
463        // Setting to visible behind will be used by the parents if there isn't another other
464        // container behind this one that has an orientation set.
465        assertEquals(SCREEN_ORIENTATION_BEHIND,
466                visibleUnsetChild1VisibleSetBehind.getOrientation());
467        assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation());
468        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
469    }
470
471    @Test
472    public void testGetOrientation_fillsParent() throws Exception {
473        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
474        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
475
476        builder.setIsVisible(true).setLayer(-1);
477        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
478        visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND);
479
480        builder.setLayer(1).setIsVisible(true);
481        final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder);
482        visibleUnspecifiedRootChild.setFillsParent(false);
483        visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
484        // Unset because the child doesn't fill the parent. May as well be invisible...
485        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
486        // The parent uses whatever orientation is set behind this container since it doesn't fill
487        // the parent.
488        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
489
490        // Test case of child filling its parent, but its parent isn't filling its own parent.
491        builder.setLayer(2).setIsVisible(true);
492        final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
493                visibleUnspecifiedRootChild.addChildWindow(builder);
494        visibleUnspecifiedRootChildChildFillsParent.setOrientation(
495                SCREEN_ORIENTATION_PORTRAIT);
496        assertEquals(SCREEN_ORIENTATION_PORTRAIT,
497                visibleUnspecifiedRootChildChildFillsParent.getOrientation());
498        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
499        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
500
501
502        visibleUnspecifiedRootChild.setFillsParent(true);
503        assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation());
504        assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation());
505    }
506
507    @Test
508    public void testCompareTo() throws Exception {
509        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
510        final TestWindowContainer root = builder.setLayer(0).build();
511
512        final TestWindowContainer child1 = root.addChildWindow();
513        final TestWindowContainer child11 = child1.addChildWindow();
514        final TestWindowContainer child12 = child1.addChildWindow();
515
516        final TestWindowContainer child2 = root.addChildWindow();
517        final TestWindowContainer child21 = child2.addChildWindow();
518        final TestWindowContainer child22 = child2.addChildWindow();
519        final TestWindowContainer child23 = child2.addChildWindow();
520        final TestWindowContainer child221 = child22.addChildWindow();
521        final TestWindowContainer child222 = child22.addChildWindow();
522        final TestWindowContainer child223 = child22.addChildWindow();
523        final TestWindowContainer child2221 = child222.addChildWindow();
524        final TestWindowContainer child2222 = child222.addChildWindow();
525        final TestWindowContainer child2223 = child222.addChildWindow();
526
527        final TestWindowContainer root2 = builder.setLayer(0).build();
528
529        assertEquals(0, root.compareTo(root));
530        assertEquals(-1, child1.compareTo(child2));
531        assertEquals(1, child2.compareTo(child1));
532
533        boolean inTheSameTree = true;
534        try {
535            root.compareTo(root2);
536        } catch (IllegalArgumentException e) {
537            inTheSameTree = false;
538        }
539        assertFalse(inTheSameTree);
540
541        assertEquals(-1, child1.compareTo(child11));
542        assertEquals(1, child21.compareTo(root));
543        assertEquals(1, child21.compareTo(child12));
544        assertEquals(-1, child11.compareTo(child2));
545        assertEquals(1, child2221.compareTo(child11));
546        assertEquals(-1, child2222.compareTo(child223));
547        assertEquals(1, child2223.compareTo(child21));
548    }
549
550    @Test
551    public void testConfigurationInit() throws Exception {
552        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
553
554        // Check root container initial config.
555        final TestWindowContainer root = builder.setLayer(0).build();
556        assertEquals(Configuration.EMPTY, root.getOverrideConfiguration());
557        assertEquals(Configuration.EMPTY, root.getMergedOverrideConfiguration());
558        assertEquals(Configuration.EMPTY, root.getConfiguration());
559
560        // Check child initial config.
561        final TestWindowContainer child1 = root.addChildWindow();
562        assertEquals(Configuration.EMPTY, child1.getOverrideConfiguration());
563        assertEquals(Configuration.EMPTY, child1.getMergedOverrideConfiguration());
564        assertEquals(Configuration.EMPTY, child1.getConfiguration());
565
566        // Check child initial config if root has overrides.
567        final Configuration rootOverrideConfig = new Configuration();
568        rootOverrideConfig.fontScale = 1.3f;
569        root.onOverrideConfigurationChanged(rootOverrideConfig);
570        final TestWindowContainer child2 = root.addChildWindow();
571        assertEquals(Configuration.EMPTY, child2.getOverrideConfiguration());
572        assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration());
573        assertEquals(rootOverrideConfig, child2.getConfiguration());
574
575        // Check child initial config if root has parent config set.
576        final Configuration rootParentConfig = new Configuration();
577        rootParentConfig.fontScale = 0.8f;
578        rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE;
579        root.onConfigurationChanged(rootParentConfig);
580        final Configuration rootFullConfig = new Configuration(rootParentConfig);
581        rootFullConfig.updateFrom(rootOverrideConfig);
582
583        final TestWindowContainer child3 = root.addChildWindow();
584        assertEquals(Configuration.EMPTY, child3.getOverrideConfiguration());
585        assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration());
586        assertEquals(rootFullConfig, child3.getConfiguration());
587    }
588
589    @Test
590    public void testConfigurationChangeOnAddRemove() throws Exception {
591        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
592
593        // Init root's config.
594        final TestWindowContainer root = builder.setLayer(0).build();
595        final Configuration rootOverrideConfig = new Configuration();
596        rootOverrideConfig.fontScale = 1.3f;
597        root.onOverrideConfigurationChanged(rootOverrideConfig);
598
599        // Init child's config.
600        final TestWindowContainer child = root.addChildWindow();
601        final Configuration childOverrideConfig = new Configuration();
602        childOverrideConfig.densityDpi = 320;
603        child.onOverrideConfigurationChanged(childOverrideConfig);
604        final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration());
605        mergedOverrideConfig.updateFrom(childOverrideConfig);
606
607        // Check configuration update when child is removed from parent - it should remain same.
608        root.removeChild(child);
609        assertEquals(childOverrideConfig, child.getOverrideConfiguration());
610        assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration());
611        assertEquals(mergedOverrideConfig, child.getConfiguration());
612
613        // It may be paranoia... but let's check if parent's config didn't change after removal.
614        assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
615        assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
616        assertEquals(rootOverrideConfig, root.getConfiguration());
617
618        // Init different root
619        final TestWindowContainer root2 = builder.setLayer(0).build();
620        final Configuration rootOverrideConfig2 = new Configuration();
621        rootOverrideConfig2.fontScale = 1.1f;
622        root2.onOverrideConfigurationChanged(rootOverrideConfig2);
623
624        // Check configuration update when child is added to different parent.
625        mergedOverrideConfig.setTo(rootOverrideConfig2);
626        mergedOverrideConfig.updateFrom(childOverrideConfig);
627        root2.addChildWindow(child);
628        assertEquals(childOverrideConfig, child.getOverrideConfiguration());
629        assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration());
630        assertEquals(mergedOverrideConfig, child.getConfiguration());
631    }
632
633    @Test
634    public void testConfigurationChangePropagation() throws Exception {
635        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
636
637        // Builds 3-level vertical hierarchy with one window container on each level.
638        // In addition to different overrides on each level, everyone in hierarchy will have one
639        // common overridden value - orientation;
640
641        // Init root's config.
642        final TestWindowContainer root = builder.setLayer(0).build();
643        final Configuration rootOverrideConfig = new Configuration();
644        rootOverrideConfig.fontScale = 1.3f;
645        rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
646        root.onOverrideConfigurationChanged(rootOverrideConfig);
647
648        // Init children.
649        final TestWindowContainer child1 = root.addChildWindow();
650        final Configuration childOverrideConfig1 = new Configuration();
651        childOverrideConfig1.densityDpi = 320;
652        childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE;
653        child1.onOverrideConfigurationChanged(childOverrideConfig1);
654
655        final TestWindowContainer child2 = child1.addChildWindow();
656        final Configuration childOverrideConfig2 = new Configuration();
657        childOverrideConfig2.screenWidthDp = 150;
658        childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT;
659        child2.onOverrideConfigurationChanged(childOverrideConfig2);
660
661        // Check configuration on all levels when root override is updated.
662        rootOverrideConfig.smallestScreenWidthDp = 200;
663        root.onOverrideConfigurationChanged(rootOverrideConfig);
664
665        final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig);
666        mergedOverrideConfig1.updateFrom(childOverrideConfig1);
667        final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1);
668
669        final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1);
670        mergedOverrideConfig2.updateFrom(childOverrideConfig2);
671        final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2);
672
673        assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
674        assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
675        assertEquals(rootOverrideConfig, root.getConfiguration());
676
677        assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
678        assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
679        assertEquals(mergedConfig1, child1.getConfiguration());
680
681        assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
682        assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
683        assertEquals(mergedConfig2, child2.getConfiguration());
684
685        // Check configuration on all levels when root parent config is updated.
686        final Configuration rootParentConfig = new Configuration();
687        rootParentConfig.screenHeightDp = 100;
688        rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT;
689        root.onConfigurationChanged(rootParentConfig);
690        final Configuration mergedRootConfig = new Configuration(rootParentConfig);
691        mergedRootConfig.updateFrom(rootOverrideConfig);
692
693        mergedConfig1.setTo(mergedRootConfig);
694        mergedConfig1.updateFrom(mergedOverrideConfig1);
695
696        mergedConfig2.setTo(mergedConfig1);
697        mergedConfig2.updateFrom(mergedOverrideConfig2);
698
699        assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
700        assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
701        assertEquals(mergedRootConfig, root.getConfiguration());
702
703        assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
704        assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
705        assertEquals(mergedConfig1, child1.getConfiguration());
706
707        assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
708        assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
709        assertEquals(mergedConfig2, child2.getConfiguration());
710    }
711
712    /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
713    private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
714        private final int mLayer;
715        private boolean mIsAnimating;
716        private boolean mIsVisible;
717        private boolean mFillsParent;
718        private Integer mOrientation;
719
720        private boolean mOnParentSetCalled;
721
722        /**
723         * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
724         * of z-order and 1 otherwise.
725         */
726        private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> {
727            final int layer1 = w1.mLayer;
728            final int layer2 = w2.mLayer;
729            if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
730                // We insert the child window into the list ordered by the mLayer. For same layers,
731                // the negative one should go below others; the positive one should go above others.
732                return -1;
733            }
734            return 1;
735        };
736
737        TestWindowContainer(int layer, boolean isAnimating, boolean isVisible,
738            Integer orientation) {
739            mLayer = layer;
740            mIsAnimating = isAnimating;
741            mIsVisible = isVisible;
742            mFillsParent = true;
743            mOrientation = orientation;
744        }
745
746        TestWindowContainer getParentWindow() {
747            return (TestWindowContainer) getParent();
748        }
749
750        int getChildrenCount() {
751            return mChildren.size();
752        }
753
754        TestWindowContainer addChildWindow(TestWindowContainer child) {
755            addChild(child, mWindowSubLayerComparator);
756            return child;
757        }
758
759        TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
760            TestWindowContainer child = childBuilder.build();
761            addChild(child, mWindowSubLayerComparator);
762            return child;
763        }
764
765        TestWindowContainer addChildWindow() {
766            return addChildWindow(new TestWindowContainerBuilder().setLayer(1));
767        }
768
769        TestWindowContainer getChildAt(int index) {
770            return mChildren.get(index);
771        }
772
773        @Override
774        void onParentSet() {
775            mOnParentSetCalled = true;
776        }
777
778        @Override
779        boolean isAnimating() {
780            return mIsAnimating || super.isAnimating();
781        }
782
783        @Override
784        boolean isVisible() {
785            return mIsVisible;
786        }
787
788        @Override
789        int getOrientation() {
790            return mOrientation != null ? mOrientation : super.getOrientation();
791        }
792
793        @Override
794        boolean fillsParent() {
795            return mFillsParent;
796        }
797
798        void setFillsParent(boolean fillsParent) {
799            mFillsParent = fillsParent;
800        }
801    }
802
803    private class TestWindowContainerBuilder {
804        private int mLayer;
805        private boolean mIsAnimating;
806        private boolean mIsVisible;
807        private Integer mOrientation;
808
809        public TestWindowContainerBuilder() {
810            reset();
811        }
812
813        TestWindowContainerBuilder setLayer(int layer) {
814            mLayer = layer;
815            return this;
816        }
817
818        TestWindowContainerBuilder setIsAnimating(boolean isAnimating) {
819            mIsAnimating = isAnimating;
820            return this;
821        }
822
823        TestWindowContainerBuilder setIsVisible(boolean isVisible) {
824            mIsVisible = isVisible;
825            return this;
826        }
827
828        TestWindowContainerBuilder setOrientation(int orientation) {
829            mOrientation = orientation;
830            return this;
831        }
832
833        TestWindowContainerBuilder reset() {
834            mLayer = 0;
835            mIsAnimating = false;
836            mIsVisible = false;
837            mOrientation = null;
838            return this;
839        }
840
841        TestWindowContainer build() {
842            return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation);
843        }
844    }
845}
846