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