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 android.server.wm; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.MODE_ERRORED; 21 import static android.app.AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW; 22 import static android.server.wm.ShellCommandHelper.executeShellCommand; 23 import static android.server.wm.alertwindowapp.Components.ALERT_WINDOW_TEST_ACTIVITY; 24 import static android.server.wm.alertwindowappsdk25.Components.SDK25_ALERT_WINDOW_TEST_ACTIVITY; 25 26 import static org.hamcrest.MatcherAssert.assertThat; 27 import static org.hamcrest.Matchers.empty; 28 import static org.hamcrest.Matchers.greaterThan; 29 import static org.hamcrest.Matchers.hasSize; 30 import static org.hamcrest.Matchers.lessThan; 31 import static org.junit.Assert.assertEquals; 32 import static org.junit.Assert.assertNotNull; 33 import static org.junit.Assert.assertTrue; 34 35 import android.content.ComponentName; 36 import android.platform.test.annotations.AppModeFull; 37 import android.platform.test.annotations.Presubmit; 38 39 import com.android.compatibility.common.util.AppOpsUtils; 40 41 import org.junit.After; 42 import org.junit.Before; 43 import org.junit.Test; 44 45 import java.util.List; 46 47 /** 48 * Build/Install/Run: 49 * atest CtsWindowManagerDeviceTestCases:AlertWindowsTests 50 */ 51 @Presubmit 52 @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_TASKS") 53 public class AlertWindowsTests extends ActivityManagerTestBase { 54 55 // From WindowManager.java 56 private static final int TYPE_BASE_APPLICATION = 1; 57 private static final int FIRST_SYSTEM_WINDOW = 2000; 58 59 private static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW + 2; 60 private static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3; 61 private static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6; 62 private static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7; 63 private static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10; 64 private static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38; 65 66 private static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW; 67 private static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11; 68 private static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19; 69 70 private static final int[] ALERT_WINDOW_TYPES = { 71 TYPE_PHONE, 72 TYPE_PRIORITY_PHONE, 73 TYPE_SYSTEM_ALERT, 74 TYPE_SYSTEM_ERROR, 75 TYPE_SYSTEM_OVERLAY, 76 TYPE_APPLICATION_OVERLAY 77 }; 78 private static final int[] SYSTEM_WINDOW_TYPES = { 79 TYPE_STATUS_BAR, 80 TYPE_INPUT_METHOD, 81 TYPE_NAVIGATION_BAR 82 }; 83 84 @Before 85 @Override setUp()86 public void setUp() throws Exception { 87 super.setUp(); 88 resetPermissionState(ALERT_WINDOW_TEST_ACTIVITY); 89 resetPermissionState(SDK25_ALERT_WINDOW_TEST_ACTIVITY); 90 } 91 92 @After tearDown()93 public void tearDown() throws Exception { 94 resetPermissionState(ALERT_WINDOW_TEST_ACTIVITY); 95 resetPermissionState(SDK25_ALERT_WINDOW_TEST_ACTIVITY); 96 stopTestPackage(ALERT_WINDOW_TEST_ACTIVITY.getPackageName()); 97 stopTestPackage(SDK25_ALERT_WINDOW_TEST_ACTIVITY.getPackageName()); 98 } 99 100 @Test testAlertWindowAllowed()101 public void testAlertWindowAllowed() throws Exception { 102 runAlertWindowTest(ALERT_WINDOW_TEST_ACTIVITY, true /* hasAlertWindowPermission */, 103 true /* atLeastO */); 104 } 105 106 @Test testAlertWindowDisallowed()107 public void testAlertWindowDisallowed() throws Exception { 108 runAlertWindowTest(ALERT_WINDOW_TEST_ACTIVITY, false /* hasAlertWindowPermission */, 109 true /* atLeastO */); 110 } 111 112 @Test testAlertWindowAllowedSdk25()113 public void testAlertWindowAllowedSdk25() throws Exception { 114 runAlertWindowTest(SDK25_ALERT_WINDOW_TEST_ACTIVITY, true /* hasAlertWindowPermission */, 115 false /* atLeastO */); 116 } 117 118 @Test testAlertWindowDisallowedSdk25()119 public void testAlertWindowDisallowedSdk25() throws Exception { 120 runAlertWindowTest(SDK25_ALERT_WINDOW_TEST_ACTIVITY, false /* hasAlertWindowPermission */, 121 false /* atLeastO */); 122 } 123 runAlertWindowTest(final ComponentName activityName, final boolean hasAlertWindowPermission, final boolean atLeastO)124 private void runAlertWindowTest(final ComponentName activityName, 125 final boolean hasAlertWindowPermission, final boolean atLeastO) throws Exception { 126 setAlertWindowPermission(activityName, hasAlertWindowPermission); 127 128 executeShellCommand(getAmStartCmd(activityName)); 129 mWmState.computeState(new WaitForValidActivityState(activityName)); 130 mWmState.assertVisibility(activityName, true); 131 132 assertAlertWindows(activityName, hasAlertWindowPermission, atLeastO); 133 } 134 allWindowsHidden(List<WindowManagerState.WindowState> windows)135 private boolean allWindowsHidden(List<WindowManagerState.WindowState> windows) { 136 for (WindowManagerState.WindowState ws : windows) { 137 if (ws.isSurfaceShown()) { 138 return false; 139 } 140 } 141 return true; 142 } 143 assertAlertWindows(final ComponentName activityName, final boolean hasAlertWindowPermission, final boolean atLeastO)144 private void assertAlertWindows(final ComponentName activityName, 145 final boolean hasAlertWindowPermission, final boolean atLeastO) throws Exception { 146 final String packageName = activityName.getPackageName(); 147 final WindowManagerState wmState = mWmState; 148 149 final List<WindowManagerState.WindowState> alertWindows = 150 wmState.getWindowsByPackageName(packageName, ALERT_WINDOW_TYPES); 151 152 if (!hasAlertWindowPermission) { 153 // When running in VR Mode, an App Op restriction is 154 // in place for SYSTEM_ALERT_WINDOW, which allows the window 155 // to be created, but will be hidden instead. 156 if (isUiModeLockedToVrHeadset()) { 157 assertThat("Should not be empty alertWindows", 158 alertWindows, hasSize(greaterThan(0))); 159 assertTrue("All alert windows should be hidden", 160 allWindowsHidden(alertWindows)); 161 } else { 162 assertThat("Should be empty alertWindows", alertWindows, empty()); 163 assertTrue(AppOpsUtils.rejectedOperationLogged(packageName, 164 OPSTR_SYSTEM_ALERT_WINDOW)); 165 return; 166 } 167 } 168 169 if (atLeastO) { 170 // Assert that only TYPE_APPLICATION_OVERLAY was created. 171 for (WindowManagerState.WindowState win : alertWindows) { 172 assertEquals("Can't create win=" + win + " on SDK O or greater", 173 win.getType(), TYPE_APPLICATION_OVERLAY); 174 } 175 } 176 177 final WindowManagerState.WindowState mainAppWindow = 178 wmState.getWindowByPackageName(packageName, TYPE_BASE_APPLICATION); 179 180 assertNotNull(mainAppWindow); 181 182 final WindowManagerState.WindowState lowestAlertWindow = alertWindows.get(0); 183 final WindowManagerState.WindowState highestAlertWindow = 184 alertWindows.get(alertWindows.size() - 1); 185 186 // Assert that the alert windows have higher z-order than the main app window 187 assertThat("lowestAlertWindow has higher z-order than mainAppWindow", 188 wmState.getZOrder(lowestAlertWindow), 189 greaterThan(wmState.getZOrder(mainAppWindow))); 190 191 // Assert that legacy alert windows have a lower z-order than the new alert window layer. 192 final WindowManagerState.WindowState appOverlayWindow = 193 wmState.getWindowByPackageName(packageName, TYPE_APPLICATION_OVERLAY); 194 if (appOverlayWindow != null && highestAlertWindow != appOverlayWindow) { 195 assertThat("highestAlertWindow has lower z-order than appOverlayWindow", 196 wmState.getZOrder(highestAlertWindow), 197 lessThan(wmState.getZOrder(appOverlayWindow))); 198 } 199 200 // Assert that alert windows are below key system windows. 201 final List<WindowManagerState.WindowState> systemWindows = 202 wmState.getWindowsByPackageName(packageName, SYSTEM_WINDOW_TYPES); 203 if (!systemWindows.isEmpty()) { 204 final WindowManagerState.WindowState lowestSystemWindow = alertWindows.get(0); 205 assertThat("highestAlertWindow has lower z-order than lowestSystemWindow", 206 wmState.getZOrder(highestAlertWindow), 207 lessThan(wmState.getZOrder(lowestSystemWindow))); 208 } 209 assertTrue(AppOpsUtils.allowedOperationLogged(packageName, OPSTR_SYSTEM_ALERT_WINDOW)); 210 } 211 212 // Resets the permission states for a package to the system defaults. 213 // Also clears the app operation logs for this package, required to test that displaying 214 // the alert window gets logged. resetPermissionState(ComponentName activityName)215 private void resetPermissionState(ComponentName activityName) throws Exception { 216 AppOpsUtils.reset(activityName.getPackageName()); 217 } 218 setAlertWindowPermission(final ComponentName activityName, final boolean allow)219 private void setAlertWindowPermission(final ComponentName activityName, final boolean allow) 220 throws Exception { 221 int mode = allow ? MODE_ALLOWED : MODE_ERRORED; 222 AppOpsUtils.setOpMode(activityName.getPackageName(), OPSTR_SYSTEM_ALERT_WINDOW, mode); 223 } 224 } 225