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