| /* |
| * Copyright (C) 2020 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.server.wm.app.Components.HIDE_OVERLAY_WINDOWS_ACTIVITY; |
| import static android.server.wm.app.Components.HideOverlayWindowsActivity.ACTION; |
| import static android.server.wm.app.Components.HideOverlayWindowsActivity.PONG; |
| import static android.view.Gravity.LEFT; |
| import static android.view.Gravity.TOP; |
| import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.Manifest; |
| import android.app.Activity; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.graphics.Color; |
| import android.graphics.Point; |
| import android.os.Bundle; |
| import android.os.ConditionVariable; |
| import android.platform.test.annotations.Presubmit; |
| import android.server.wm.app.Components; |
| import android.view.WindowManager; |
| import android.widget.TextView; |
| |
| import androidx.annotation.Nullable; |
| |
| import com.android.compatibility.common.util.SystemUtil; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| /** |
| * Build/Install/Run: |
| * atest CtsWindowManagerDeviceTestCases:HideOverlayWindowsTest |
| */ |
| @Presubmit |
| public class HideOverlayWindowsTest extends ActivityManagerTestBase { |
| |
| private final static String WINDOW_NAME_EXTRA = "window_name"; |
| private final static String SYSTEM_APPLICATION_OVERLAY_EXTRA = "system_application_overlay"; |
| private PongReceiver mPongReceiver; |
| |
| @Before |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| mPongReceiver = new PongReceiver(); |
| mContext.registerReceiver(mPongReceiver, new IntentFilter(PONG), Context.RECEIVER_EXPORTED); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| mContext.unregisterReceiver(mPongReceiver); |
| } |
| |
| @Test |
| public void testApplicationOverlayHiddenWhenRequested() { |
| String windowName = "SYSTEM_ALERT_WINDOW"; |
| ComponentName componentName = new ComponentName( |
| mContext, SystemWindowActivity.class); |
| |
| SystemUtil.runWithShellPermissionIdentity(() -> { |
| launchActivity(componentName, |
| CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName)); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| }, Manifest.permission.SYSTEM_ALERT_WINDOW); |
| |
| launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| |
| setHideOverlayWindowsAndWaitForPong(true); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, false); |
| |
| setHideOverlayWindowsAndWaitForPong(false); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| } |
| |
| @Test |
| public void testSystemApplicationOverlayFlagNoEffectWithoutPermission() { |
| String windowName = "SYSTEM_ALERT_WINDOW"; |
| ComponentName componentName = new ComponentName( |
| mContext, SystemWindowActivity.class); |
| |
| SystemUtil.runWithShellPermissionIdentity(() -> { |
| launchActivity(componentName, |
| CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName), |
| CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true)); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| }, Manifest.permission.SYSTEM_ALERT_WINDOW); |
| |
| launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| |
| setHideOverlayWindowsAndWaitForPong(true); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, false); |
| |
| setHideOverlayWindowsAndWaitForPong(false); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| } |
| |
| @Test |
| public void testInternalSystemApplicationOverlaysNotHidden() { |
| String windowName = "INTERNAL_SYSTEM_WINDOW"; |
| ComponentName componentName = new ComponentName( |
| mContext, InternalSystemWindowActivity.class); |
| |
| SystemUtil.runWithShellPermissionIdentity(() -> { |
| launchActivity(componentName, |
| CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName)); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| }, Manifest.permission.INTERNAL_SYSTEM_WINDOW); |
| |
| launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY); |
| setHideOverlayWindowsAndWaitForPong(true); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| } |
| |
| @Test |
| public void testSystemApplicationOverlaysNotHidden() { |
| String windowName = "SYSTEM_APPLICATION_OVERLAY"; |
| ComponentName componentName = new ComponentName( |
| mContext, SystemApplicationOverlayActivity.class); |
| SystemUtil.runWithShellPermissionIdentity(() -> { |
| launchActivity(componentName, |
| CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName), |
| CliIntentExtra.extraBool(SYSTEM_APPLICATION_OVERLAY_EXTRA, true)); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY); |
| |
| launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY); |
| setHideOverlayWindowsAndWaitForPong(true); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| } |
| |
| @Test |
| public void testSystemApplicationOverlayHiddenWithoutFlag() { |
| String windowName = "SYSTEM_APPLICATION_OVERLAY"; |
| ComponentName componentName = new ComponentName( |
| mContext, SystemApplicationOverlayActivity.class); |
| SystemUtil.runWithShellPermissionIdentity(() -> { |
| launchActivity(componentName, |
| CliIntentExtra.extraString(WINDOW_NAME_EXTRA, windowName)); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, true); |
| }, Manifest.permission.SYSTEM_APPLICATION_OVERLAY); |
| |
| launchActivity(HIDE_OVERLAY_WINDOWS_ACTIVITY); |
| setHideOverlayWindowsAndWaitForPong(true); |
| mWmState.waitAndAssertWindowSurfaceShown(windowName, false); |
| } |
| |
| void setHideOverlayWindowsAndWaitForPong(boolean hide) { |
| Intent intent = new Intent(ACTION); |
| intent.putExtra(Components.HideOverlayWindowsActivity.SHOULD_HIDE, hide); |
| mContext.sendBroadcast(intent); |
| mPongReceiver.waitForPong(); |
| } |
| |
| public static class BaseSystemWindowActivity extends Activity { |
| |
| TextView mTextView; |
| |
| @Override |
| protected void onCreate(@Nullable Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| String windowName = getIntent().getStringExtra(WINDOW_NAME_EXTRA); |
| |
| final Point size = new Point(); |
| getDisplay().getRealSize(size); |
| |
| WindowManager.LayoutParams params = |
| new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY, 0); |
| params.width = size.x / 3; |
| params.height = size.y / 3; |
| params.gravity = TOP | LEFT; |
| params.setTitle(windowName); |
| params.setSystemApplicationOverlay( |
| getIntent().getBooleanExtra(SYSTEM_APPLICATION_OVERLAY_EXTRA, false)); |
| |
| mTextView = new TextView(this); |
| mTextView.setText(windowName + " type=" + TYPE_APPLICATION_OVERLAY); |
| mTextView.setBackgroundColor(Color.GREEN); |
| |
| getWindowManager().addView(mTextView, params); |
| } |
| |
| @Override |
| protected void onDestroy() { |
| super.onDestroy(); |
| getWindowManager().removeView(mTextView); |
| } |
| } |
| |
| // These activities are running the same code, but in different processes to ensure that they |
| // each create their own WindowSession, using the correct permissions. If they are run in the |
| // same process WindowSession is cached and might end up not matching the permissions set up |
| // with adoptShellPermissions |
| public static class InternalSystemWindowActivity extends BaseSystemWindowActivity {} |
| public static class SystemApplicationOverlayActivity extends BaseSystemWindowActivity {} |
| public static class SystemWindowActivity extends BaseSystemWindowActivity {} |
| |
| private static class PongReceiver extends BroadcastReceiver { |
| |
| volatile ConditionVariable mConditionVariable = new ConditionVariable(); |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| mConditionVariable.open(); |
| } |
| |
| public void waitForPong() { |
| assertThat(mConditionVariable.block(10000L)).isTrue(); |
| mConditionVariable = new ConditionVariable(); |
| } |
| } |
| |
| } |