1 /* 2 * Copyright (C) 2022 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.activity; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assume.assumeTrue; 24 25 import android.Manifest; 26 import android.os.Bundle; 27 import android.platform.test.annotations.Presubmit; 28 import android.server.wm.WindowManagerState; 29 import android.server.wm.WindowManagerTestBase; 30 31 import com.android.compatibility.common.util.ApiTest; 32 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Test; 36 37 import java.util.concurrent.CountDownLatch; 38 import java.util.concurrent.Executors; 39 import java.util.concurrent.TimeUnit; 40 41 /** 42 * Ensure Activity screencapture callback is invoked as expected. 43 * 44 * <p>Build/Install/Run: atest CtsWindowManagerDeviceActivity:ActivityCaptureCallbackTests 45 */ 46 @Presubmit 47 @ApiTest(apis = {"android.app.Activity#registerScreenCaptureCallback", 48 "android.app.Activity#unregisterScreenCaptureCallback"}) 49 public class ActivityCaptureCallbackTests extends WindowManagerTestBase { 50 private PrimaryActivity mPrimaryActivity; 51 52 @Before 53 @Override setUp()54 public void setUp() throws Exception { 55 super.setUp(); 56 mPrimaryActivity = startActivity(PrimaryActivity.class, DEFAULT_DISPLAY); 57 } 58 59 @After tearDown()60 public void tearDown() throws Exception { 61 mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); 62 } 63 64 /** Test a registered Activity callback invocation. */ 65 @Test testScreencaptureInvokeCallback()66 public void testScreencaptureInvokeCallback() { 67 mInstrumentation 68 .getUiAutomation() 69 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 70 mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); 71 mPrimaryActivity.waitAndAssertCallbackInvokedOnActivity(); 72 } 73 74 /** Test multi-window activities, both callbacks are invoked. */ 75 @Test testScreencaptureInvokeCallbackOnAllVisibleActivities()76 public void testScreencaptureInvokeCallbackOnAllVisibleActivities() { 77 assumeTrue(supportsMultiDisplay()); 78 79 final WindowManagerState.DisplayContent newDisplay = 80 createManagedExternalDisplaySession().createVirtualDisplay(); 81 final SecondaryActivity secondaryActivity = 82 startActivity(SecondaryActivity.class, newDisplay.mId, /* hasFocus */ false); 83 mInstrumentation 84 .getUiAutomation() 85 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 86 mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); 87 mWm.notifyScreenshotListeners(newDisplay.mId); 88 mPrimaryActivity.waitAndAssertCallbackInvokedOnActivity(); 89 secondaryActivity.waitAndAssertCallbackInvokedOnActivity(); 90 } 91 92 /** Test screenshotting only one display. */ 93 @Test testScreencaptureInvokeCallbackOnOneDisplay()94 public void testScreencaptureInvokeCallbackOnOneDisplay() { 95 assumeTrue(supportsMultiDisplay()); 96 97 final WindowManagerState.DisplayContent newDisplay = 98 createManagedExternalDisplaySession().createVirtualDisplay(); 99 final SecondaryActivity secondaryActivity = 100 startActivity(SecondaryActivity.class, newDisplay.mId, /* hasFocus */ false); 101 mInstrumentation 102 .getUiAutomation() 103 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 104 mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); 105 mPrimaryActivity.waitAndAssertCallbackInvokedOnActivity(); 106 secondaryActivity.waitAndAssertCallbackNotInvoked(); 107 } 108 /** Test multi-window activities, only registered callback is invoked. */ 109 @Test testScreencaptureInvokeCallbackOnRegisteredVisibleActivities()110 public void testScreencaptureInvokeCallbackOnRegisteredVisibleActivities() { 111 assumeTrue(supportsMultiDisplay()); 112 113 mPrimaryActivity.unregisterScreencaptureCallback(); 114 final WindowManagerState.DisplayContent newDisplay = 115 createManagedExternalDisplaySession().createVirtualDisplay(); 116 final SecondaryActivity secondaryActivity = 117 startActivity(SecondaryActivity.class, newDisplay.mId, /* hasFocus */ false); 118 mInstrumentation 119 .getUiAutomation() 120 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 121 mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); 122 mWm.notifyScreenshotListeners(newDisplay.mId); 123 mPrimaryActivity.waitAndAssertCallbackNotInvoked(); 124 secondaryActivity.waitAndAssertCallbackInvokedOnActivity(); 125 } 126 127 /** Test only the top activity callback is invoked */ 128 @Test testScreencaptureInvokeCallbackOnVisibleOnly()129 public void testScreencaptureInvokeCallbackOnVisibleOnly() { 130 final SecondaryActivity topActivity = 131 startActivity(SecondaryActivity.class, DEFAULT_DISPLAY); 132 mInstrumentation 133 .getUiAutomation() 134 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 135 mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); 136 topActivity.waitAndAssertCallbackInvokedOnActivity(); 137 mPrimaryActivity.waitAndAssertCallbackNotInvoked(); 138 } 139 140 /** Test unregister callback */ 141 @Test testScreencaptureUnregisterCallback()142 public void testScreencaptureUnregisterCallback() { 143 mInstrumentation 144 .getUiAutomation() 145 .adoptShellPermissionIdentity(Manifest.permission.STATUS_BAR_SERVICE); 146 mPrimaryActivity.unregisterScreencaptureCallback(); 147 mWm.notifyScreenshotListeners(DEFAULT_DISPLAY); 148 mPrimaryActivity.waitAndAssertCallbackNotInvoked(); 149 } 150 151 public static class PrimaryActivity extends ScreencaptureCallbackActivity {} 152 153 public static class SecondaryActivity extends ScreencaptureCallbackActivity {} 154 155 private static class ScreencaptureCallbackActivity extends FocusableActivity { 156 private static final long TIMEOUT_SCREENCAPTURE_CALLBACK_INVOKED = 1000; // milliseconds 157 158 private CountDownLatch mCountDownLatch = new CountDownLatch(1); 159 160 final ScreenCaptureCallback mCallback = 161 new ScreenCaptureCallback() { 162 163 @Override 164 public void onScreenCaptured() { 165 mCountDownLatch.countDown(); 166 } 167 }; 168 waitAndAssertCallbackInvokedOnActivity()169 void waitAndAssertCallbackInvokedOnActivity() { 170 try { 171 boolean invoked = mCountDownLatch.await( 172 TIMEOUT_SCREENCAPTURE_CALLBACK_INVOKED, TimeUnit.MILLISECONDS); 173 assertTrue(invoked); 174 } catch (InterruptedException e) { 175 // This shouldn't happen 176 } 177 } 178 waitAndAssertCallbackNotInvoked()179 void waitAndAssertCallbackNotInvoked() { 180 try { 181 boolean invoked = mCountDownLatch.await( 182 TIMEOUT_SCREENCAPTURE_CALLBACK_INVOKED, TimeUnit.MILLISECONDS); 183 assertFalse(invoked); 184 } catch (InterruptedException e) { 185 // This shouldn't happen 186 } 187 } 188 unregisterScreencaptureCallback()189 public void unregisterScreencaptureCallback() { 190 unregisterScreenCaptureCallback(mCallback); 191 } 192 193 @Override onCreate(Bundle savedInstanceState)194 protected void onCreate(Bundle savedInstanceState) { 195 super.onCreate(savedInstanceState); 196 registerScreenCaptureCallback(Executors.newSingleThreadExecutor(), mCallback); 197 } 198 } 199 } 200