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;
25import android.view.Surface;
26import android.view.WindowManager;
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_REVERSE_LANDSCAPE;
31import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
32import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
33import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
34import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
35import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
36import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
37import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
38import static org.junit.Assert.assertEquals;
39import static org.junit.Assert.assertFalse;
40import static org.junit.Assert.assertNull;
41import static org.junit.Assert.assertTrue;
42/**
43 * Tests for the {@link AppWindowToken} class.
44 *
45 * Build/Install/Run:
46 *  bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
47 */
48@SmallTest
49@Presubmit
50@RunWith(AndroidJUnit4.class)
51public class AppWindowTokenTests extends WindowTestsBase {
52
53    @Test
54    public void testAddWindow_Order() throws Exception {
55        final WindowTestUtils.TestAppWindowToken token =
56                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
57
58        assertEquals(0, token.getWindowsCount());
59
60        final WindowState win1 = createWindow(null, TYPE_APPLICATION, token, "win1");
61        final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, token,
62                "startingWin");
63        final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, token, "baseWin");
64        final WindowState win4 = createWindow(null, TYPE_APPLICATION, token, "win4");
65
66        // Should not contain the windows that were added above.
67        assertEquals(4, token.getWindowsCount());
68        assertTrue(token.hasWindow(win1));
69        assertTrue(token.hasWindow(startingWin));
70        assertTrue(token.hasWindow(baseWin));
71        assertTrue(token.hasWindow(win4));
72
73        // The starting window should be on-top of all other windows.
74        assertEquals(startingWin, token.getLastChild());
75
76        // The base application window should be below all other windows.
77        assertEquals(baseWin, token.getFirstChild());
78        token.removeImmediately();
79    }
80
81    @Test
82    public void testFindMainWindow() throws Exception {
83        final WindowTestUtils.TestAppWindowToken token =
84                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
85
86        assertNull(token.findMainWindow());
87
88        final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, token, "window1");
89        final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, token, "window11");
90        final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, token, "window12");
91        assertEquals(window1, token.findMainWindow());
92        window1.mAnimatingExit = true;
93        assertEquals(window1, token.findMainWindow());
94        final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
95        assertEquals(window2, token.findMainWindow());
96        token.removeImmediately();
97    }
98
99    @Test
100    public void testLandscapeSeascapeRotationByApp() throws Exception {
101        // Some plumbing to get the service ready for rotation updates.
102        sWm.mDisplayReady = true;
103        sWm.mDisplayEnabled = true;
104
105        // Create an app window with token on a display.
106        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
107        final Task task = createTaskInStack(stack, 0 /* userId */);
108        final WindowTestUtils.TestAppWindowToken appWindowToken =
109                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
110        task.addChild(appWindowToken, 0);
111        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
112                TYPE_BASE_APPLICATION);
113        attrs.setTitle("AppWindow");
114        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
115        appWindowToken.addWindow(appWindow);
116
117        // Set initial orientation and update.
118        appWindowToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
119        sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
120                mDisplayContent.getDisplayId());
121        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
122        appWindow.resizeReported = false;
123
124        // Update the orientation to perform 180 degree rotation and check that resize was reported.
125        appWindowToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
126        sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
127                mDisplayContent.getDisplayId());
128        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
129        assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
130        assertTrue(appWindow.resizeReported);
131        appWindow.removeImmediately();
132    }
133
134    @Test
135    public void testLandscapeSeascapeRotationByPolicy() throws Exception {
136        // Some plumbing to get the service ready for rotation updates.
137        sWm.mDisplayReady = true;
138        sWm.mDisplayEnabled = true;
139
140        // Create an app window with token on a display.
141        final DisplayContent defaultDisplayContent = sWm.getDefaultDisplayContentLocked();
142        final TaskStack stack = createTaskStackOnDisplay(defaultDisplayContent);
143        final Task task = createTaskInStack(stack, 0 /* userId */);
144        final WindowTestUtils.TestAppWindowToken appWindowToken =
145                new WindowTestUtils.TestAppWindowToken(defaultDisplayContent);
146        task.addChild(appWindowToken, 0);
147        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
148                TYPE_BASE_APPLICATION);
149        attrs.setTitle("AppWindow");
150        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, appWindowToken);
151        appWindowToken.addWindow(appWindow);
152
153        // Set initial orientation and update.
154        performRotation(Surface.ROTATION_90);
155        appWindow.resizeReported = false;
156
157        // Update the rotation to perform 180 degree rotation and check that resize was reported.
158        performRotation(Surface.ROTATION_270);
159        assertTrue(appWindow.resizeReported);
160        appWindow.removeImmediately();
161    }
162
163    private void performRotation(int rotationToReport) {
164        ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = rotationToReport;
165        sWm.updateRotation(false, false);
166        // Simulate animator finishing orientation change
167        sWm.mRoot.mOrientationChangeComplete = true;
168        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
169    }
170
171    @Test
172    public void testGetOrientation() throws Exception {
173        final WindowTestUtils.TestAppWindowToken token =
174                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
175        token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
176
177        token.setFillsParent(false);
178        // Can specify orientation if app doesn't fill parent. Allowed for SDK <= 25.
179        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation());
180
181        token.setFillsParent(true);
182        token.hidden = true;
183        token.sendingToBottom = true;
184        // Can not specify orientation if app isn't visible even though it fills parent.
185        assertEquals(SCREEN_ORIENTATION_UNSET, token.getOrientation());
186        // Can specify orientation if the current orientation candidate is orientation behind.
187        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation(SCREEN_ORIENTATION_BEHIND));
188    }
189
190    @Test
191    public void testKeyguardFlagsDuringRelaunch() throws Exception {
192        final WindowTestUtils.TestAppWindowToken token =
193                new WindowTestUtils.TestAppWindowToken(mDisplayContent);
194        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
195                TYPE_BASE_APPLICATION);
196        attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
197        attrs.setTitle("AppWindow");
198        final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, token);
199
200        // Add window with show when locked flag
201        token.addWindow(appWindow);
202        assertTrue(token.containsShowWhenLockedWindow() && token.containsDismissKeyguardWindow());
203
204        // Start relaunching
205        token.startRelaunching();
206        assertTrue(token.containsShowWhenLockedWindow() && token.containsDismissKeyguardWindow());
207
208        // Remove window and make sure that we still report back flag
209        token.removeChild(appWindow);
210        assertTrue(token.containsShowWhenLockedWindow() && token.containsDismissKeyguardWindow());
211
212        // Finish relaunching and ensure flag is now not reported
213        token.finishRelaunching();
214        assertFalse(token.containsShowWhenLockedWindow() || token.containsDismissKeyguardWindow());
215    }
216}
217