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), Context.RECEIVER_EXPORTED); 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