blob: 7c50ab27926a66c461631563369c5d9c2484a00b [file] [log] [blame]
/*
* 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);
}
}