1 /* 2 * Copyright (C) 2017 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 21 import android.platform.test.annotations.Presubmit; 22 import android.platform.test.annotations.SecurityTest; 23 import android.support.test.InstrumentationRegistry; 24 import android.support.test.filters.SmallTest; 25 import android.support.test.runner.AndroidJUnit4; 26 import android.view.WindowManager; 27 28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 29 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 30 import static android.content.res.Configuration.EMPTY; 31 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 32 import static org.junit.Assert.assertEquals; 33 import static org.junit.Assert.assertFalse; 34 import static org.junit.Assert.assertNotNull; 35 import static org.junit.Assert.assertNull; 36 import static org.junit.Assert.fail; 37 38 import java.util.function.Consumer; 39 40 /** 41 * Test class for {@link AppWindowContainerController}. 42 * 43 * Build/Install/Run: 44 * bit FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests 45 */ 46 @SmallTest 47 @Presubmit 48 @org.junit.runner.RunWith(AndroidJUnit4.class) 49 public class AppWindowContainerControllerTests extends WindowTestsBase { 50 51 @Test 52 public void testRemoveContainer() throws Exception { 53 final WindowTestUtils.TestAppWindowContainerController controller = 54 createAppWindowController(); 55 56 // Assert token was added to display. 57 assertNotNull(mDisplayContent.getWindowToken(controller.mToken.asBinder())); 58 // Assert that the container was created and linked. 59 assertNotNull(controller.mContainer); 60 61 controller.removeContainer(mDisplayContent.getDisplayId()); 62 63 // Assert token was remove from display. 64 assertNull(mDisplayContent.getWindowToken(controller.mToken.asBinder())); 65 // Assert that the container was removed. 66 assertNull(controller.mContainer); 67 } 68 69 @Test 70 public void testSetOrientation() throws Exception { 71 final WindowTestUtils.TestAppWindowContainerController controller = 72 createAppWindowController(); 73 74 // Assert orientation is unspecified to start. 75 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation()); 76 77 controller.setOrientation(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getDisplayId(), 78 EMPTY /* displayConfig */, false /* freezeScreenIfNeeded */); 79 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, controller.getOrientation()); 80 81 controller.removeContainer(mDisplayContent.getDisplayId()); 82 // Assert orientation is unspecified to after container is removed. 83 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation()); 84 85 // Reset display frozen state 86 sWm.mDisplayFrozen = false; 87 } 88 89 private void assertHasStartingWindow(AppWindowToken atoken) { 90 assertNotNull(atoken.startingSurface); 91 assertNotNull(atoken.startingData); 92 assertNotNull(atoken.startingWindow); 93 } 94 95 private void assertNoStartingWindow(AppWindowToken atoken) { 96 assertNull(atoken.startingSurface); 97 assertNull(atoken.startingWindow); 98 assertNull(atoken.startingData); 99 atoken.forAllWindows(windowState -> { 100 assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING); 101 }, true); 102 } 103 104 @Test 105 public void testCreateRemoveStartingWindow() throws Exception { 106 final WindowTestUtils.TestAppWindowContainerController controller = 107 createAppWindowController(); 108 controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), 109 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 110 false, false); 111 waitUntilHandlersIdle(); 112 final AppWindowToken atoken = controller.getAppWindowToken(mDisplayContent); 113 assertHasStartingWindow(atoken); 114 controller.removeStartingWindow(); 115 waitUntilHandlersIdle(); 116 assertNoStartingWindow(atoken); 117 } 118 119 @Test 120 public void testAddRemoveRace() throws Exception { 121 122 // There was once a race condition between adding and removing starting windows 123 for (int i = 0; i < 1000; i++) { 124 final WindowTestUtils.TestAppWindowContainerController controller = 125 createAppWindowController(); 126 controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), 127 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 128 false, false); 129 controller.removeStartingWindow(); 130 waitUntilHandlersIdle(); 131 assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent)); 132 } 133 } 134 135 @Test 136 public void testTransferStartingWindow() throws Exception { 137 final WindowTestUtils.TestAppWindowContainerController controller1 = 138 createAppWindowController(); 139 final WindowTestUtils.TestAppWindowContainerController controller2 = 140 createAppWindowController(); 141 controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), 142 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 143 false, false); 144 waitUntilHandlersIdle(); 145 controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), 146 android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(), 147 true, true, false, true, false, false); 148 waitUntilHandlersIdle(); 149 assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent)); 150 assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent)); 151 } 152 153 @Test 154 public void testTransferStartingWindowWhileCreating() throws Exception { 155 final WindowTestUtils.TestAppWindowContainerController controller1 = 156 createAppWindowController(); 157 final WindowTestUtils.TestAppWindowContainerController controller2 = 158 createAppWindowController(); 159 ((TestWindowManagerPolicy) sWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> { 160 161 // Surprise, ...! Transfer window in the middle of the creation flow. 162 controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), 163 android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(), 164 true, true, false, true, false, false); 165 }); 166 controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(), 167 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 168 false, false); 169 waitUntilHandlersIdle(); 170 assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent)); 171 assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent)); 172 } 173 174 @Test 175 public void testReparent() throws Exception { 176 final StackWindowController stackController = 177 createStackControllerOnDisplay(mDisplayContent); 178 final WindowTestUtils.TestTaskWindowContainerController taskController1 = 179 new WindowTestUtils.TestTaskWindowContainerController(stackController); 180 final WindowTestUtils.TestAppWindowContainerController appWindowController1 = 181 createAppWindowController(taskController1); 182 final WindowTestUtils.TestTaskWindowContainerController taskController2 = 183 new WindowTestUtils.TestTaskWindowContainerController(stackController); 184 final WindowTestUtils.TestAppWindowContainerController appWindowController2 = 185 createAppWindowController(taskController2); 186 final WindowTestUtils.TestTaskWindowContainerController taskController3 = 187 new WindowTestUtils.TestTaskWindowContainerController(stackController); 188 189 try { 190 appWindowController1.reparent(taskController1, 0); 191 fail("Should not be able to reparent to the same parent"); 192 } catch (IllegalArgumentException e) { 193 // Expected 194 } 195 196 try { 197 taskController3.setContainer(null); 198 appWindowController1.reparent(taskController3, 0); 199 fail("Should not be able to reparent to a task that doesn't have a container"); 200 } catch (IllegalArgumentException e) { 201 // Expected 202 } 203 204 // Reparent the app window and ensure that it is moved 205 appWindowController1.reparent(taskController2, 0); 206 assertEquals(taskController2.mContainer, appWindowController1.mContainer.getParent()); 207 assertEquals(0, ((WindowTestUtils.TestAppWindowToken) appWindowController1.mContainer) 208 .positionInParent()); 209 assertEquals(1, ((WindowTestUtils.TestAppWindowToken) appWindowController2.mContainer) 210 .positionInParent()); 211 } 212 213 private WindowTestUtils.TestAppWindowContainerController createAppWindowController() { 214 return createAppWindowController( 215 new WindowTestUtils.TestTaskWindowContainerController(this)); 216 } 217 218 private WindowTestUtils.TestAppWindowContainerController createAppWindowController( 219 WindowTestUtils.TestTaskWindowContainerController taskController) { 220 return new WindowTestUtils.TestAppWindowContainerController(taskController); 221 } 222 } 223