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 static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
27import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
28import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
29import static org.junit.Assert.assertEquals;
30import static org.junit.Assert.assertFalse;
31import static org.junit.Assert.assertNotNull;
32import static org.junit.Assert.assertNull;
33import static org.junit.Assert.assertTrue;
34import static org.mockito.Mockito.mock;
35
36/**
37 * Tests for the {@link WindowToken} class.
38 *
39 * Build/Install/Run:
40 *  bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
41 */
42@SmallTest
43@Presubmit
44@RunWith(AndroidJUnit4.class)
45public class WindowTokenTests extends WindowTestsBase {
46
47    @Test
48    public void testAddWindow() throws Exception {
49        final WindowTestUtils.TestWindowToken token =
50                new WindowTestUtils.TestWindowToken(0, mDisplayContent);
51
52        assertEquals(0, token.getWindowsCount());
53
54        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
55        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
56        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
57        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
58        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
59
60        token.addWindow(window1);
61        // NOTE: Child windows will not be added to the token as window containers can only
62        // contain/reference their direct children.
63        token.addWindow(window11);
64        token.addWindow(window12);
65        token.addWindow(window2);
66        token.addWindow(window3);
67
68        // Should not contain the child windows that were added above.
69        assertEquals(3, token.getWindowsCount());
70        assertTrue(token.hasWindow(window1));
71        assertFalse(token.hasWindow(window11));
72        assertFalse(token.hasWindow(window12));
73        assertTrue(token.hasWindow(window2));
74        assertTrue(token.hasWindow(window3));
75    }
76
77    @Test
78    public void testChildRemoval() throws Exception {
79        final DisplayContent dc = mDisplayContent;
80        final WindowTestUtils.TestWindowToken token = new WindowTestUtils.TestWindowToken(0, dc);
81
82        assertEquals(token, dc.getWindowToken(token.token));
83
84        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
85        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
86
87        window2.removeImmediately();
88        // The token should still be mapped in the display content since it still has a child.
89        assertEquals(token, dc.getWindowToken(token.token));
90
91        window1.removeImmediately();
92        // The token should have been removed from the display content since it no longer has a
93        // child.
94        assertEquals(null, dc.getWindowToken(token.token));
95    }
96
97    @Test
98    public void testAdjustAnimLayer() throws Exception {
99        final WindowTestUtils.TestWindowToken token =
100                new WindowTestUtils.TestWindowToken(0, mDisplayContent);
101        final WindowState window1 = createWindow(null, TYPE_APPLICATION, token, "window1");
102        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
103        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
104        final WindowState window2 = createWindow(null, TYPE_APPLICATION, token, "window2");
105        final WindowState window3 = createWindow(null, TYPE_APPLICATION, token, "window3");
106
107        window2.mLayer = 100;
108        window3.mLayer = 200;
109
110        // We assign layers once, to get the base values computed by
111        // the controller.
112        mLayersController.assignWindowLayers(mDisplayContent);
113
114        final int window1StartLayer = window1.mWinAnimator.mAnimLayer;
115        final int window11StartLayer = window11.mWinAnimator.mAnimLayer;
116        final int window12StartLayer = window12.mWinAnimator.mAnimLayer;
117        final int window2StartLayer = window2.mWinAnimator.mAnimLayer;
118        final int window3StartLayer = window3.mWinAnimator.mAnimLayer;
119
120        // Then we set an adjustment, and assign them again, they should
121        // be offset.
122        int adj = token.adj = 50;
123        mLayersController.assignWindowLayers(mDisplayContent);
124        final int highestLayer = token.getHighestAnimLayer();
125
126        assertEquals(window1StartLayer + adj, window1.mWinAnimator.mAnimLayer);
127        assertEquals(window11StartLayer + adj, window11.mWinAnimator.mAnimLayer);
128        assertEquals(window12StartLayer + adj, window12.mWinAnimator.mAnimLayer);
129        assertEquals(window2StartLayer + adj, window2.mWinAnimator.mAnimLayer);
130        assertEquals(window3StartLayer + adj, window3.mWinAnimator.mAnimLayer);
131        assertEquals(window3StartLayer + adj, highestLayer);
132    }
133
134    /**
135     * Test that a window token isn't orphaned by the system when it is requested to be removed.
136     * Tokens should only be removed from the system when all their windows are gone.
137     */
138    @Test
139    public void testTokenRemovalProcess() throws Exception {
140        final WindowTestUtils.TestWindowToken token =
141                new WindowTestUtils.TestWindowToken(TYPE_TOAST, mDisplayContent,
142                        true /* persistOnEmpty */);
143
144        // Verify that the token is on the display
145        assertNotNull(mDisplayContent.getWindowToken(token.token));
146
147        final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
148        final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
149
150        mDisplayContent.removeWindowToken(token.token);
151        // Verify that the token is no longer mapped on the display
152        assertNull(mDisplayContent.getWindowToken(token.token));
153        // Verify that the token is still attached to its parent
154        assertNotNull(token.getParent());
155        // Verify that the token windows are still around.
156        assertEquals(2, token.getWindowsCount());
157
158        window1.removeImmediately();
159        // Verify that the token is still attached to its parent
160        assertNotNull(token.getParent());
161        // Verify that the other token window is still around.
162        assertEquals(1, token.getWindowsCount());
163
164        window2.removeImmediately();
165        // Verify that the token is no-longer attached to its parent
166        assertNull(token.getParent());
167        // Verify that the token windows are no longer attached to it.
168        assertEquals(0, token.getWindowsCount());
169    }
170}
171