Home | History | Annotate | Download | only in wm
      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
     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 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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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 
    759         TestWindowContainer getParentWindow() {
    760             return (TestWindowContainer) getParent();
    761         }
    762 
    763         int getChildrenCount() {
    764             return mChildren.size();
    765         }
    766 
    767         TestWindowContainer addChildWindow(TestWindowContainer child) {
    768             addChild(child, mWindowSubLayerComparator);
    769             return child;
    770         }
    771 
    772         TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
    773             TestWindowContainer child = childBuilder.build();
    774             addChild(child, mWindowSubLayerComparator);
    775             return child;
    776         }
    777 
    778         TestWindowContainer addChildWindow() {
    779             return addChildWindow(new TestWindowContainerBuilder().setLayer(1));
    780         }
    781 
    782         TestWindowContainer getChildAt(int index) {
    783             return mChildren.get(index);
    784         }
    785 
    786         @Override
    787         void onParentSet() {
    788             mOnParentSetCalled = true;
    789         }
    790 
    791         @Override
    792         void onDescendantOverrideConfigurationChanged() {
    793             mOnDescendantOverrideCalled = true;
    794             super.onDescendantOverrideConfigurationChanged();
    795         }
    796 
    797         @Override
    798         boolean isAnimating() {
    799             return mIsAnimating || super.isAnimating();
    800         }
    801 
    802         @Override
    803         boolean isVisible() {
    804             return mIsVisible;
    805         }
    806 
    807         @Override
    808         int getOrientation(int candidate) {
    809             return mOrientation != null ? mOrientation : super.getOrientation(candidate);
    810         }
    811 
    812         @Override
    813         int getOrientation() {
    814             return getOrientation(super.mOrientation);
    815         }
    816 
    817         @Override
    818         boolean fillsParent() {
    819             return mFillsParent;
    820         }
    821 
    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 
    833         public TestWindowContainerBuilder() {
    834             reset();
    835         }
    836 
    837         TestWindowContainerBuilder setLayer(int layer) {
    838             mLayer = layer;
    839             return this;
    840         }
    841 
    842         TestWindowContainerBuilder setIsAnimating(boolean isAnimating) {
    843             mIsAnimating = isAnimating;
    844             return this;
    845         }
    846 
    847         TestWindowContainerBuilder setIsVisible(boolean isVisible) {
    848             mIsVisible = isVisible;
    849             return this;
    850         }
    851 
    852         TestWindowContainerBuilder setOrientation(int orientation) {
    853             mOrientation = orientation;
    854             return this;
    855         }
    856 
    857         TestWindowContainerBuilder reset() {
    858             mLayer = 0;
    859             mIsAnimating = false;
    860             mIsVisible = false;
    861             mOrientation = null;
    862             return this;
    863         }
    864 
    865         TestWindowContainer build() {
    866             return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation);
    867         }
    868     }
    869 }
    870