1 /* 2 * Copyright (C) 2021 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.other; 18 19 import static android.server.wm.app.Components.KEEP_CLEAR_RECTS_ACTIVITY; 20 import static android.server.wm.app.Components.KEEP_CLEAR_RECTS_ACTIVITY2; 21 import static android.server.wm.app.Components.KeepClearRectsActivity.EXTRA_KEEP_CLEAR_RECTS; 22 import static android.view.Display.DEFAULT_DISPLAY; 23 24 import static org.junit.Assert.assertFalse; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assume.assumeTrue; 27 28 import static java.util.Collections.EMPTY_LIST; 29 30 import android.accessibility.cts.common.InstrumentedAccessibilityServiceTestRule; 31 import android.app.Activity; 32 import android.content.ComponentName; 33 import android.content.Intent; 34 import android.graphics.Color; 35 import android.graphics.Rect; 36 import android.os.Bundle; 37 import android.platform.test.annotations.Presubmit; 38 import android.server.wm.WindowManagerState; 39 import android.server.wm.WindowManagerTestBase; 40 import android.server.wm.cts.R; 41 import android.view.Gravity; 42 import android.view.View; 43 import android.view.ViewConfiguration; 44 import android.view.ViewGroup; 45 import android.view.WindowManager; 46 import android.view.accessibility.AccessibilityNodeInfo; 47 import android.widget.RelativeLayout; 48 import android.widget.RelativeLayout.LayoutParams; 49 50 import com.android.compatibility.common.util.ApiTest; 51 import com.android.compatibility.common.util.PollingCheck; 52 53 import org.junit.After; 54 import org.junit.Before; 55 import org.junit.Rule; 56 import org.junit.Test; 57 58 import java.util.ArrayList; 59 import java.util.Arrays; 60 import java.util.Collections; 61 import java.util.List; 62 import java.util.concurrent.Callable; 63 64 @Presubmit 65 public class KeepClearRectsTests extends WindowManagerTestBase { 66 private static final long SAME_ELEMENT_ASSERTION_TIMEOUT = 3000; 67 private static final List<Rect> TEST_KEEP_CLEAR_RECTS = 68 Arrays.asList(new Rect(0, 0, 25, 25), 69 new Rect(30, 0, 50, 25), 70 new Rect(25, 25, 50, 50), 71 new Rect(10, 30, 20, 50)); 72 private static final List<Rect> TEST_KEEP_CLEAR_RECTS_2 = 73 Arrays.asList(new Rect(55, 0, 75, 15), 74 new Rect(50, 15, 60, 25), 75 new Rect(75, 25, 90, 50), 76 new Rect(90, 0, 100, 10)); 77 private static final Rect TEST_VIEW_BOUNDS = new Rect(0, 0, 100, 100); 78 private static final String USE_KEEP_CLEAR_ATTR_LAYOUT = "use_keep_clear_attr_layout"; 79 80 private TestActivitySession<TestActivity> mTestSession; 81 82 @Rule 83 public InstrumentedAccessibilityServiceTestRule<AccessibilityTestService> 84 mAccessibilityServiceRule = new InstrumentedAccessibilityServiceTestRule<>( 85 AccessibilityTestService.class, false); 86 87 @Before setUp()88 public void setUp() throws Exception { 89 super.setUp(); 90 mTestSession = createManagedTestActivitySession(); 91 } 92 93 @After tearDown()94 public void tearDown() throws Exception { 95 mWmState.setSuppressAccessibilityServices(true); 96 } 97 98 @Test 99 @ApiTest(apis = {"android.view.View#attr_android:preferKeepClear"}) testSetPreferKeepClearAttr()100 public void testSetPreferKeepClearAttr() throws Exception { 101 final Intent intent = new Intent(mContext, TestActivity.class); 102 intent.putExtra(USE_KEEP_CLEAR_ATTR_LAYOUT, true); 103 mTestSession.launchTestActivityOnDisplaySync(null, intent, DEFAULT_DISPLAY); 104 final TestActivity activity = mTestSession.getActivity(); 105 106 // To be kept in sync with res/layout/keep_clear_attr_activity 107 final Rect keepClearRect = new Rect(0, 0, 25, 25); 108 assertSameElementsEventually(Arrays.asList(keepClearRect), 109 () -> getKeepClearRectsForActivity(activity)); 110 } 111 112 @Test 113 @ApiTest(apis = {"android.view.View#setPreferKeepClear"}) testSetPreferKeepClearSingleView()114 public void testSetPreferKeepClearSingleView() throws Exception { 115 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 116 final TestActivity activity = mTestSession.getActivity(); 117 118 final Rect keepClearRect = new Rect(0, 0, 25, 25); 119 final View v = createTestViewInActivity(activity, keepClearRect); 120 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 121 122 assertSameElementsEventually(Arrays.asList(keepClearRect), 123 () -> getKeepClearRectsForActivity(activity)); 124 } 125 126 @Test 127 @ApiTest(apis = {"android.view.View#setPreferKeepClear"}) testSetPreferKeepClearTwoViews()128 public void testSetPreferKeepClearTwoViews() throws Exception { 129 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 130 final TestActivity activity = mTestSession.getActivity(); 131 132 final Rect keepClearRect = new Rect(0, 0, 25, 25); 133 final View v = createTestViewInActivity(activity, keepClearRect); 134 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 135 136 final List<Rect> expected = new ArrayList(Arrays.asList(keepClearRect)); 137 assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity)); 138 139 final Rect keepClearRect2 = new Rect(25, 25, 50, 50); 140 final View v2 = createTestViewInActivity(activity, keepClearRect2); 141 mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClear(true)); 142 143 expected.addAll(Arrays.asList(keepClearRect2)); 144 assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity)); 145 } 146 147 @Test 148 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects"}) testSetMultipleKeepClearRectsSingleView()149 public void testSetMultipleKeepClearRectsSingleView() throws Exception { 150 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 151 final TestActivity activity = mTestSession.getActivity(); 152 153 final View v = createTestViewInActivity(activity); 154 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 155 156 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 157 () -> getKeepClearRectsForActivity(activity)); 158 } 159 160 @Test 161 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects"}) testSetMultipleKeepClearRectsTwoViews()162 public void testSetMultipleKeepClearRectsTwoViews() throws Exception { 163 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 164 final TestActivity activity = mTestSession.getActivity(); 165 166 final View v1 = createTestViewInActivity(activity); 167 final View v2 = createTestViewInActivity(activity); 168 mTestSession.runOnMainSyncAndWait(() -> { 169 v1.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS); 170 v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS_2); 171 }); 172 173 final List<Rect> expected = new ArrayList(TEST_KEEP_CLEAR_RECTS); 174 expected.addAll(TEST_KEEP_CLEAR_RECTS_2); 175 assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity)); 176 } 177 178 @Test 179 @ApiTest(apis = {"android.view.View#setPreferKeepClear", 180 "android.view.View#isPreferKeepClear"}) testIsPreferKeepClearSingleView()181 public void testIsPreferKeepClearSingleView() { 182 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 183 final TestActivity activity = mTestSession.getActivity(); 184 185 final Rect viewBounds = new Rect(0, 0, 60, 60); 186 final View v = createTestViewInActivity(activity, viewBounds); 187 assertFalse(v.isPreferKeepClear()); 188 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 189 assertTrue(v.isPreferKeepClear()); 190 191 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(false)); 192 assertFalse(v.isPreferKeepClear()); 193 } 194 195 @Test 196 @ApiTest(apis = {"android.view.View#getPreferKeepClearRects", 197 "android.view.View#setPreferKeepClearRects"}) testGetPreferKeepClearRectsSingleView()198 public void testGetPreferKeepClearRectsSingleView() throws Exception { 199 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 200 final TestActivity activity = mTestSession.getActivity(); 201 202 final Rect viewBounds = new Rect(0, 0, 60, 60); 203 final View v = createTestViewInActivity(activity, viewBounds); 204 assertSameElementsEventually(EMPTY_LIST, () -> v.getPreferKeepClearRects()); 205 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 206 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, () -> v.getPreferKeepClearRects()); 207 208 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS_2)); 209 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS_2, () -> v.getPreferKeepClearRects()); 210 211 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(EMPTY_LIST)); 212 assertSameElementsEventually(EMPTY_LIST, () -> v.getPreferKeepClearRects()); 213 } 214 215 @Test 216 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects", 217 "android.view.View#setPreferKeepClear", 218 "android.view.View#getPreferKeepClearRects", 219 "android.view.View#isPreferKeepClear"}) testGettersPreferKeepClearRectsTwoViews()220 public void testGettersPreferKeepClearRectsTwoViews() throws Exception { 221 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 222 final TestActivity activity = mTestSession.getActivity(); 223 224 final Rect viewBounds1 = new Rect(0, 0, 60, 60); 225 final Rect viewBounds2 = new Rect(0, 0, 90, 90); 226 final View v1 = createTestViewInActivity(activity, viewBounds1); 227 final View v2 = createTestViewInActivity(activity, viewBounds2); 228 mTestSession.runOnMainSyncAndWait(() -> { 229 v1.setPreferKeepClear(true); 230 v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS); 231 }); 232 233 assertTrue(v1.isPreferKeepClear()); 234 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, () -> v2.getPreferKeepClearRects()); 235 236 mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(false)); 237 assertFalse(v1.isPreferKeepClear()); 238 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, () -> v2.getPreferKeepClearRects()); 239 240 mTestSession.runOnMainSyncAndWait(() -> { 241 v1.setPreferKeepClear(true); 242 v2.setPreferKeepClearRects(EMPTY_LIST); 243 }); 244 assertTrue(v1.isPreferKeepClear()); 245 assertSameElementsEventually(EMPTY_LIST, () -> v2.getPreferKeepClearRects()); 246 } 247 248 @Test 249 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects", 250 "android.view.View#setPreferKeepClear"}) testSetPreferKeepClearCombinesWithMultipleRects()251 public void testSetPreferKeepClearCombinesWithMultipleRects() throws Exception { 252 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 253 final TestActivity activity = mTestSession.getActivity(); 254 255 final Rect viewBounds = new Rect(0, 0, 60, 60); 256 final View v = createTestViewInActivity(activity, viewBounds); 257 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 258 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 259 () -> getKeepClearRectsForActivity(activity)); 260 261 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 262 final List<Rect> combinedRects = new ArrayList<>(TEST_KEEP_CLEAR_RECTS); 263 combinedRects.add(viewBounds); 264 assertSameElementsEventually(combinedRects, () -> getKeepClearRectsForActivity(activity)); 265 266 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(false)); 267 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 268 () -> getKeepClearRectsForActivity(activity)); 269 } 270 271 @Test 272 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects", 273 "android.view.View#setPreferKeepClear"}) testIgnoreKeepClearRectsFromGoneViews()274 public void testIgnoreKeepClearRectsFromGoneViews() throws Exception { 275 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 276 final TestActivity activity = mTestSession.getActivity(); 277 278 final Rect viewBounds = new Rect(0, 0, 60, 60); 279 final View v = createTestViewInActivity(activity, viewBounds); 280 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 281 assertSameElementsEventually(Arrays.asList(viewBounds), 282 () -> getKeepClearRectsForActivity(activity)); 283 284 mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.GONE)); 285 assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity)); 286 287 mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.VISIBLE)); 288 assertSameElementsEventually(Arrays.asList(viewBounds), 289 () -> getKeepClearRectsForActivity(activity)); 290 291 mTestSession.runOnMainSyncAndWait(() -> { 292 v.setPreferKeepClear(false); 293 v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS); 294 }); 295 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 296 () -> getKeepClearRectsForActivity(activity)); 297 298 mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.GONE)); 299 assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity)); 300 301 mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.VISIBLE)); 302 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 303 () -> getKeepClearRectsForActivity(activity)); 304 305 final Rect viewBounds2 = new Rect(60, 60, 90, 90); 306 final View v2 = createTestViewInActivity(activity, viewBounds2); 307 mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClear(true)); 308 309 final List<Rect> expected = new ArrayList(TEST_KEEP_CLEAR_RECTS); 310 expected.add(viewBounds2); 311 assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity)); 312 313 mTestSession.runOnMainSyncAndWait(() -> v.setVisibility(View.GONE)); 314 assertSameElementsEventually(Arrays.asList(viewBounds2), 315 () -> getKeepClearRectsForActivity(activity)); 316 317 mTestSession.runOnMainSyncAndWait(() -> { 318 v.setVisibility(View.VISIBLE); 319 v2.setVisibility(View.GONE); 320 }); 321 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 322 () -> getKeepClearRectsForActivity(activity)); 323 324 mTestSession.runOnMainSyncAndWait(() -> { 325 v.setVisibility(View.VISIBLE); 326 v2.setVisibility(View.VISIBLE); 327 }); 328 assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity)); 329 } 330 331 @Test 332 @ApiTest(apis = {"android.view.View#setPreferKeepClear"}) testIgnoreKeepClearRectsFromDetachedViews()333 public void testIgnoreKeepClearRectsFromDetachedViews() throws Exception { 334 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 335 final TestActivity activity = mTestSession.getActivity(); 336 337 final Rect viewBounds = new Rect(0, 0, 60, 60); 338 final View v = createTestViewInActivity(activity, viewBounds); 339 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 340 assertSameElementsEventually(Arrays.asList(viewBounds), 341 () -> getKeepClearRectsForActivity(activity)); 342 343 mTestSession.runOnMainSyncAndWait(() -> ((ViewGroup) v.getParent()).removeView(v)); 344 assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity)); 345 } 346 347 @Test testFocusedViewDeclaredAsKeepClearArea()348 public void testFocusedViewDeclaredAsKeepClearArea() throws Exception { 349 assumeTrue(ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()); 350 351 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 352 final TestActivity activity = mTestSession.getActivity(); 353 354 final Rect viewBounds = new Rect(0, 0, 60, 60); 355 final View v = createTestViewInActivity(activity, viewBounds); 356 assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity)); 357 358 mTestSession.runOnMainSyncAndWait(() -> { 359 v.setFocusableInTouchMode(true); 360 v.setFocusable(true); 361 v.requestFocus(); 362 }); 363 364 assertSameElementsEventually(Arrays.asList(viewBounds), 365 () -> getKeepClearRectsForActivity(activity)); 366 367 mTestSession.runOnMainSyncAndWait(() -> v.setFocusable(false)); 368 assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity)); 369 } 370 371 @Test 372 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects"}) testKeepClearRectsGetTranslatedToWindowSpace()373 public void testKeepClearRectsGetTranslatedToWindowSpace() throws Exception { 374 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 375 final TestActivity activity = mTestSession.getActivity(); 376 377 final Rect viewBounds = new Rect(30, 30, 60, 60); 378 final View v = createTestViewInActivity(activity, viewBounds); 379 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 380 final List<Rect> expected = new ArrayList(); 381 for (Rect r : TEST_KEEP_CLEAR_RECTS) { 382 Rect newRect = new Rect(r); 383 newRect.offset(viewBounds.left, viewBounds.top); 384 expected.add(newRect); 385 } 386 387 assertSameElementsEventually(expected, () -> getKeepClearRectsForActivity(activity)); 388 } 389 390 @Test 391 @ApiTest(apis = {"android.view.View#setPreferKeepClear", 392 "android.view.View#setPreferKeepClearRects"}) testSetKeepClearRectsOnDisplaySingleWindow()393 public void testSetKeepClearRectsOnDisplaySingleWindow() throws Exception { 394 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 395 final TestActivity activity = mTestSession.getActivity(); 396 397 final Rect keepClearRect = new Rect(0, 0, 25, 25); 398 final View v = createTestViewInActivity(activity, keepClearRect); 399 final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay(); 400 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClear(true)); 401 assertSameElementsEventually(Arrays.asList(keepClearRect), 402 () -> getKeepClearRectsForActivity(activity)); 403 404 mTestSession.runOnMainSyncAndWait(() -> { 405 v.setPreferKeepClear(false); 406 v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS); 407 }); 408 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 409 () -> getKeepClearRectsForActivity(activity)); 410 411 final List<Rect> expectedRectsOnDisplay = new ArrayList<Rect>(); 412 expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay); 413 expectedRectsOnDisplay.addAll( 414 getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, activity.getComponentName())); 415 assertSameElementsEventually(expectedRectsOnDisplay, 416 () -> getKeepClearRectsOnDefaultDisplay()); 417 } 418 419 @Test 420 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects"}) testFinishingActivityRemovesItsKeepClearRects()421 public void testFinishingActivityRemovesItsKeepClearRects() throws Exception { 422 final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay(); 423 424 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 425 final TestActivity activity = mTestSession.getActivity(); 426 427 final Rect viewBounds = new Rect(0, 0, 60, 60); 428 final View v = createTestViewInActivity(activity, viewBounds); 429 mTestSession.runOnMainSyncAndWait(() -> v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 430 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 431 () -> getKeepClearRectsForActivity(activity)); 432 433 activity.finishAndRemoveTask(); 434 assertSameElementsEventually(prevKeepClearRectsOnDisplay, 435 () -> getKeepClearRectsOnDefaultDisplay()); 436 } 437 438 @Test 439 @ApiTest(apis = {"android.view.View#setPreferKeepClear"}) testKeepClearRectsOnDisplayTwoWindows()440 public void testKeepClearRectsOnDisplayTwoWindows() throws Exception { 441 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 442 final TestActivity activity = mTestSession.getActivity(); 443 444 final Rect viewBounds = new Rect(0, 0, 25, 25); 445 final View v1 = createTestViewInActivity(activity, viewBounds); 446 mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true)); 447 assertSameElementsEventually(Arrays.asList(viewBounds), 448 () -> getKeepClearRectsForActivity(activity)); 449 450 final String title = "KeepClearRectsTestWindow"; 451 mTestSession.runOnMainSyncAndWait(() -> { 452 final View testView = new View(activity); 453 testView.setPreferKeepClear(true); 454 testView.setBackgroundColor(Color.argb(20, 255, 0, 0)); 455 WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 456 params.gravity = Gravity.TOP | Gravity.START; 457 params.width = 50; 458 params.height = 50; 459 params.setTitle(title); 460 activity.getWindowManager().addView(testView, params); 461 }); 462 mWmState.waitAndAssertWindowSurfaceShown(title, true); 463 464 assertSameElementsEventually(Arrays.asList(viewBounds), 465 () -> getKeepClearRectsForActivity(activity)); 466 } 467 468 @Test 469 @ApiTest(apis = {"android.view.View#setPreferKeepClear", 470 "android.view.View#setPreferKeepClearRects"}) testKeepClearRectsOnDisplayTwoFullscreenActivities()471 public void testKeepClearRectsOnDisplayTwoFullscreenActivities() throws Exception { 472 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 473 final TestActivity activity1 = mTestSession.getActivity(); 474 475 final Rect viewBounds = new Rect(0, 0, 25, 25); 476 final View v1 = createTestViewInActivity(activity1, viewBounds); 477 final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay(); 478 mTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true)); 479 assertSameElementsEventually(Arrays.asList(viewBounds), 480 () -> getKeepClearRectsForActivity(activity1)); 481 482 final TestActivitySession<TranslucentTestActivity> translucentTestSession = 483 createManagedTestActivitySession(); 484 translucentTestSession.launchTestActivityOnDisplaySync( 485 TranslucentTestActivity.class, DEFAULT_DISPLAY); 486 final TestActivity activity2 = translucentTestSession.getActivity(); 487 488 final View v2 = createTestViewInActivity(activity2); 489 mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 490 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 491 () -> getKeepClearRectsForActivity(activity2)); 492 493 mWmState.assertVisibility(activity1.getComponentName(), true); 494 mWmState.assertVisibility(activity2.getComponentName(), true); 495 496 // Since both activities are fullscreen, WM only takes the keep clear areas from the top one 497 final List<Rect> expectedRectsOnDisplay = new ArrayList<Rect>(); 498 expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay); 499 expectedRectsOnDisplay.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, 500 activity2.getComponentName())); 501 assertSameElementsEventually(expectedRectsOnDisplay, 502 () -> getKeepClearRectsOnDefaultDisplay()); 503 } 504 505 @Test 506 @ApiTest(apis = {"android.view.View#setPreferKeepClear", 507 "android.view.View#setPreferKeepClearRects"}) testDisplayHasKeepClearRectsOnlyFromVisibleWindows()508 public void testDisplayHasKeepClearRectsOnlyFromVisibleWindows() throws Exception { 509 final TestActivitySession<TranslucentTestActivity> translucentTestSession = 510 createManagedTestActivitySession(); 511 translucentTestSession.launchTestActivityOnDisplaySync( 512 TranslucentTestActivity.class, DEFAULT_DISPLAY); 513 final TestActivity activity1 = translucentTestSession.getActivity(); 514 final Rect viewBounds = new Rect(0, 0, 25, 25); 515 final View v1 = createTestViewInActivity(activity1, viewBounds); 516 final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay(); 517 translucentTestSession.runOnMainSyncAndWait(() -> v1.setPreferKeepClear(true)); 518 519 // Add keep-clear rects in the activity 520 final List<Rect> expectedRectsOnDisplay = new ArrayList<Rect>(); 521 expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay); 522 expectedRectsOnDisplay.addAll(getRectsInScreenSpace(Arrays.asList(viewBounds), 523 activity1.getComponentName())); 524 assertSameElementsEventually(expectedRectsOnDisplay, 525 () -> getKeepClearRectsOnDefaultDisplay()); 526 527 // Start an opaque activity on top 528 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 529 final TestActivity activity2 = mTestSession.getActivity(); 530 531 // Add keep-clear rects in the opaque activity 532 final View v2 = createTestViewInActivity(activity2); 533 mTestSession.runOnMainSyncAndWait(() -> v2.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS)); 534 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 535 () -> getKeepClearRectsForActivity(activity2)); 536 537 mWmState.waitAndAssertVisibilityGone(activity1.getComponentName()); 538 mWmState.assertVisibility(activity2.getComponentName(), true); 539 540 // Only the opaque activity's keep-clear areas should be reported on the display 541 expectedRectsOnDisplay.clear(); 542 expectedRectsOnDisplay.addAll(prevKeepClearRectsOnDisplay); 543 expectedRectsOnDisplay.addAll(getRectsInScreenSpace( 544 TEST_KEEP_CLEAR_RECTS, activity2.getComponentName())); 545 assertSameElementsEventually(expectedRectsOnDisplay, 546 () -> getKeepClearRectsOnDefaultDisplay()); 547 } 548 549 @Test 550 @ApiTest(apis = {"android.view.View#setPreferKeepClearRects"}) testDisplayHasKeepClearAreasFromTwoActivitiesInSplitscreen()551 public void testDisplayHasKeepClearAreasFromTwoActivitiesInSplitscreen() throws Exception { 552 assumeTrue("Skipping test: no split multi-window support", 553 supportsSplitScreenMultiWindow()); 554 555 startKeepClearActivitiesInSplitscreen(KEEP_CLEAR_RECTS_ACTIVITY, 556 KEEP_CLEAR_RECTS_ACTIVITY2, Collections.emptyList(), Collections.emptyList()); 557 final List<Rect> prevKeepClearRectsOnDisplay = getKeepClearRectsOnDefaultDisplay(); 558 559 removeRootTask(mWmState.getTaskByActivity(KEEP_CLEAR_RECTS_ACTIVITY).getTaskId()); 560 removeRootTask(mWmState.getTaskByActivity(KEEP_CLEAR_RECTS_ACTIVITY2).getTaskId()); 561 562 startKeepClearActivitiesInSplitscreen(KEEP_CLEAR_RECTS_ACTIVITY, 563 KEEP_CLEAR_RECTS_ACTIVITY2, TEST_KEEP_CLEAR_RECTS, TEST_KEEP_CLEAR_RECTS_2); 564 565 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 566 () -> getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY)); 567 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS_2, 568 () -> getKeepClearRectsForActivity(KEEP_CLEAR_RECTS_ACTIVITY2)); 569 570 final List<Rect> expected = new ArrayList(); 571 expected.addAll(prevKeepClearRectsOnDisplay); 572 expected.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS, KEEP_CLEAR_RECTS_ACTIVITY)); 573 expected.addAll(getRectsInScreenSpace(TEST_KEEP_CLEAR_RECTS_2, KEEP_CLEAR_RECTS_ACTIVITY2)); 574 assertSameElementsEventually(expected, () -> getKeepClearRectsOnDefaultDisplay()); 575 } 576 startKeepClearActivitiesInSplitscreen(ComponentName activity1, ComponentName activity2, List<Rect> keepClearRects1, List<Rect> keepClearRects2)577 private void startKeepClearActivitiesInSplitscreen(ComponentName activity1, 578 ComponentName activity2, List<Rect> keepClearRects1, List<Rect> keepClearRects2) { 579 final LaunchActivityBuilder activityBuilder1 = getLaunchActivityBuilder() 580 .setUseInstrumentation() 581 .setTargetActivity(activity1) 582 .setIntentExtra(extra -> { 583 extra.putParcelableArrayList(EXTRA_KEEP_CLEAR_RECTS, 584 new ArrayList(keepClearRects1)); 585 }); 586 587 final LaunchActivityBuilder activityBuilder2 = getLaunchActivityBuilder() 588 .setUseInstrumentation() 589 .setTargetActivity(activity2) 590 .setIntentExtra(extra -> { 591 extra.putParcelableArrayList(EXTRA_KEEP_CLEAR_RECTS, 592 new ArrayList(keepClearRects2)); 593 }); 594 595 launchActivitiesInSplitScreen(activityBuilder1, activityBuilder2); 596 597 waitAndAssertResumedActivity(activity1, activity1 + " must be resumed"); 598 waitAndAssertResumedActivity(activity2, activity2 + " must be resumed"); 599 mWmState.assertVisibility(activity1, true); 600 mWmState.assertVisibility(activity2, true); 601 } 602 603 @Test 604 @ApiTest(apis = {"android.view.View#setUnrestrictedPreferKeepClearRects", 605 "android.view.View#setPreferKeepClearRects"}) testUnrestrictedKeepClearRects()606 public void testUnrestrictedKeepClearRects() throws Exception { 607 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 608 final TestActivity activity = mTestSession.getActivity(); 609 610 final View v = createTestViewInActivity(activity); 611 mTestSession.runOnMainSyncAndWait(() -> { 612 v.setUnrestrictedPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS); 613 }); 614 615 assertSameElementsEventually(EMPTY_LIST, () -> getKeepClearRectsForActivity(activity)); 616 assertSameElementsEventually(EMPTY_LIST, 617 () -> getUnrestrictedKeepClearRectsForActivity(activity)); 618 619 mTestSession.runOnMainSyncAndWait(() -> { 620 v.setPreferKeepClearRects(TEST_KEEP_CLEAR_RECTS); 621 }); 622 623 assertSameElementsEventually(TEST_KEEP_CLEAR_RECTS, 624 () -> getKeepClearRectsForActivity(activity)); 625 assertSameElementsEventually(EMPTY_LIST, 626 () -> getUnrestrictedKeepClearRectsForActivity(activity)); 627 } 628 629 @Test testAccessibilityFocusCreatesKeepClearRect()630 public void testAccessibilityFocusCreatesKeepClearRect() throws Exception { 631 assumeTrue(ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()); 632 633 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 634 final TestActivity activity = mTestSession.getActivity(); 635 636 mWmState.setSuppressAccessibilityServices(false); 637 mAccessibilityServiceRule.enableService(); 638 639 final View v = createTestViewInActivity(activity, TEST_VIEW_BOUNDS); 640 v.setFocusable(false); 641 642 mTestSession.runOnMainSyncAndWait(() -> { 643 v.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 644 }); 645 646 assertSameElementsEventually(Collections.singletonList(TEST_VIEW_BOUNDS), 647 () -> getKeepClearRectsForActivity(activity)); 648 } 649 650 @Test testAccessibilityAndInputFocusCreateKeepClearRects()651 public void testAccessibilityAndInputFocusCreateKeepClearRects() throws Exception { 652 assumeTrue(ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()); 653 654 mTestSession.launchTestActivityOnDisplaySync(TestActivity.class, DEFAULT_DISPLAY); 655 final TestActivity activity = mTestSession.getActivity(); 656 657 mWmState.setSuppressAccessibilityServices(false); 658 mAccessibilityServiceRule.enableService(); 659 660 final Rect a11yFocusViewBounds = new Rect(30, 0, 50, 25); 661 final Rect inputFocusViewBounds = new Rect(0, 0, 25, 25); 662 663 final View a11yFocusView = createTestViewInActivity(activity, a11yFocusViewBounds); 664 final View inputFocusView = createTestViewInActivity(activity, inputFocusViewBounds); 665 666 mTestSession.runOnMainSyncAndWait(() -> { 667 a11yFocusView.performAccessibilityAction( 668 AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); 669 670 inputFocusView.setFocusableInTouchMode(true); 671 inputFocusView.setFocusable(true); 672 inputFocusView.requestFocus(); 673 }); 674 675 assertSameElementsEventually(Arrays.asList(a11yFocusViewBounds, inputFocusViewBounds), 676 () -> getKeepClearRectsForActivity(activity)); 677 } 678 createTestViewInActivity(TestActivity activity)679 private View createTestViewInActivity(TestActivity activity) { 680 return createTestViewInActivity(activity, TEST_VIEW_BOUNDS); 681 } 682 createTestViewInActivity(TestActivity activity, Rect viewBounds)683 private View createTestViewInActivity(TestActivity activity, Rect viewBounds) { 684 final View newView = new View(activity); 685 final LayoutParams params = new LayoutParams(viewBounds.width(), viewBounds.height()); 686 params.leftMargin = viewBounds.left; 687 params.topMargin = viewBounds.top; 688 mTestSession.runOnMainSyncAndWait(() -> { 689 activity.addView(newView, params); 690 }); 691 waitForIdle(); 692 return newView; 693 } 694 getKeepClearRectsForActivity(Activity activity)695 private List<Rect> getKeepClearRectsForActivity(Activity activity) { 696 return getKeepClearRectsForActivity(activity.getComponentName()); 697 } 698 getKeepClearRectsForActivity(ComponentName activityComponent)699 private List<Rect> getKeepClearRectsForActivity(ComponentName activityComponent) { 700 mWmState.computeState(); 701 return mWmState.getWindowState(activityComponent).getKeepClearRects(); 702 } 703 getKeepClearRectsOnDefaultDisplay()704 private List<Rect> getKeepClearRectsOnDefaultDisplay() { 705 mWmState.computeState(); 706 return mWmState.getDisplay(DEFAULT_DISPLAY).getKeepClearRects(); 707 } 708 getUnrestrictedKeepClearRectsForActivity(Activity activity)709 private List<Rect> getUnrestrictedKeepClearRectsForActivity(Activity activity) { 710 mWmState.computeState(); 711 return mWmState.getWindowState(activity.getComponentName()).getUnrestrictedKeepClearRects(); 712 } 713 714 public static class TestActivity extends FocusableActivity { 715 private RelativeLayout mRootView; 716 addView(View v, LayoutParams params)717 public void addView(View v, LayoutParams params) { 718 mRootView.addView(v, params); 719 } 720 721 @Override onCreate(Bundle savedInstanceState)722 protected void onCreate(Bundle savedInstanceState) { 723 super.onCreate(savedInstanceState); 724 if (getIntent().getBooleanExtra(USE_KEEP_CLEAR_ATTR_LAYOUT, false)) { 725 setContentView(R.layout.keep_clear_attr_activity); 726 } else { 727 setContentView(R.layout.keep_clear_rects_activity); 728 } 729 mRootView = findViewById(R.id.root); 730 731 getWindow().setDecorFitsSystemWindows(false); 732 } 733 } 734 735 public static class TranslucentTestActivity extends TestActivity {} 736 getRectsInScreenSpace(List<Rect> rects, ComponentName componentName)737 private List<Rect> getRectsInScreenSpace(List<Rect> rects, ComponentName componentName) { 738 mWmState.computeState(); 739 final WindowManagerState.WindowState windowState = 740 mWmState.getWindowState(componentName); 741 final List<Rect> result = new ArrayList<>(); 742 for (Rect r : rects) { 743 Rect rectInScreenSpace = new Rect(r); 744 rectInScreenSpace.offset(windowState.getFrame().left, windowState.getFrame().top); 745 result.add(rectInScreenSpace); 746 } 747 return result; 748 } 749 assertSameElementsEventually(List<T> expected, Callable<List<T>> actual)750 private static <T> void assertSameElementsEventually(List<T> expected, Callable<List<T>> actual) 751 throws Exception { 752 PollingCheck.check("Lists do not have the same elements." 753 + "Expected=" + expected + ", actual=" + actual.call(), 754 SAME_ELEMENT_ASSERTION_TIMEOUT, 755 () -> hasSameElements(expected, actual.call())); 756 } 757 hasSameElements(List<T> fst, List<T> snd)758 private static <T> boolean hasSameElements(List<T> fst, List<T> snd) { 759 if (fst.size() != snd.size()) return false; 760 761 for (T a : fst) { 762 if (!snd.contains(a)) { 763 return false; 764 } 765 } 766 return true; 767 } 768 } 769