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