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