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.PONG;
22 import static android.view.Gravity.LEFT;
23 import static android.view.Gravity.TOP;
24 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
25 
26 import static com.google.common.truth.Truth.assertThat;
27 
28 import android.Manifest;
29 import android.app.Activity;
30 import android.content.BroadcastReceiver;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.IntentFilter;
35 import android.graphics.Color;
36 import android.graphics.Point;
37 import android.os.Bundle;
38 import android.os.ConditionVariable;
39 import android.platform.test.annotations.Presubmit;
40 import android.server.wm.app.Components;
41 import android.view.WindowManager;
42 import android.widget.TextView;
43 
44 import androidx.annotation.Nullable;
45 
46 import com.android.compatibility.common.util.SystemUtil;
47 
48 import org.junit.After;
49 import org.junit.Before;
50 import org.junit.Test;
51 
52 /**
53  * Build/Install/Run:
54  * atest CtsWindowManagerDeviceTestCases:HideOverlayWindowsTest
55  */
56 @Presubmit
57 public class HideOverlayWindowsTest extends ActivityManagerTestBase {
58 
59     private final static String WINDOW_NAME_EXTRA = "window_name";
60     private final static String SYSTEM_APPLICATION_OVERLAY_EXTRA = "system_application_overlay";
61     private PongReceiver mPongReceiver;
62 
63     @Before
64     @Override
setUp()65     public void setUp() throws Exception {
66         super.setUp();
67         mPongReceiver = new PongReceiver();
68         mContext.registerReceiver(mPongReceiver, new IntentFilter(PONG));
69     }
70 
71     @After
tearDown()72     public void tearDown() throws Exception {
73         mContext.unregisterReceiver(mPongReceiver);
74     }
75 
76     @Test
testApplicationOverlayHiddenWhenRequested()77     public void testApplicationOverlayHiddenWhenRequested() {
78         String windowName = "SYSTEM_ALERT_WINDOW";
79         ComponentName componentName = new ComponentName(
80                 mContext, SystemWindowActivity.class);
81 
82         SystemUtil.runWithShellPermissionIdentity(() -> {
83             launchActivity(componentName,
84                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
85             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
86         }, Manifest.permission.SYSTEM_ALERT_WINDOW);
87 
88         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
89         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
90 
91         setHideOverlayWindowsAndWaitForPong(true);
92         mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
93 
94         setHideOverlayWindowsAndWaitForPong(false);
95         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
96     }
97 
98     @Test
testSystemApplicationOverlayFlagNoEffectWithoutPermission()99     public void testSystemApplicationOverlayFlagNoEffectWithoutPermission() {
100         String windowName = "SYSTEM_ALERT_WINDOW";
101         ComponentName componentName = new ComponentName(
102                 mContext, SystemWindowActivity.class);
103 
104         SystemUtil.runWithShellPermissionIdentity(() -> {
105             launchActivity(componentName,
106                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
107                     CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
108             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
109         }, Manifest.permission.SYSTEM_ALERT_WINDOW);
110 
111         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
112         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
113 
114         setHideOverlayWindowsAndWaitForPong(true);
115         mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
116 
117         setHideOverlayWindowsAndWaitForPong(false);
118         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
119     }
120 
121     @Test
testInternalSystemApplicationOverlaysNotHidden()122     public void testInternalSystemApplicationOverlaysNotHidden() {
123         String windowName = "INTERNAL_SYSTEM_WINDOW";
124         ComponentName componentName = new ComponentName(
125                 mContext, InternalSystemWindowActivity.class);
126 
127         SystemUtil.runWithShellPermissionIdentity(() -> {
128             launchActivity(componentName,
129                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
130             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
131         }, Manifest.permission.INTERNAL_SYSTEM_WINDOW);
132 
133         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
134         setHideOverlayWindowsAndWaitForPong(true);
135         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
136     }
137 
138     @Test
testSystemApplicationOverlaysNotHidden()139     public void testSystemApplicationOverlaysNotHidden() {
140         String windowName = "SYSTEM_APPLICATION_OVERLAY";
141         ComponentName componentName = new ComponentName(
142                 mContext, SystemApplicationOverlayActivity.class);
143         SystemUtil.runWithShellPermissionIdentity(() -> {
144             launchActivity(componentName,
145                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName),
146                     CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true));
147             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
148         }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
149 
150         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
151         setHideOverlayWindowsAndWaitForPong(true);
152         mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
153     }
154 
155     @Test
testSystemApplicationOverlayHiddenWithoutFlag()156     public void testSystemApplicationOverlayHiddenWithoutFlag() {
157         String windowName = "SYSTEM_APPLICATION_OVERLAY";
158         ComponentName componentName = new ComponentName(
159                 mContext, SystemApplicationOverlayActivity.class);
160         SystemUtil.runWithShellPermissionIdentity(() -> {
161             launchActivity(componentName,
162                     CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName));
163             mWmState.waitAndAssertWindowSurfaceShown(windowName, true);
164         }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY);
165 
166         launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY);
167         setHideOverlayWindowsAndWaitForPong(true);
168         mWmState.waitAndAssertWindowSurfaceShown(windowName, false);
169     }
170 
setHideOverlayWindowsAndWaitForPong(boolean hide)171     void setHideOverlayWindowsAndWaitForPong(boolean hide) {
172         Intent intent = new Intent(ACTION);
173         intent.putExtra(Components.HideOverlayWindowsActivity.SHOULD_HIDE, hide);
174         mContext.sendBroadcast(intent);
175         mPongReceiver.waitForPong();
176     }
177 
178     public static class BaseSystemWindowActivity extends Activity {
179 
180         TextView mTextView;
181 
182         @Override
onCreate(@ullable Bundle savedInstanceState)183         protected void onCreate(@Nullable Bundle savedInstanceState) {
184             super.onCreate(savedInstanceState);
185             String windowName = getIntent().getStringExtra(WINDOW_NAME_EXTRA);
186 
187             final Point size = new Point();
188             getDisplay().getRealSize(size);
189 
190             WindowManager.LayoutParams params =
191                     new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY, 0);
192             params.width = size.x / 3;
193             params.height = size.y / 3;
194             params.gravity = TOP | LEFT;
195             params.setTitle(windowName);
196             params.setSystemApplicationOverlay(
197                     getIntent().getBooleanExtra(SYSTEM_APPLICATION_OVERLAY_EXTRA, false));
198 
199             mTextView = new TextView(this);
200             mTextView.setText(windowName + "   type=" + TYPE_APPLICATION_OVERLAY);
201             mTextView.setBackgroundColor(Color.GREEN);
202 
203             getWindowManager().addView(mTextView, params);
204         }
205 
206         @Override
onDestroy()207         protected void onDestroy() {
208             super.onDestroy();
209             getWindowManager().removeView(mTextView);
210         }
211     }
212 
213     // These activities are running the same code, but in different processes to ensure that they
214     // each create their own WindowSession, using the correct permissions. If they are run in the
215     // same process WindowSession is cached and might end up not matching the permissions set up
216     // with adoptShellPermissions
217     public static class InternalSystemWindowActivity extends BaseSystemWindowActivity {}
218     public static class SystemApplicationOverlayActivity extends BaseSystemWindowActivity {}
219     public static class SystemWindowActivity extends BaseSystemWindowActivity {}
220 
221     private static class PongReceiver extends BroadcastReceiver {
222 
223         volatile ConditionVariable mConditionVariable = new ConditionVariable();
224 
225         @Override
onReceive(Context context, Intent intent)226         public void onReceive(Context context, Intent intent) {
227             mConditionVariable.open();
228         }
229 
waitForPong()230         public void waitForPong() {
231             assertThat(mConditionVariable.block(10000L)).isTrue();
232             mConditionVariable = new ConditionVariable();
233         }
234     }
235 
236 }
237