• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.server.wm.app.Components.HIDE_OVERLAY_WINDOWS_ACTIVITY;
20 import static android.server.wm.app.Components.HideOverlayWindowsActivity.ACTION;
21 import static android.server.wm.app.Components.HideOverlayWindowsActivity.MOTION_EVENT_EXTRA;
22 import static android.server.wm.app.Components.HideOverlayWindowsActivity.PONG;
23 import static android.server.wm.app.Components.HideOverlayWindowsActivity.REPORT_TOUCH;
24 import static android.view.Gravity.LEFT;
25 import static android.view.Gravity.TOP;
26 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
27 
28 import static com.google.common.truth.Truth.assertThat;
29 
30 import android.Manifest;
31 import android.app.Activity;
32 import android.content.BroadcastReceiver;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.IntentFilter;
37 import android.graphics.Color;
38 import android.graphics.Point;
39 import android.os.Bundle;
40 import android.os.ConditionVariable;
41 import android.platform.test.annotations.Presubmit;
42 import android.server.wm.app.Components;
43 import android.view.Display;
44 import android.view.MotionEvent;
45 import android.view.WindowManager;
46 import android.widget.TextView;
47 
48 import androidx.annotation.Nullable;
49 
50 import com.android.compatibility.common.util.SystemUtil;
51 
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 
56 /**
57  * Build/Install/Run:
58  * atest CtsWindowManagerDeviceTestCases:HideOverlayWindowsTest
59  */
60 @Presubmit
61 public class HideOverlayWindowsTest extends ActivityManagerTestBase {
62 
63     private final static String WINDOW_NAME_EXTRA = "window_name";
64     private final static String SYSTEM_APPLICATION_OVERLAY_EXTRA = "system_application_overlay";
65     private PongReceiver mPongReceiver;
66     private TouchReceiver mTouchReceiver;
67 
68     @Before
69     @Override
setUp()70     public void setUp() throws Exception {
71         super.setUp();
72         mPongReceiver = new PongReceiver();
73         mContext.registerReceiver(mPongReceiver, new IntentFilter(PONG), Context.RECEIVER_EXPORTED);
74         mTouchReceiver = new TouchReceiver();
75         mContext.registerReceiver(mTouchReceiver, new IntentFilter(REPORT_TOUCH),
76                 Context.RECEIVER_EXPORTED);
77     }
78 
79     @After
tearDown()80     public void tearDown() throws Exception {
81         mContext.unregisterReceiver(mPongReceiver);
82         mContext.unregisterReceiver(mTouchReceiver);
83     }
84 
85     @Test
testApplicationOverlayHiddenWhenRequested()86     public void testApplicationOverlayHiddenWhenRequested() {
87         String windowName = "SYSTEM_ALERT_WINDOW";
88         ComponentName componentName = new ComponentName(
89                 mContext, SystemWindowActivity.class);
90 
91         SystemUtil.runWithShellPermissionIdentity(() -> {
92             launchActivity(componentName,
93                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
94             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
95         }, Manifest.permission.SYSTEM_ALERT_WINDOW);
96 
97         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
98         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
99 
100         setHideOverlayWindowsAndWaitForPong(true);
101         mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
102 
103         setHideOverlayWindowsAndWaitForPong(false);
104         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
105     }
106 
107     @Test
testSystemApplicationOverlayFlagNoEffectWithoutPermission()108     public void testSystemApplicationOverlayFlagNoEffectWithoutPermission() {
109         String windowName = "SYSTEM_ALERT_WINDOW";
110         ComponentName componentName = new ComponentName(
111                 mContext, SystemWindowActivity.class);
112 
113         SystemUtil.runWithShellPermissionIdentity(() -> {
114             launchActivity(componentName,
115                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
116                     CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
117             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
118         }, Manifest.permission.SYSTEM_ALERT_WINDOW);
119 
120         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
121         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
122 
123         setHideOverlayWindowsAndWaitForPong(true);
124         mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
125 
126         setHideOverlayWindowsAndWaitForPong(false);
127         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
128     }
129 
130     @Test
testInternalSystemApplicationOverlaysNotHidden()131     public void testInternalSystemApplicationOverlaysNotHidden() {
132         String windowName = "INTERNAL_SYSTEM_WINDOW";
133         ComponentName componentName = new ComponentName(
134                 mContext, InternalSystemWindowActivity.class);
135 
136         SystemUtil.runWithShellPermissionIdentity(() -> {
137             launchActivity(componentName,
138                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
139             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
140         }, Manifest.permission.INTERNAL_SYSTEM_WINDOW);
141 
142         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
143         setHideOverlayWindowsAndWaitForPong(true);
144         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
145     }
146 
147     @Test
testSystemApplicationOverlaysNotHidden()148     public void testSystemApplicationOverlaysNotHidden() {
149         String windowName = "SYSTEM_APPLICATION_OVERLAY";
150         ComponentName componentName = new ComponentName(
151                 mContext, SystemApplicationOverlayActivity.class);
152         SystemUtil.runWithShellPermissionIdentity(() -> {
153             launchActivity(componentName,
154                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
155                     CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
156             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
157         }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
158 
159         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
160         setHideOverlayWindowsAndWaitForPong(true);
161         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
162     }
163 
164     @Test
testSystemApplicationOverlayHiddenWithoutFlag()165     public void testSystemApplicationOverlayHiddenWithoutFlag() {
166         String windowName = "SYSTEM_APPLICATION_OVERLAY";
167         ComponentName componentName = new ComponentName(
168                 mContext, SystemApplicationOverlayActivity.class);
169         SystemUtil.runWithShellPermissionIdentity(() -> {
170             launchActivity(componentName,
171                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
172             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
173         }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
174 
175         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
176         setHideOverlayWindowsAndWaitForPong(true);
177         mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
178     }
179 
180     @Test
testSystemApplicationOverlayAllowsTouchWithoutObscured()181     public void testSystemApplicationOverlayAllowsTouchWithoutObscured() {
182         String windowName = "SYSTEM_APPLICATION_OVERLAY";
183         ComponentName componentName = new ComponentName(
184                 mContext, SystemApplicationOverlayActivity.class);
185         SystemUtil.runWithShellPermissionIdentity(() -> {
186             launchActivity(componentName,
187                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
188                     CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
189             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
190         }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
191 
192         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
193         setHideOverlayWindowsAndWaitForPong(true);
194         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
195 
196         MotionEvent motionEvent = touchCenterOfDisplayAndWaitForMotionEvent();
197 
198         assertThat(
199                 motionEvent.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED).isEqualTo(
200                 0);
201     }
202 
203     @Test
testApplicationOverlay_touchIsObscuredWithoutCorrectPermission()204     public void testApplicationOverlay_touchIsObscuredWithoutCorrectPermission() {
205         String windowName = "SYSTEM_APPLICATION_OVERLAY";
206         ComponentName componentName = new ComponentName(
207                 mContext, SystemWindowActivity.class);
208         SystemUtil.runWithShellPermissionIdentity(() -> {
209             launchActivity(componentName,
210                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
211                     CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
212             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
213         }, Manifest.permission.SYSTEM_ALERT_WINDOW);
214 
215         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
216         setHideOverlayWindowsAndWaitForPong(false);
217         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
218 
219         MotionEvent motionEvent = touchCenterOfDisplayAndWaitForMotionEvent();
220         assertThat(
221                 motionEvent.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED).isEqualTo(
222                 MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
223     }
224 
touchCenterOfDisplayAndWaitForMotionEvent()225     private MotionEvent touchCenterOfDisplayAndWaitForMotionEvent() {
226         mTouchHelper.tapOnDisplayCenter(Display.DEFAULT_DISPLAY);
227         return mTouchReceiver.getMotionEvent();
228     }
229 
setHideOverlayWindowsAndWaitForPong(boolean hide)230     void setHideOverlayWindowsAndWaitForPong(boolean hide) {
231         Intent intent = new Intent(ACTION);
232         intent.putExtra(Components.HideOverlayWindowsActivity.SHOULD_HIDE, hide);
233         mContext.sendBroadcast(intent);
234         mPongReceiver.waitForPong();
235     }
236 
237     public static class BaseSystemWindowActivity extends Activity {
238 
239         TextView mTextView;
240 
241         @Override
onCreate(@ullable Bundle savedInstanceState)242         protected void onCreate(@Nullable Bundle savedInstanceState) {
243             super.onCreate(savedInstanceState);
244             String windowName = getIntent().getStringExtra(WINDOW_NAME_EXTRA);
245 
246             final Point size = new Point();
247             getDisplay().getRealSize(size);
248 
249             WindowManager.LayoutParams params =
250                     new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY,
251                             WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
252             params.width = size.x / 3;
253             params.height = size.y / 3;
254             params.gravity = TOP | LEFT;
255             params.setTitle(windowName);
256             params.setSystemApplicationOverlay(
257                     getIntent().getBooleanExtra(SYSTEM_APPLICATION_OVERLAY_EXTRA, false));
258 
259             mTextView = new TextView(this);
260             mTextView.setText(windowName + "   type=" + TYPE_APPLICATION_OVERLAY);
261             mTextView.setBackgroundColor(Color.GREEN);
262 
263             getWindowManager().addView(mTextView, params);
264         }
265 
266         @Override
onDestroy()267         protected void onDestroy() {
268             super.onDestroy();
269             getWindowManager().removeView(mTextView);
270         }
271     }
272 
273     // These activities are running the same code, but in different processes to ensure that they
274     // each create their own WindowSession, using the correct permissions. If they are run in the
275     // same process WindowSession is cached and might end up not matching the permissions set up
276     // with adoptShellPermissions
277     public static class InternalSystemWindowActivity extends BaseSystemWindowActivity {}
278     public static class SystemApplicationOverlayActivity extends BaseSystemWindowActivity {}
279     public static class SystemWindowActivity extends BaseSystemWindowActivity {}
280 
281     private static class PongReceiver extends BroadcastReceiver {
282 
283         volatile ConditionVariable mConditionVariable = new ConditionVariable();
284 
285         @Override
onReceive(Context context, Intent intent)286         public void onReceive(Context context, Intent intent) {
287             mConditionVariable.open();
288         }
289 
waitForPong()290         public void waitForPong() {
291             assertThat(mConditionVariable.block(10000L)).isTrue();
292             mConditionVariable = new ConditionVariable();
293         }
294     }
295 
296     private static class TouchReceiver extends BroadcastReceiver {
297 
298         volatile ConditionVariable mConditionVariable = new ConditionVariable();
299         MotionEvent mMotionEvent;
300 
301         @Override
onReceive(Context context, Intent intent)302         public void onReceive(Context context, Intent intent) {
303             mMotionEvent = intent.getParcelableExtra(MOTION_EVENT_EXTRA, MotionEvent.class);
304             mConditionVariable.open();
305         }
306 
getMotionEvent()307         public MotionEvent getMotionEvent() {
308             assertThat(mConditionVariable.block(10000L)).isTrue();
309             mConditionVariable = new ConditionVariable();
310             return mMotionEvent;
311         }
312     }
313 
314 }
315