• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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