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