| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package android.server.wm; |
| |
| import static android.app.AppOpsManager.MODE_ALLOWED; |
| import static android.app.AppOpsManager.MODE_ERRORED; |
| import static android.app.AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW; |
| import static android.server.wm.alertwindowapp.Components.ALERT_WINDOW_TEST_ACTIVITY; |
| import static android.server.wm.alertwindowappsdk25.Components.SDK25_ALERT_WINDOW_TEST_ACTIVITY; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.Matchers.empty; |
| import static org.hamcrest.Matchers.greaterThan; |
| import static org.hamcrest.Matchers.hasSize; |
| import static org.hamcrest.Matchers.lessThan; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import android.content.ComponentName; |
| import android.platform.test.annotations.AppModeFull; |
| import android.platform.test.annotations.Presubmit; |
| |
| import com.android.compatibility.common.util.AppOpsUtils; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| import java.util.List; |
| |
| /** |
| * Build/Install/Run: |
| * atest CtsWindowManagerDeviceTestCases:AlertWindowsTests |
| */ |
| @Presubmit |
| @AppModeFull(reason = "Requires android.permission.MANAGE_ACTIVITY_STACKS") |
| public class AlertWindowsTests extends ActivityManagerTestBase { |
| |
| // From WindowManager.java |
| private static final int TYPE_BASE_APPLICATION = 1; |
| private static final int FIRST_SYSTEM_WINDOW = 2000; |
| |
| private static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW + 2; |
| private static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3; |
| private static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6; |
| private static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7; |
| private static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10; |
| private static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38; |
| |
| private static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW; |
| private static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11; |
| private static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19; |
| |
| private static final int[] ALERT_WINDOW_TYPES = { |
| TYPE_PHONE, |
| TYPE_PRIORITY_PHONE, |
| TYPE_SYSTEM_ALERT, |
| TYPE_SYSTEM_ERROR, |
| TYPE_SYSTEM_OVERLAY, |
| TYPE_APPLICATION_OVERLAY |
| }; |
| private static final int[] SYSTEM_WINDOW_TYPES = { |
| TYPE_STATUS_BAR, |
| TYPE_INPUT_METHOD, |
| TYPE_NAVIGATION_BAR |
| }; |
| |
| @Before |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| resetPermissionState(ALERT_WINDOW_TEST_ACTIVITY); |
| resetPermissionState(SDK25_ALERT_WINDOW_TEST_ACTIVITY); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| resetPermissionState(ALERT_WINDOW_TEST_ACTIVITY); |
| resetPermissionState(SDK25_ALERT_WINDOW_TEST_ACTIVITY); |
| stopTestPackage(ALERT_WINDOW_TEST_ACTIVITY.getPackageName()); |
| stopTestPackage(SDK25_ALERT_WINDOW_TEST_ACTIVITY.getPackageName()); |
| } |
| |
| @Test |
| public void testAlertWindowAllowed() throws Exception { |
| runAlertWindowTest(ALERT_WINDOW_TEST_ACTIVITY, true /* hasAlertWindowPermission */, |
| true /* atLeastO */); |
| } |
| |
| @Test |
| public void testAlertWindowDisallowed() throws Exception { |
| runAlertWindowTest(ALERT_WINDOW_TEST_ACTIVITY, false /* hasAlertWindowPermission */, |
| true /* atLeastO */); |
| } |
| |
| @Test |
| public void testAlertWindowAllowedSdk25() throws Exception { |
| runAlertWindowTest(SDK25_ALERT_WINDOW_TEST_ACTIVITY, true /* hasAlertWindowPermission */, |
| false /* atLeastO */); |
| } |
| |
| @Test |
| public void testAlertWindowDisallowedSdk25() throws Exception { |
| runAlertWindowTest(SDK25_ALERT_WINDOW_TEST_ACTIVITY, false /* hasAlertWindowPermission */, |
| false /* atLeastO */); |
| } |
| |
| private void runAlertWindowTest(final ComponentName activityName, |
| final boolean hasAlertWindowPermission, final boolean atLeastO) throws Exception { |
| setAlertWindowPermission(activityName, hasAlertWindowPermission); |
| |
| executeShellCommand(getAmStartCmd(activityName)); |
| mWmState.computeState(new WaitForValidActivityState(activityName)); |
| mWmState.assertVisibility(activityName, true); |
| |
| assertAlertWindows(activityName, hasAlertWindowPermission, atLeastO); |
| } |
| |
| private boolean allWindowsHidden(List<WindowManagerState.WindowState> windows) { |
| for (WindowManagerState.WindowState ws : windows) { |
| if (ws.isSurfaceShown()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private void assertAlertWindows(final ComponentName activityName, |
| final boolean hasAlertWindowPermission, final boolean atLeastO) throws Exception { |
| final String packageName = activityName.getPackageName(); |
| final WindowManagerState wmState = mWmState; |
| |
| final List<WindowManagerState.WindowState> alertWindows = |
| wmState.getWindowsByPackageName(packageName, ALERT_WINDOW_TYPES); |
| |
| if (!hasAlertWindowPermission) { |
| // When running in VR Mode, an App Op restriction is |
| // in place for SYSTEM_ALERT_WINDOW, which allows the window |
| // to be created, but will be hidden instead. |
| if (isUiModeLockedToVrHeadset()) { |
| assertThat("Should not be empty alertWindows", |
| alertWindows, hasSize(greaterThan(0))); |
| assertTrue("All alert windows should be hidden", |
| allWindowsHidden(alertWindows)); |
| } else { |
| assertThat("Should be empty alertWindows", alertWindows, empty()); |
| assertTrue(AppOpsUtils.rejectedOperationLogged(packageName, |
| OPSTR_SYSTEM_ALERT_WINDOW)); |
| return; |
| } |
| } |
| |
| if (atLeastO) { |
| // Assert that only TYPE_APPLICATION_OVERLAY was created. |
| for (WindowManagerState.WindowState win : alertWindows) { |
| assertEquals("Can't create win=" + win + " on SDK O or greater", |
| win.getType(), TYPE_APPLICATION_OVERLAY); |
| } |
| } |
| |
| final WindowManagerState.WindowState mainAppWindow = |
| wmState.getWindowByPackageName(packageName, TYPE_BASE_APPLICATION); |
| |
| assertNotNull(mainAppWindow); |
| |
| final WindowManagerState.WindowState lowestAlertWindow = alertWindows.get(0); |
| final WindowManagerState.WindowState highestAlertWindow = |
| alertWindows.get(alertWindows.size() - 1); |
| |
| // Assert that the alert windows have higher z-order than the main app window |
| assertThat("lowestAlertWindow has higher z-order than mainAppWindow", |
| wmState.getZOrder(lowestAlertWindow), |
| greaterThan(wmState.getZOrder(mainAppWindow))); |
| |
| // Assert that legacy alert windows have a lower z-order than the new alert window layer. |
| final WindowManagerState.WindowState appOverlayWindow = |
| wmState.getWindowByPackageName(packageName, TYPE_APPLICATION_OVERLAY); |
| if (appOverlayWindow != null && highestAlertWindow != appOverlayWindow) { |
| assertThat("highestAlertWindow has lower z-order than appOverlayWindow", |
| wmState.getZOrder(highestAlertWindow), |
| lessThan(wmState.getZOrder(appOverlayWindow))); |
| } |
| |
| // Assert that alert windows are below key system windows. |
| final List<WindowManagerState.WindowState> systemWindows = |
| wmState.getWindowsByPackageName(packageName, SYSTEM_WINDOW_TYPES); |
| if (!systemWindows.isEmpty()) { |
| final WindowManagerState.WindowState lowestSystemWindow = alertWindows.get(0); |
| assertThat("highestAlertWindow has lower z-order than lowestSystemWindow", |
| wmState.getZOrder(highestAlertWindow), |
| lessThan(wmState.getZOrder(lowestSystemWindow))); |
| } |
| assertTrue(AppOpsUtils.allowedOperationLogged(packageName, OPSTR_SYSTEM_ALERT_WINDOW)); |
| } |
| |
| // Resets the permission states for a package to the system defaults. |
| // Also clears the app operation logs for this package, required to test that displaying |
| // the alert window gets logged. |
| private void resetPermissionState(ComponentName activityName) throws Exception { |
| AppOpsUtils.reset(activityName.getPackageName()); |
| } |
| |
| private void setAlertWindowPermission(final ComponentName activityName, final boolean allow) |
| throws Exception { |
| int mode = allow ? MODE_ALLOWED : MODE_ERRORED; |
| AppOpsUtils.setOpMode(activityName.getPackageName(), OPSTR_SYSTEM_ALERT_WINDOW, mode); |
| } |
| } |