WindowContainerTests.java revision f6192868fa4fcf85130ef40a90d0c96fbbca761d
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.platform.test.annotations.Presubmit;
23import android.support.test.filters.SmallTest;
24import android.support.test.runner.AndroidJUnit4;
25
26import java.util.Comparator;
27
28import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
29import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
30import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
31import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
32import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
33import static org.junit.Assert.assertEquals;
34import static org.junit.Assert.assertFalse;
35import static org.junit.Assert.assertNotNull;
36import static org.junit.Assert.assertNull;
37import static org.junit.Assert.assertTrue;
38
39/**
40 * Test class for {@link WindowContainer}.
41 *
42 * Build: mmma -j32 frameworks/base/services/tests/servicestests
43 * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
44 * Run: adb shell am instrument -w -e class com.android.server.wm.WindowContainerTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
45 */
46@SmallTest
47@Presubmit
48@RunWith(AndroidJUnit4.class)
49public class WindowContainerTests {
50
51    @Test
52    public void testCreation() throws Exception {
53        final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build();
54        assertNull("window must have no parent", w.getParentWindow());
55        assertEquals("window must have no children", 0, w.getChildrenCount());
56    }
57
58    @Test
59    public void testAdd() throws Exception {
60        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
61        final TestWindowContainer root = builder.setLayer(0).build();
62
63        final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1));
64        final TestWindowContainer secondLayer1 = root.addChildWindow(builder.setLayer(1));
65        final TestWindowContainer layer2 = root.addChildWindow(builder.setLayer(2));
66        final TestWindowContainer layerNeg1 = root.addChildWindow(builder.setLayer(-1));
67        final TestWindowContainer layerNeg2 = root.addChildWindow(builder.setLayer(-2));
68        final TestWindowContainer secondLayerNeg1 = root.addChildWindow(builder.setLayer(-1));
69        final TestWindowContainer layer0 = root.addChildWindow(builder.setLayer(0));
70
71        assertEquals(7, root.getChildrenCount());
72
73        assertEquals(root, layer1.getParentWindow());
74        assertEquals(root, secondLayer1.getParentWindow());
75        assertEquals(root, layer2.getParentWindow());
76        assertEquals(root, layerNeg1.getParentWindow());
77        assertEquals(root, layerNeg2.getParentWindow());
78        assertEquals(root, secondLayerNeg1.getParentWindow());
79        assertEquals(root, layer0.getParentWindow());
80
81        assertEquals(layerNeg2, root.getChildAt(0));
82        assertEquals(secondLayerNeg1, root.getChildAt(1));
83        assertEquals(layerNeg1, root.getChildAt(2));
84        assertEquals(layer0, root.getChildAt(3));
85        assertEquals(layer1, root.getChildAt(4));
86        assertEquals(secondLayer1, root.getChildAt(5));
87        assertEquals(layer2, root.getChildAt(6));
88    }
89
90    @Test
91    public void testAdd_AlreadyHasParent() throws Exception {
92        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
93        final TestWindowContainer root = builder.setLayer(0).build();
94
95        final TestWindowContainer child1 = root.addChildWindow();
96        final TestWindowContainer child2 = root.addChildWindow();
97
98        boolean gotException = false;
99        try {
100            child1.addChildWindow(child2);
101        } catch (IllegalArgumentException e) {
102            gotException = true;
103        }
104        assertTrue(gotException);
105
106        gotException = false;
107        try {
108            root.addChildWindow(child2);
109        } catch (IllegalArgumentException e) {
110            gotException = true;
111        }
112        assertTrue(gotException);
113    }
114
115    @Test
116    public void testHasChild() throws Exception {
117        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
118        final TestWindowContainer root = builder.setLayer(0).build();
119
120        final TestWindowContainer child1 = root.addChildWindow();
121        final TestWindowContainer child2 = root.addChildWindow();
122        final TestWindowContainer child11 = child1.addChildWindow();
123        final TestWindowContainer child12 = child1.addChildWindow();
124        final TestWindowContainer child21 = child2.addChildWindow();
125
126        assertEquals(2, root.getChildrenCount());
127        assertEquals(2, child1.getChildrenCount());
128        assertEquals(1, child2.getChildrenCount());
129
130        assertTrue(root.hasChild(child1));
131        assertTrue(root.hasChild(child2));
132        assertTrue(root.hasChild(child11));
133        assertTrue(root.hasChild(child12));
134        assertTrue(root.hasChild(child21));
135
136        assertTrue(child1.hasChild(child11));
137        assertTrue(child1.hasChild(child12));
138        assertFalse(child1.hasChild(child21));
139
140        assertTrue(child2.hasChild(child21));
141        assertFalse(child2.hasChild(child11));
142        assertFalse(child2.hasChild(child12));
143    }
144
145    @Test
146    public void testRemoveImmediately() throws Exception {
147        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
148        final TestWindowContainer root = builder.setLayer(0).build();
149
150        final TestWindowContainer child1 = root.addChildWindow();
151        final TestWindowContainer child2 = root.addChildWindow();
152        final TestWindowContainer child11 = child1.addChildWindow();
153        final TestWindowContainer child12 = child1.addChildWindow();
154        final TestWindowContainer child21 = child2.addChildWindow();
155
156        assertNotNull(child12.getParentWindow());
157        child12.removeImmediately();
158        assertNull(child12.getParentWindow());
159        assertEquals(1, child1.getChildrenCount());
160        assertFalse(child1.hasChild(child12));
161        assertFalse(root.hasChild(child12));
162
163        assertTrue(root.hasChild(child2));
164        assertNotNull(child2.getParentWindow());
165        child2.removeImmediately();
166        assertNull(child2.getParentWindow());
167        assertNull(child21.getParentWindow());
168        assertEquals(0, child2.getChildrenCount());
169        assertEquals(1, root.getChildrenCount());
170        assertFalse(root.hasChild(child2));
171        assertFalse(root.hasChild(child21));
172
173        assertTrue(root.hasChild(child1));
174        assertTrue(root.hasChild(child11));
175
176        root.removeImmediately();
177        assertEquals(0, root.getChildrenCount());
178    }
179
180    @Test
181    public void testDetachFromDisplay() throws Exception {
182        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
183        final TestWindowContainer root = builder.setLayer(0).build();
184
185        final TestWindowContainer child1 = root.addChildWindow(builder.setCanDetach(true));
186        final TestWindowContainer child2 = root.addChildWindow();
187        final TestWindowContainer child11 = child1.addChildWindow();
188        final TestWindowContainer child12 = child1.addChildWindow(builder.setCanDetach(true));
189        final TestWindowContainer child21 = child2.addChildWindow();
190
191        assertTrue(root.detachFromDisplay());
192        assertTrue(child1.detachFromDisplay());
193        assertFalse(child11.detachFromDisplay());
194        assertTrue(child12.detachFromDisplay());
195        assertFalse(child2.detachFromDisplay());
196        assertFalse(child21.detachFromDisplay());
197    }
198
199    @Test
200    public void testIsAnimating() throws Exception {
201        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
202        final TestWindowContainer root = builder.setLayer(0).build();
203
204        final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true));
205        final TestWindowContainer child2 = root.addChildWindow();
206        final TestWindowContainer child11 = child1.addChildWindow();
207        final TestWindowContainer child12 = child1.addChildWindow(builder.setIsAnimating(true));
208        final TestWindowContainer child21 = child2.addChildWindow();
209
210        assertTrue(root.isAnimating());
211        assertTrue(child1.isAnimating());
212        assertFalse(child11.isAnimating());
213        assertTrue(child12.isAnimating());
214        assertFalse(child2.isAnimating());
215        assertFalse(child21.isAnimating());
216    }
217
218    @Test
219    public void testIsVisible() throws Exception {
220        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
221        final TestWindowContainer root = builder.setLayer(0).build();
222
223        final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true));
224        final TestWindowContainer child2 = root.addChildWindow();
225        final TestWindowContainer child11 = child1.addChildWindow();
226        final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true));
227        final TestWindowContainer child21 = child2.addChildWindow();
228
229        assertFalse(root.isVisible());
230        assertTrue(child1.isVisible());
231        assertFalse(child11.isVisible());
232        assertTrue(child12.isVisible());
233        assertFalse(child2.isVisible());
234        assertFalse(child21.isVisible());
235    }
236
237    @Test
238    public void testRemoveChild() throws Exception {
239        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
240        final TestWindowContainer root = builder.setLayer(0).build();
241        final TestWindowContainer child1 = root.addChildWindow();
242        final TestWindowContainer child2 = root.addChildWindow();
243        final TestWindowContainer child11 = child1.addChildWindow();
244        final TestWindowContainer child21 = child2.addChildWindow();
245
246        assertTrue(root.hasChild(child2));
247        assertTrue(root.hasChild(child21));
248        root.removeChild(child2);
249        assertFalse(root.hasChild(child2));
250        assertFalse(root.hasChild(child21));
251        assertNull(child2.getParentWindow());
252
253        boolean gotException = false;
254        assertTrue(root.hasChild(child11));
255        try {
256            // Can only detach our direct children.
257            root.removeChild(child11);
258        } catch (IllegalArgumentException e) {
259            gotException = true;
260        }
261        assertTrue(gotException);
262    }
263
264    @Test
265    public void testGetOrientation_Unset() throws Exception {
266        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
267        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
268        // Unspecified well because we didn't specify anything...
269        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
270    }
271
272    @Test
273    public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception {
274        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
275        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
276
277        builder.setIsVisible(false).setLayer(-1);
278        final TestWindowContainer invisible = root.addChildWindow(builder);
279        builder.setIsVisible(true).setLayer(-2);
280        final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder);
281        invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
282        // Landscape well because the container is visible and that is what we set on it above.
283        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
284        // Unset because the container isn't visible even though it has a child that thinks it is
285        // visible.
286        assertEquals(SCREEN_ORIENTATION_UNSET, invisible.getOrientation());
287        // Unspecified because we are visible and we didn't specify an orientation and there isn't
288        // a visible child.
289        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
290
291        builder.setIsVisible(true).setLayer(-3);
292        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
293        visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
294        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
295        assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
296
297    }
298
299    @Test
300    public void testGetOrientation_setBehind() throws Exception {
301        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
302        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
303
304        builder.setIsVisible(true).setLayer(-1);
305        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
306        visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
307
308        builder.setIsVisible(true).setLayer(-2);
309        final TestWindowContainer visibleUnsetChild1VisibleSetBehind =
310                visibleUnset.addChildWindow(builder);
311        visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND);
312        // Setting to visible behind will be used by the parents if there isn't another other
313        // container behind this one that has an orientation set.
314        assertEquals(SCREEN_ORIENTATION_BEHIND,
315                visibleUnsetChild1VisibleSetBehind.getOrientation());
316        assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation());
317        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
318    }
319
320    @Test
321    public void testGetOrientation_fillsParent() throws Exception {
322        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
323        final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
324
325        builder.setIsVisible(true).setLayer(-1);
326        final TestWindowContainer visibleUnset = root.addChildWindow(builder);
327        visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND);
328
329        builder.setLayer(1).setIsVisible(true);
330        final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder);
331        visibleUnspecifiedRootChild.setFillsParent(false);
332        visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
333        // Unset because the child doesn't fill the parent. May as well be invisible...
334        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
335        // The parent uses whatever orientation is set behind this container since it doesn't fill
336        // the parent.
337        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
338
339        // Test case of child filling its parent, but its parent isn't filling its own parent.
340        builder.setLayer(2).setIsVisible(true);
341        final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
342                visibleUnspecifiedRootChild.addChildWindow(builder);
343        visibleUnspecifiedRootChildChildFillsParent.setOrientation(
344                SCREEN_ORIENTATION_PORTRAIT);
345        assertEquals(SCREEN_ORIENTATION_PORTRAIT,
346                visibleUnspecifiedRootChildChildFillsParent.getOrientation());
347        assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
348        assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
349
350
351        visibleUnspecifiedRootChild.setFillsParent(true);
352        assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation());
353        assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation());
354    }
355
356    @Test
357    public void testCompareTo() throws Exception {
358        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
359        final TestWindowContainer root = builder.setLayer(0).build();
360
361        final TestWindowContainer child1 = root.addChildWindow();
362        final TestWindowContainer child11 = child1.addChildWindow();
363        final TestWindowContainer child12 = child1.addChildWindow();
364
365        final TestWindowContainer child2 = root.addChildWindow();
366        final TestWindowContainer child21 = child2.addChildWindow();
367        final TestWindowContainer child22 = child2.addChildWindow();
368        final TestWindowContainer child23 = child2.addChildWindow();
369        final TestWindowContainer child221 = child22.addChildWindow();
370        final TestWindowContainer child222 = child22.addChildWindow();
371        final TestWindowContainer child223 = child22.addChildWindow();
372        final TestWindowContainer child2221 = child222.addChildWindow();
373        final TestWindowContainer child2222 = child222.addChildWindow();
374        final TestWindowContainer child2223 = child222.addChildWindow();
375
376        final TestWindowContainer root2 = builder.setLayer(0).build();
377
378        assertEquals(0, root.compareTo(root));
379        assertEquals(-1, child1.compareTo(child2));
380        assertEquals(1, child2.compareTo(child1));
381
382        boolean inTheSameTree = true;
383        try {
384            root.compareTo(root2);
385        } catch (IllegalArgumentException e) {
386            inTheSameTree = false;
387        }
388        assertFalse(inTheSameTree);
389
390        assertEquals(-1, child1.compareTo(child11));
391        assertEquals(1, child21.compareTo(root));
392        assertEquals(1, child21.compareTo(child12));
393        assertEquals(-1, child11.compareTo(child2));
394        assertEquals(1, child2221.compareTo(child11));
395        assertEquals(-1, child2222.compareTo(child223));
396        assertEquals(1, child2223.compareTo(child21));
397    }
398
399    /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
400    private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
401        private final int mLayer;
402        private final boolean mCanDetach;
403        private boolean mIsAnimating;
404        private boolean mIsVisible;
405        private boolean mFillsParent;
406
407        /**
408         * Compares 2 window layers and returns -1 if the first is lesser than the second in terms
409         * of z-order and 1 otherwise.
410         */
411        private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> {
412            final int layer1 = w1.mLayer;
413            final int layer2 = w2.mLayer;
414            if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
415                // We insert the child window into the list ordered by the mLayer. For same layers,
416                // the negative one should go below others; the positive one should go above others.
417                return -1;
418            }
419            return 1;
420        };
421
422        TestWindowContainer(int layer, boolean canDetach, boolean isAnimating, boolean isVisible) {
423            mLayer = layer;
424            mCanDetach = canDetach;
425            mIsAnimating = isAnimating;
426            mIsVisible = isVisible;
427            mFillsParent = true;
428        }
429
430        TestWindowContainer getParentWindow() {
431            return (TestWindowContainer) getParent();
432        }
433
434        int getChildrenCount() {
435            return mChildren.size();
436        }
437
438        TestWindowContainer addChildWindow(TestWindowContainer child) {
439            addChild(child, mWindowSubLayerComparator);
440            return child;
441        }
442
443        TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
444            TestWindowContainer child = childBuilder.build();
445            addChild(child, mWindowSubLayerComparator);
446            return child;
447        }
448
449        TestWindowContainer addChildWindow() {
450            return addChildWindow(new TestWindowContainerBuilder().setLayer(1));
451        }
452
453        TestWindowContainer getChildAt(int index) {
454            return mChildren.get(index);
455        }
456
457        @Override
458        boolean detachFromDisplay() {
459            return super.detachFromDisplay() || mCanDetach;
460        }
461
462        @Override
463        boolean isAnimating() {
464            return mIsAnimating || super.isAnimating();
465        }
466
467        @Override
468        boolean isVisible() {
469            return mIsVisible;
470        }
471
472        @Override
473        boolean fillsParent() {
474            return mFillsParent;
475        }
476
477        void setFillsParent(boolean fillsParent) {
478            mFillsParent = fillsParent;
479        }
480    }
481
482    private class TestWindowContainerBuilder {
483        private int mLayer;
484        private boolean mCanDetach;
485        private boolean mIsAnimating;
486        private boolean mIsVisible;
487
488        public TestWindowContainerBuilder() {
489            reset();
490        }
491
492        TestWindowContainerBuilder setLayer(int layer) {
493            mLayer = layer;
494            return this;
495        }
496
497        TestWindowContainerBuilder setCanDetach(boolean canDetach) {
498            mCanDetach = canDetach;
499            return this;
500        }
501
502        TestWindowContainerBuilder setIsAnimating(boolean isAnimating) {
503            mIsAnimating = isAnimating;
504            return this;
505        }
506
507        TestWindowContainerBuilder setIsVisible(boolean isVisible) {
508            mIsVisible = isVisible;
509            return this;
510        }
511
512        TestWindowContainerBuilder reset() {
513            mLayer = 0;
514            mCanDetach = false;
515            mIsAnimating = false;
516            mIsVisible = false;
517            return this;
518        }
519
520        TestWindowContainer build() {
521            return new TestWindowContainer(mLayer, mCanDetach, mIsAnimating, mIsVisible);
522        }
523    }
524}
525