• 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.server.wm.WindowManagerTestBase.startActivity;
20 import static android.view.WindowInsets.Type.captionBar;
21 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
22 
23 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
24 
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertTrue;
28 
29 import android.app.UiAutomation;
30 import android.content.ComponentName;
31 import android.graphics.Bitmap;
32 import android.graphics.Color;
33 import android.graphics.Rect;
34 import android.os.Bundle;
35 import android.view.SurfaceControl;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.view.WindowInsets;
39 import android.view.WindowInsetsController;
40 import android.view.WindowManager;
41 import android.view.cts.surfacevalidator.BitmapPixelChecker;
42 import android.window.SplashScreen;
43 
44 import androidx.annotation.Nullable;
45 import androidx.test.platform.app.InstrumentationRegistry;
46 
47 import org.junit.After;
48 import org.junit.Before;
49 import org.junit.Test;
50 
51 import java.util.concurrent.CountDownLatch;
52 import java.util.concurrent.TimeUnit;
53 
54 /* Build/Install/Run:
55  *     atest CtsWindowManagerDeviceTestCases:SnapshotTaskTests
56  */
57 public class SnapshotTaskTests extends ActivityManagerTestBase {
58     private static final String TAG = "SnapshotTaskTests";
59     private static final ComponentName TEST_ACTIVITY = new ComponentName(
60             getInstrumentation().getContext(), TestActivity.class);
61 
62     private TestActivity mActivity;
63     private WindowManager mWindowManager;
64     private UiAutomation mUiAutomation;
65 
66     private static final int MATCHING_PIXEL_MISMATCH_ALLOWED = 100;
67 
68     @Before
setup()69     public void setup() throws Exception {
70         super.setUp();
71         mActivity = startActivity(TestActivity.class);
72 
73         mWindowManager = mActivity.getSystemService(WindowManager.class);
74         mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
75         mUiAutomation.adoptShellPermissionIdentity();
76 
77         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
78         mActivity.waitUntilReady();
79     }
80 
81     @After
cleanup()82     public void cleanup() {
83         mUiAutomation.dropShellPermissionIdentity();
84     }
85 
86     @Test
testSetDisablePreviewScreenshots()87     public void testSetDisablePreviewScreenshots() throws Exception {
88         final View decor = mActivity.getWindow().getDecorView();
89         final int captionBarHeight = decor.getRootWindowInsets().getInsets(captionBar()).top;
90 
91         BitmapPixelChecker pixelChecker = new BitmapPixelChecker(Color.RED);
92 
93         int retries = 0;
94         boolean matchesPixels = false;
95         while (retries < 5) {
96             Bitmap bitmap = mWindowManager.snapshotTaskForRecents(mActivity.getTaskId());
97             if (bitmap != null) {
98                 int expectedMatching =
99                         bitmap.getWidth() * bitmap.getHeight() - MATCHING_PIXEL_MISMATCH_ALLOWED
100                                 - (captionBarHeight * decor.getWidth());
101                 Rect boundToCheck = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
102                 int matchingPixels = pixelChecker.getNumMatchingPixels(bitmap, boundToCheck);
103                 matchesPixels = matchingPixels >= expectedMatching;
104             }
105             if (matchesPixels) {
106                 break;
107             }
108             retries++;
109             Thread.sleep(1000);
110         }
111 
112         assertTrue(matchesPixels);
113 
114         mActivity.setRecentsScreenshotEnabled(false);
115 
116         retries = 0;
117         WindowManagerState.Activity activityContainer = null;
118         boolean enableScreenshot = true;
119         while (retries < 3) {
120             mWmState.computeState();
121             activityContainer = mWmState.getActivity(TEST_ACTIVITY);
122             if (activityContainer != null) {
123                 enableScreenshot = activityContainer.enableRecentsScreenshot();
124             }
125             if (enableScreenshot) {
126                 break;
127             }
128             retries++;
129             Thread.sleep(500);
130         }
131         assertFalse("Recents screenshots should be disabled", enableScreenshot);
132 
133         Bitmap bitmap = mWindowManager.snapshotTaskForRecents(mActivity.getTaskId());
134         assertNotNull(bitmap);
135         Rect boundToCheck = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
136         int matchingPixels = pixelChecker.getNumMatchingPixels(bitmap, boundToCheck);
137         assertTrue("Expected <=" + MATCHING_PIXEL_MISMATCH_ALLOWED + " matched " + matchingPixels,
138                 matchingPixels <= MATCHING_PIXEL_MISMATCH_ALLOWED);
139     }
140 
141     public static class TestActivity extends WindowManagerTestBase.FocusableActivity {
142         private final CountDownLatch mReadyToStart = new CountDownLatch(3);
143 
144         @Override
onEnterAnimationComplete()145         public void onEnterAnimationComplete() {
146             mReadyToStart.countDown();
147         }
148 
waitUntilReady()149         public void waitUntilReady() throws InterruptedException {
150             mReadyToStart.await(5, TimeUnit.SECONDS);
151         }
152 
153         @Override
onAttachedToWindow()154         public void onAttachedToWindow() {
155             super.onAttachedToWindow();
156 
157             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
158             t.addTransactionCommittedListener(getMainExecutor(),
159                     mReadyToStart::countDown);
160             getWindow().getDecorView().getRootSurfaceControl().applyTransactionOnDraw(t);
161         }
162 
163         @Override
onCreate(@ullable Bundle savedInstanceState)164         protected void onCreate(@Nullable Bundle savedInstanceState) {
165             super.onCreate(savedInstanceState);
166             View view = new View(this);
167             view.setBackgroundColor(Color.RED);
168             WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
169                     ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
170             setContentView(view, layoutParams);
171 
172             WindowInsetsController windowInsetsController = getWindow().getInsetsController();
173             windowInsetsController.hide(
174                     WindowInsets.Type.navigationBars() | WindowInsets.Type.statusBars());
175             WindowManager.LayoutParams params = getWindow().getAttributes();
176             params.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
177             getWindow().setAttributes(params);
178             getWindow().setDecorFitsSystemWindows(false);
179 
180             SplashScreen splashscreen = getSplashScreen();
181             splashscreen.setOnExitAnimationListener(splashView -> {
182                 splashView.remove();
183                 mReadyToStart.countDown();
184             });
185         }
186     }
187 }
188