/* * Copyright (C) 2022 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.view.Display.DEFAULT_DISPLAY; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import android.Manifest; import android.platform.test.annotations.Presubmit; import com.android.compatibility.common.util.ApiTest; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * Ensure Activity screencapture callback is invoked as expected. * *

Build/Install/Run: atest CtsWindowManagerDeviceTestCases:ActivityCaptureCallbackTests */ @Presubmit @ApiTest(apis = {"android.app.Activity#registerScreenCaptureCallback", "android.app.Activity#unregisterScreenCaptureCallback"}) public class ActivityCaptureCallbackTests extends WindowManagerTestBase { private PrimaryActivity mPrimaryActivity; @Before @Override public void setUp() throws Exception { super.setUp(); mPrimaryActivity = startActivity(PrimaryActivity.class, DEFAULT_DISPLAY); } @After public void tearDown() throws Exception { mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); } /** Test a registered Activity callback invocation. */ @Test public void testScreencaptureInvokeCallback() { mInstrumentation .getUiAutomation() .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); mPrimaryActivity.waitAndAssertCallbackInvokedOnActivity(); } /** Test multi-window activities, both callbacks are invoked. */ @Test public void testScreencaptureInvokeCallbackOnAllVisibleActivities() { assumeTrue(supportsMultiDisplay()); final WindowManagerState.DisplayContent newDisplay = createManagedExternalDisplaySession().createVirtualDisplay(); final SecondaryActivity secondaryActivity = startActivity(SecondaryActivity.class, newDisplay.mId, /* hasFocus */ false); mInstrumentation .getUiAutomation() .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); mWm.notifyScreenshotListeners(newDisplay.mId); mPrimaryActivity.waitAndAssertCallbackInvokedOnActivity(); secondaryActivity.waitAndAssertCallbackInvokedOnActivity(); } /** Test screenshotting only one display. */ @Test public void testScreencaptureInvokeCallbackOnOneDisplay() { assumeTrue(supportsMultiDisplay()); final WindowManagerState.DisplayContent newDisplay = createManagedExternalDisplaySession().createVirtualDisplay(); final SecondaryActivity secondaryActivity = startActivity(SecondaryActivity.class, newDisplay.mId, /* hasFocus */ false); mInstrumentation .getUiAutomation() .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); mPrimaryActivity.waitAndAssertCallbackInvokedOnActivity(); secondaryActivity.waitAndAssertCallbackNotInvoked(); } /** Test multi-window activities, only registered callback is invoked. */ @Test public void testScreencaptureInvokeCallbackOnRegisteredVisibleActivities() { assumeTrue(supportsMultiDisplay()); mPrimaryActivity.unregisterScreencaptureCallback(); final WindowManagerState.DisplayContent newDisplay = createManagedExternalDisplaySession().createVirtualDisplay(); final SecondaryActivity secondaryActivity = startActivity(SecondaryActivity.class, newDisplay.mId, /* hasFocus */ false); mInstrumentation .getUiAutomation() .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); mWm.notifyScreenshotListeners(newDisplay.mId); mPrimaryActivity.waitAndAssertCallbackNotInvoked(); secondaryActivity.waitAndAssertCallbackInvokedOnActivity(); } /** Test only the top activity callback is invoked */ @Test public void testScreencaptureInvokeCallbackOnVisibleOnly() { final SecondaryActivity topActivity = startActivity(SecondaryActivity.class, DEFAULT_DISPLAY); mInstrumentation .getUiAutomation() .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); topActivity.waitAndAssertCallbackInvokedOnActivity(); mPrimaryActivity.waitAndAssertCallbackNotInvoked(); } /** Test unregister callback */ @Test public void testScreencaptureUnregisterCallback() { mInstrumentation .getUiAutomation() .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); mPrimaryActivity.unregisterScreencaptureCallback(); mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); mPrimaryActivity.waitAndAssertCallbackNotInvoked(); } public static class PrimaryActivity extends ScreencaptureCallbackActivity {} public static class SecondaryActivity extends ScreencaptureCallbackActivity {} private static class ScreencaptureCallbackActivity extends FocusableActivity { private static final long TIMEOUT_SCREENCAPTURE_CALLBACK_INVOKED = 1000; // milliseconds private CountDownLatch mCountDownLatch = new CountDownLatch(1); final ScreenCaptureCallback mCallback = new ScreenCaptureCallback() { @Override public void onScreenCaptured() { mCountDownLatch.countDown(); } }; void waitAndAssertCallbackInvokedOnActivity() { try { boolean invoked = mCountDownLatch.await( TIMEOUT_SCREENCAPTURE_CALLBACK_INVOKED, TimeUnit.MILLISECONDS); assertTrue(invoked); } catch (InterruptedException e) { // This shouldn't happen } } void waitAndAssertCallbackNotInvoked() { try { boolean invoked = mCountDownLatch.await( TIMEOUT_SCREENCAPTURE_CALLBACK_INVOKED, TimeUnit.MILLISECONDS); assertFalse(invoked); } catch (InterruptedException e) { // This shouldn't happen } } public void unregisterScreencaptureCallback() { unregisterScreenCaptureCallback(mCallback); } @Override protected void onStart() { super.onStart(); registerScreenCaptureCallback(Executors.newSingleThreadExecutor(), mCallback); } } }