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