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