1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui;
16 
17 import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
18 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
19 import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
20 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
21 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
22 
23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
24 import static com.android.systemui.dump.LogBufferHelperKt.logcatLogBuffer;
25 
26 import static com.google.common.truth.Truth.assertThat;
27 
28 import static org.hamcrest.Matchers.is;
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertFalse;
31 import static org.junit.Assert.assertNotNull;
32 import static org.junit.Assert.assertNull;
33 import static org.junit.Assert.assertThat;
34 import static org.junit.Assert.assertTrue;
35 import static org.junit.Assert.fail;
36 import static org.mockito.ArgumentMatchers.any;
37 import static org.mockito.ArgumentMatchers.anyInt;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.ArgumentMatchers.isA;
40 import static org.mockito.Mockito.clearInvocations;
41 import static org.mockito.Mockito.doAnswer;
42 import static org.mockito.Mockito.doNothing;
43 import static org.mockito.Mockito.doReturn;
44 import static org.mockito.Mockito.mock;
45 import static org.mockito.Mockito.never;
46 import static org.mockito.Mockito.spy;
47 import static org.mockito.Mockito.times;
48 import static org.mockito.Mockito.verify;
49 import static org.mockito.Mockito.when;
50 
51 import android.annotation.IdRes;
52 import android.content.pm.PackageManager;
53 import android.content.res.Configuration;
54 import android.content.res.TypedArray;
55 import android.graphics.Path;
56 import android.graphics.PixelFormat;
57 import android.graphics.Rect;
58 import android.graphics.drawable.Drawable;
59 import android.hardware.display.DisplayManager;
60 import android.hardware.graphics.common.DisplayDecorationSupport;
61 import android.os.Handler;
62 import android.testing.AndroidTestingRunner;
63 import android.testing.TestableLooper;
64 import android.testing.TestableLooper.RunWithLooper;
65 import android.util.PathParser;
66 import android.util.Size;
67 import android.view.Display;
68 import android.view.DisplayCutout;
69 import android.view.DisplayInfo;
70 import android.view.Surface;
71 import android.view.View;
72 import android.view.ViewGroup;
73 import android.view.WindowManager;
74 import android.view.WindowMetrics;
75 
76 import androidx.annotation.DrawableRes;
77 import androidx.annotation.NonNull;
78 import androidx.annotation.Nullable;
79 import androidx.test.filters.SmallTest;
80 
81 import com.android.keyguard.KeyguardUpdateMonitor;
82 import com.android.systemui.biometrics.AuthController;
83 import com.android.systemui.decor.CornerDecorProvider;
84 import com.android.systemui.decor.CutoutDecorProviderFactory;
85 import com.android.systemui.decor.CutoutDecorProviderImpl;
86 import com.android.systemui.decor.DebugRoundedCornerModel;
87 import com.android.systemui.decor.DecorProvider;
88 import com.android.systemui.decor.DecorProviderFactory;
89 import com.android.systemui.decor.FaceScanningOverlayProviderImpl;
90 import com.android.systemui.decor.FaceScanningProviderFactory;
91 import com.android.systemui.decor.OverlayWindow;
92 import com.android.systemui.decor.PrivacyDotCornerDecorProviderImpl;
93 import com.android.systemui.decor.PrivacyDotDecorProviderFactory;
94 import com.android.systemui.decor.RoundedCornerResDelegate;
95 import com.android.systemui.flags.FakeFeatureFlags;
96 import com.android.systemui.flags.Flags;
97 import com.android.systemui.log.ScreenDecorationsLogger;
98 import com.android.systemui.plugins.statusbar.StatusBarStateController;
99 import com.android.systemui.settings.FakeDisplayTracker;
100 import com.android.systemui.settings.UserTracker;
101 import com.android.systemui.statusbar.commandline.CommandRegistry;
102 import com.android.systemui.statusbar.events.PrivacyDotViewController;
103 import com.android.systemui.util.concurrency.FakeExecutor;
104 import com.android.systemui.util.concurrency.FakeThreadFactory;
105 import com.android.systemui.util.settings.FakeSettings;
106 import com.android.systemui.util.settings.SecureSettings;
107 import com.android.systemui.util.time.FakeSystemClock;
108 
109 import org.junit.Before;
110 import org.junit.Test;
111 import org.junit.runner.RunWith;
112 import org.mockito.ArgumentCaptor;
113 import org.mockito.Captor;
114 import org.mockito.Mock;
115 import org.mockito.MockitoAnnotations;
116 import org.mockito.invocation.InvocationOnMock;
117 import org.mockito.stubbing.Answer;
118 
119 import java.util.ArrayList;
120 import java.util.List;
121 
122 @RunWithLooper
123 @RunWith(AndroidTestingRunner.class)
124 @SmallTest
125 public class ScreenDecorationsTest extends SysuiTestCase {
126 
127     private ScreenDecorations mScreenDecorations;
128     private WindowManager mWindowManager;
129     private DisplayManager mDisplayManager;
130     private SecureSettings mSecureSettings;
131     private FakeExecutor mExecutor;
132     private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
133     private FakeThreadFactory mThreadFactory;
134     private ArrayList<DecorProvider> mPrivacyDecorProviders;
135     private ArrayList<DecorProvider> mFaceScanningProviders;
136     @Mock
137     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
138     @Mock
139     private StatusBarStateController mStatusBarStateController;
140     @Mock
141     private AuthController mAuthController;
142     @Mock
143     private Display mDisplay;
144     @Mock
145     private CommandRegistry mCommandRegistry;
146     @Mock
147     private UserTracker mUserTracker;
148     @Mock
149     private PrivacyDotViewController mDotViewController;
150     @Mock
151     private TypedArray mMockTypedArray;
152     @Mock
153     private PrivacyDotDecorProviderFactory mPrivacyDotDecorProviderFactory;
154     @Mock
155     private FaceScanningProviderFactory mFaceScanningProviderFactory;
156     @Mock
157     private FaceScanningOverlayProviderImpl mFaceScanningDecorProvider;
158     @Mock
159     private CornerDecorProvider mPrivacyDotTopLeftDecorProvider;
160     @Mock
161     private CornerDecorProvider mPrivacyDotTopRightDecorProvider;
162     @Mock
163     private CornerDecorProvider mPrivacyDotBottomLeftDecorProvider;
164     @Mock
165     private CornerDecorProvider mPrivacyDotBottomRightDecorProvider;
166     @Mock
167     private Display.Mode mDisplayMode;
168     @Mock
169     private DisplayInfo mDisplayInfo;
170     private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener;
171     @Mock
172     private CutoutDecorProviderFactory mCutoutFactory;
173     @Captor
174     private ArgumentCaptor<AuthController.Callback> mAuthControllerCallback;
175     private List<DecorProvider> mMockCutoutList;
176 
177     @Before
setup()178     public void setup() {
179         MockitoAnnotations.initMocks(this);
180 
181         Handler mainHandler = new Handler(TestableLooper.get(this).getLooper());
182         mSecureSettings = new FakeSettings();
183         mExecutor = new FakeExecutor(new FakeSystemClock());
184         mThreadFactory = new FakeThreadFactory(mExecutor);
185         mThreadFactory.setHandler(mainHandler);
186 
187         mWindowManager = mock(WindowManager.class);
188         WindowMetrics metrics = mContext.getSystemService(WindowManager.class)
189                 .getMaximumWindowMetrics();
190         when(mWindowManager.getMaximumWindowMetrics()).thenReturn(metrics);
191         mContext.addMockSystemService(WindowManager.class, mWindowManager);
192         mDisplayManager = mock(DisplayManager.class);
193         mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
194 
195         spyOn(mContext);
196         when(mContext.getDisplay()).thenReturn(mDisplay);
197         // Not support hwc layer by default
198         doReturn(null).when(mDisplay).getDisplayDecorationSupport();
199         doReturn(mDisplayMode).when(mDisplayInfo).getMode();
200 
201         when(mMockTypedArray.length()).thenReturn(0);
202         mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
203                 R.id.privacy_dot_top_left_container,
204                 DisplayCutout.BOUNDS_POSITION_TOP,
205                 DisplayCutout.BOUNDS_POSITION_LEFT,
206                 R.layout.privacy_dot_top_left));
207 
208         mPrivacyDotTopRightDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
209                 R.id.privacy_dot_top_right_container,
210                 DisplayCutout.BOUNDS_POSITION_TOP,
211                 DisplayCutout.BOUNDS_POSITION_RIGHT,
212                 R.layout.privacy_dot_top_right));
213 
214         mPrivacyDotBottomLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
215                 R.id.privacy_dot_bottom_left_container,
216                 DisplayCutout.BOUNDS_POSITION_BOTTOM,
217                 DisplayCutout.BOUNDS_POSITION_LEFT,
218                 R.layout.privacy_dot_bottom_left));
219 
220         mPrivacyDotBottomRightDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl(
221                 R.id.privacy_dot_bottom_right_container,
222                 DisplayCutout.BOUNDS_POSITION_BOTTOM,
223                 DisplayCutout.BOUNDS_POSITION_RIGHT,
224                 R.layout.privacy_dot_bottom_right));
225 
226         // Default no cutout
227         mMockCutoutList = new ArrayList<>();
228         doAnswer(it -> !(mMockCutoutList.isEmpty())).when(mCutoutFactory).getHasProviders();
229         doReturn(mMockCutoutList).when(mCutoutFactory).getProviders();
230 
231         FakeFeatureFlags featureFlags = new FakeFeatureFlags();
232         featureFlags.set(Flags.STOP_PULSING_FACE_SCANNING_ANIMATION, true);
233         mFaceScanningDecorProvider = spy(new FaceScanningOverlayProviderImpl(
234                 BOUNDS_POSITION_TOP,
235                 mAuthController,
236                 mStatusBarStateController,
237                 mKeyguardUpdateMonitor,
238                 mExecutor,
239                 new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")),
240                 featureFlags));
241 
242         mScreenDecorations = spy(new ScreenDecorations(mContext, mSecureSettings,
243                 mCommandRegistry, mUserTracker, mDisplayTracker, mDotViewController,
244                 mThreadFactory,
245                 mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory,
246                 new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")),
247                 mAuthController) {
248             @Override
249             public void start() {
250                 super.start();
251                 mExecutor.runAllReady();
252             }
253 
254             @Override
255             public void onConfigurationChanged(Configuration newConfig) {
256                 super.onConfigurationChanged(newConfig);
257                 mExecutor.runAllReady();
258             }
259 
260             @Override
261             protected void updateOverlayWindowVisibilityIfViewExists(@Nullable View view) {
262                 super.updateOverlayWindowVisibilityIfViewExists(view);
263                 mExecutor.runAllReady();
264             }
265 
266             @Override
267             protected CutoutDecorProviderFactory getCutoutFactory() {
268                 return ScreenDecorationsTest.this.mCutoutFactory;
269             }
270         });
271         mScreenDecorations.mDisplayInfo = mDisplayInfo;
272         // Make sure tests are never run starting in debug mode
273         mScreenDecorations.setDebug(false);
274         doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
275         doNothing().when(mScreenDecorations).updateOverlayProviderViews(any());
276 
277         try {
278             mPrivacyDotShowingListener = mScreenDecorations.mPrivacyDotShowingListener.getClass()
279                     .getDeclaredConstructor(ScreenDecorations.class)
280                     .newInstance(mScreenDecorations);
281         } catch (Exception e) {
282             fail(e.getMessage());
283         }
284     }
285 
286     @NonNull
getRoundCornerIdsFromOverlayId(@isplayCutout.BoundsPosition int overlayId)287     private int[] getRoundCornerIdsFromOverlayId(@DisplayCutout.BoundsPosition int overlayId) {
288         switch (overlayId) {
289             case BOUNDS_POSITION_LEFT:
290                 return new int[] {
291                         R.id.rounded_corner_top_left,
292                         R.id.rounded_corner_top_left };
293             case BOUNDS_POSITION_TOP:
294                 return new int[] {
295                         R.id.rounded_corner_top_left,
296                         R.id.rounded_corner_top_right };
297             case BOUNDS_POSITION_RIGHT:
298                 return new int[] {
299                         R.id.rounded_corner_top_right,
300                         R.id.rounded_corner_bottom_right };
301             case BOUNDS_POSITION_BOTTOM:
302                 return new int[] {
303                         R.id.rounded_corner_bottom_left,
304                         R.id.rounded_corner_bottom_right };
305             default:
306                 throw new IllegalArgumentException("unknown overlayId: " + overlayId);
307         }
308     }
309 
verifyRoundedCornerViewsExist( @isplayCutout.BoundsPosition final int overlayId, @View.Visibility final boolean isExist)310     private void verifyRoundedCornerViewsExist(
311             @DisplayCutout.BoundsPosition final int overlayId,
312             @View.Visibility final boolean isExist) {
313         final View overlay = mScreenDecorations.mOverlays[overlayId].getRootView();
314         for (int id: getRoundCornerIdsFromOverlayId(overlayId)) {
315             final View view = overlay.findViewById(id);
316             if (isExist) {
317                 assertNotNull(view);
318                 assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
319             } else {
320                 assertNull(view);
321             }
322         }
323     }
324 
verifyFaceScanningViewExists(final boolean exists)325     private void verifyFaceScanningViewExists(final boolean exists) {
326         final View overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView();
327         final View view = overlay.findViewById(mFaceScanningDecorProvider.getViewId());
328         if (exists) {
329             assertNotNull(view);
330         } else {
331             assertNull(view);
332         }
333     }
334 
335     @Nullable
findViewFromOverlays(@dRes int id)336     private View findViewFromOverlays(@IdRes int id) {
337         for (OverlayWindow overlay: mScreenDecorations.mOverlays) {
338             if (overlay == null) {
339                 continue;
340             }
341 
342             View view = overlay.getRootView().findViewById(id);
343             if (view != null) {
344                 return view;
345             }
346         }
347         return null;
348     }
349 
verifyTopDotViewsNullable(final boolean isAssertNull)350     private void verifyTopDotViewsNullable(final boolean isAssertNull) {
351         View tl = findViewFromOverlays(R.id.privacy_dot_top_left_container);
352         View tr = findViewFromOverlays(R.id.privacy_dot_top_right_container);
353         if (isAssertNull) {
354             assertNull(tl);
355             assertNull(tr);
356         } else {
357             assertNotNull(tl);
358             assertNotNull(tr);
359         }
360     }
361 
verifyBottomDotViewsNullable(final boolean isAssertNull)362     private void verifyBottomDotViewsNullable(final boolean isAssertNull) {
363         View bl = findViewFromOverlays(R.id.privacy_dot_bottom_left_container);
364         View br = findViewFromOverlays(R.id.privacy_dot_bottom_right_container);
365         if (isAssertNull) {
366             assertNull(bl);
367             assertNull(br);
368         } else {
369             assertNotNull(bl);
370             assertNotNull(br);
371         }
372     }
373 
verifyDotViewsNullable(final boolean isAssertNull)374     private void verifyDotViewsNullable(final boolean isAssertNull) {
375         verifyTopDotViewsNullable(isAssertNull);
376         verifyBottomDotViewsNullable(isAssertNull);
377     }
378 
verifyTopDotViewsVisibility(@iew.Visibility final int visibility)379     private void verifyTopDotViewsVisibility(@View.Visibility final int visibility) {
380         verifyTopDotViewsNullable(false);
381         View tl = findViewFromOverlays(R.id.privacy_dot_top_left_container);
382         View tr = findViewFromOverlays(R.id.privacy_dot_top_right_container);
383         assertThat(tl.getVisibility()).isEqualTo(visibility);
384         assertThat(tr.getVisibility()).isEqualTo(visibility);
385     }
386 
verifyBottomDotViewsVisibility(@iew.Visibility final int visibility)387     private void verifyBottomDotViewsVisibility(@View.Visibility final int visibility) {
388         verifyBottomDotViewsNullable(false);
389         View bl = findViewFromOverlays(R.id.privacy_dot_bottom_left_container);
390         View br = findViewFromOverlays(R.id.privacy_dot_bottom_right_container);
391         assertThat(bl.getVisibility()).isEqualTo(visibility);
392         assertThat(br.getVisibility()).isEqualTo(visibility);
393     }
394 
verifyDotViewsVisibility(@iew.Visibility final int visibility)395     private void verifyDotViewsVisibility(@View.Visibility final int visibility) {
396         verifyTopDotViewsVisibility(visibility);
397         verifyBottomDotViewsVisibility(visibility);
398     }
399 
verifyOverlaysExistAndAdded(boolean left, boolean top, boolean right, boolean bottom, @Nullable Integer visibilityIfExist)400     private void verifyOverlaysExistAndAdded(boolean left, boolean top, boolean right,
401             boolean bottom, @Nullable Integer visibilityIfExist) {
402         if (left || top || right || bottom) {
403             assertNotNull(mScreenDecorations.mOverlays);
404         } else {
405             assertNull(mScreenDecorations.mOverlays);
406             return;
407         }
408 
409         if (left) {
410             final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT];
411             assertNotNull(overlay);
412             verify(mWindowManager, times(1)).addView(
413                     eq(overlay.getRootView()), any());
414             if (visibilityIfExist != null) {
415                 assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
416             }
417         } else {
418             assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]);
419         }
420 
421         if (top) {
422             final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP];
423             assertNotNull(overlay);
424             verify(mWindowManager, times(1)).addView(
425                     eq(overlay.getRootView()), any());
426             if (visibilityIfExist != null) {
427                 assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
428             }
429         } else {
430             assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]);
431         }
432 
433         if (right) {
434             final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT];
435             assertNotNull(overlay);
436             verify(mWindowManager, times(1)).addView(
437                     eq(overlay.getRootView()), any());
438             if (visibilityIfExist != null) {
439                 assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
440             }
441         } else {
442             assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]);
443         }
444 
445         if (bottom) {
446             final OverlayWindow overlay = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM];
447             assertNotNull(overlay);
448             verify(mWindowManager, times(1)).addView(
449                     eq(overlay.getRootView()), any());
450             if (visibilityIfExist != null) {
451                 assertEquals(visibilityIfExist.intValue(), overlay.getRootView().getVisibility());
452             }
453         } else {
454             assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]);
455         }
456     }
457 
458     @Test
testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning()459     public void testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
460         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
461                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
462                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
463 
464         // no cutout (default)
465 
466         mScreenDecorations.start();
467         // No views added.
468         verifyOverlaysExistAndAdded(false, false, false, false, null);
469         // No dot controller init
470         verify(mDotViewController, never()).initialize(any(), any(), any(), any());
471     }
472 
473     @Test
testNoRounding_NoCutout_PrivacyDot_NoFaceScanning()474     public void testNoRounding_NoCutout_PrivacyDot_NoFaceScanning() {
475         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
476                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
477                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
478 
479         // no cutout (default)
480 
481         mScreenDecorations.start();
482 
483         // Top and bottom windows are created with INVISIBLE because of privacy dot only
484         // Left and right window should be null.
485         verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
486         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
487         verify(mDotViewController, times(1)).setShowingListener(
488                 mScreenDecorations.mPrivacyDotShowingListener);
489 
490         // Rounded corner views shall not exist
491         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
492         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
493 
494         // Privacy dots shall exist but invisible
495         verifyDotViewsVisibility(View.INVISIBLE);
496 
497         // Face scanning doesn't exist
498         verifyFaceScanningViewExists(false);
499 
500         // Dot controller init
501         verify(mDotViewController, times(1)).initialize(
502                 isA(View.class), isA(View.class), isA(View.class), isA(View.class));
503     }
504 
505     @Test
testRounding_NoCutout_NoPrivacyDot_NoFaceScanning()506     public void testRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
507         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
508                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
509                 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
510 
511         // no cutout (default)
512 
513         mScreenDecorations.start();
514 
515         // Top and bottom windows are created for rounded corners.
516         // Left and right window should be null.
517         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
518 
519         // Rounded corner views shall exist
520         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
521         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
522 
523         // Privacy dots shall not exist
524         verifyDotViewsNullable(true);
525 
526         // Face scanning doesn't exist
527         verifyFaceScanningViewExists(false);
528 
529         // No dot controller init
530         verify(mDotViewController, never()).initialize(any(), any(), any(), any());
531     }
532 
533     @Test
testRounding_NoCutout_PrivacyDot_NoFaceScanning()534     public void testRounding_NoCutout_PrivacyDot_NoFaceScanning() {
535         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
536                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
537                 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
538 
539         // no cutout (default)
540 
541         mScreenDecorations.start();
542 
543         // Top and bottom windows are created for rounded corners.
544         // Left and right window should be null.
545         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
546         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
547         verify(mDotViewController, times(1)).setShowingListener(null);
548 
549         // Rounded corner views shall exist
550         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
551         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
552 
553         // Privacy dots shall exist but invisible
554         verifyDotViewsVisibility(View.INVISIBLE);
555 
556         // Face scanning doesn't exist
557         verifyFaceScanningViewExists(false);
558 
559         // Dot controller init
560         verify(mDotViewController, times(1)).initialize(
561                 isA(View.class), isA(View.class), isA(View.class), isA(View.class));
562     }
563 
564     @Test
testRoundingRadius_NoCutout()565     public void testRoundingRadius_NoCutout() {
566         final Size testRadiusPoint = new Size(3, 3);
567         setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
568                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
569                 /* roundedTopDrawable */,
570                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
571                 /* roundedBottomDrawable */,
572                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
573 
574         // no cutout (default)
575 
576         mScreenDecorations.start();
577         // Size of corner view should same as rounded_corner_radius{_top|_bottom}
578         final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
579         assertThat(resDelegate.getTopRoundedSize()).isEqualTo(testRadiusPoint);
580         assertThat(resDelegate.getBottomRoundedSize()).isEqualTo(testRadiusPoint);
581     }
582 
583     @Test
testRoundingTopBottomRadius_OnTopBottomOverlay()584     public void testRoundingTopBottomRadius_OnTopBottomOverlay() {
585         setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
586                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
587                 /* roundedTopDrawable */,
588                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
589                 /* roundedBottomDrawable */,
590                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
591 
592         // no cutout (default)
593 
594         mScreenDecorations.start();
595         View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
596                 .findViewById(R.id.rounded_corner_top_left);
597         View rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
598                 .findViewById(R.id.rounded_corner_top_right);
599         ViewGroup.LayoutParams leftParams = leftRoundedCorner.getLayoutParams();
600         ViewGroup.LayoutParams rightParams = rightRoundedCorner.getLayoutParams();
601         assertEquals(4, leftParams.width);
602         assertEquals(4, leftParams.height);
603         assertEquals(4, rightParams.width);
604         assertEquals(4, rightParams.height);
605 
606         leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
607                 .findViewById(R.id.rounded_corner_bottom_left);
608         rightRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
609                 .findViewById(R.id.rounded_corner_bottom_right);
610         leftParams = leftRoundedCorner.getLayoutParams();
611         rightParams = rightRoundedCorner.getLayoutParams();
612         assertEquals(3, leftParams.width);
613         assertEquals(3, leftParams.height);
614         assertEquals(3, rightParams.width);
615         assertEquals(3, rightParams.height);
616     }
617 
618     @Test
testRoundingTopBottomRadius_OnLeftRightOverlay()619     public void testRoundingTopBottomRadius_OnLeftRightOverlay() {
620         setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
621                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
622                 /* roundedTopDrawable */,
623                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
624                 /* roundedBottomDrawable */,
625                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
626 
627         // left cutout
628         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
629 
630         mScreenDecorations.start();
631         View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
632                 .findViewById(R.id.rounded_corner_top_left);
633         View bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
634                 .findViewById(R.id.rounded_corner_bottom_left);
635         ViewGroup.LayoutParams topParams = topRoundedCorner.getLayoutParams();
636         ViewGroup.LayoutParams bottomParams = bottomRoundedCorner.getLayoutParams();
637         assertEquals(3, topParams.width);
638         assertEquals(3, topParams.height);
639         assertEquals(5, bottomParams.width);
640         assertEquals(5, bottomParams.height);
641 
642         topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
643                 .findViewById(R.id.rounded_corner_top_right);
644         bottomRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].getRootView()
645                 .findViewById(R.id.rounded_corner_bottom_right);
646         topParams = topRoundedCorner.getLayoutParams();
647         bottomParams = bottomRoundedCorner.getLayoutParams();
648         assertEquals(3, topParams.width);
649         assertEquals(3, topParams.height);
650         assertEquals(5, bottomParams.width);
651         assertEquals(5, bottomParams.height);
652     }
653 
654     @Test
testNoRounding_CutoutShortEdge_NoPrivacyDot()655     public void testNoRounding_CutoutShortEdge_NoPrivacyDot() {
656         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
657                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
658                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
659 
660         // top cutout
661         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
662 
663         mScreenDecorations.start();
664         // Top window is created for top cutout.
665         // Bottom, left, or right window should be null.
666         verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
667 
668         // Privacy dots shall not exist because of no privacy
669         verifyDotViewsNullable(true);
670 
671         // No dot controller init
672         verify(mDotViewController, never()).initialize(any(), any(), any(), any());
673     }
674 
675     @Test
testNoRounding_CutoutShortEdge_PrivacyDot()676     public void testNoRounding_CutoutShortEdge_PrivacyDot() {
677         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
678                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
679                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
680 
681         // top cutout
682         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
683 
684         mScreenDecorations.start();
685         // Top window is created for top cutout.
686         // Bottom window is created for privacy dot.
687         // Left or right window should be null.
688         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
689         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
690         verify(mDotViewController, times(1)).setShowingListener(null);
691 
692         // Top rounded corner views shall exist because of cutout
693         // but be gone because of no rounded corner
694         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
695         // Bottom rounded corner views shall exist because of privacy dot
696         // but be gone because of no rounded corner
697         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
698 
699         // Privacy dots shall exist but invisible
700         verifyDotViewsVisibility(View.INVISIBLE);
701 
702         // Dot controller init
703         verify(mDotViewController, times(1)).initialize(
704                 isA(View.class), isA(View.class), isA(View.class), isA(View.class));
705     }
706 
707     @Test
testNoRounding_CutoutLongEdge_NoPrivacyDot()708     public void testNoRounding_CutoutLongEdge_NoPrivacyDot() {
709         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
710                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
711                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
712 
713         // left cutout
714         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
715 
716         mScreenDecorations.start();
717         // Left window is created for left cutout.
718         // Bottom, top, or right window should be null.
719         verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
720 
721         // Left rounded corner views shall exist because of cutout
722         // but be gone because of no rounded corner
723         verifyRoundedCornerViewsExist(BOUNDS_POSITION_LEFT, false);
724 
725         // Top privacy dots shall not exist because of no privacy
726         verifyDotViewsNullable(true);
727 
728         // No dot controller init
729         verify(mDotViewController, never()).initialize(any(), any(), any(), any());
730     }
731 
732     @Test
testNoRounding_CutoutLongEdge_PrivacyDot()733     public void testNoRounding_CutoutLongEdge_PrivacyDot() {
734         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
735                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
736                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
737 
738         // left cutout
739         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
740 
741         mScreenDecorations.start();
742         // Left window is created for left cutout.
743         // Right window is created for privacy.
744         // Bottom, or top window should be null.
745         verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
746         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
747         verify(mDotViewController, times(1)).setShowingListener(null);
748 
749         // Privacy dots shall exist but invisible
750         verifyDotViewsVisibility(View.INVISIBLE);
751 
752         // Dot controller init
753         verify(mDotViewController, times(1)).initialize(
754                 isA(View.class), isA(View.class), isA(View.class), isA(View.class));
755     }
756 
757     @Test
testRounding_CutoutShortEdge_NoPrivacyDot()758     public void testRounding_CutoutShortEdge_NoPrivacyDot() {
759         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
760                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
761                 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
762 
763         // top cutout
764         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
765 
766         mScreenDecorations.start();
767         // Top window is created for rounded corner and top cutout.
768         // Bottom window is created for rounded corner.
769         // Left, or right window should be null.
770         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
771 
772         // Rounded corner views shall exist
773         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
774         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
775 
776         // Top privacy dots shall not exist because of no privacy dot
777         verifyDotViewsNullable(true);
778 
779         // No dot controller init
780         verify(mDotViewController, never()).initialize(any(), any(), any(), any());
781     }
782 
783     @Test
testRounding_CutoutShortEdge_PrivacyDot()784     public void testRounding_CutoutShortEdge_PrivacyDot() {
785         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
786                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
787                 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
788 
789         // top cutout
790         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
791 
792         mScreenDecorations.start();
793         // Top window is created for rounded corner and top cutout.
794         // Bottom window is created for rounded corner.
795         // Left, or right window should be null.
796         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
797         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
798         verify(mDotViewController, times(1)).setShowingListener(null);
799 
800         // Rounded corner views shall exist
801         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, true);
802         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, true);
803 
804         // Top privacy dots shall exist but invisible
805         verifyDotViewsVisibility(View.INVISIBLE);
806 
807         // Dot controller init
808         verify(mDotViewController, times(1)).initialize(
809                 isA(View.class), isA(View.class), isA(View.class), isA(View.class));
810     }
811 
812     @Test
testRounding_CutoutLongEdge_NoPrivacyDot()813     public void testRounding_CutoutLongEdge_NoPrivacyDot() {
814         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
815                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
816                 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
817 
818         // left cutout
819         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
820 
821         mScreenDecorations.start();
822         // Left window is created for rounded corner and left cutout.
823         // Right window is created for rounded corner.
824         // Top, or bottom window should be null.
825         verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
826     }
827 
828     @Test
testRounding_CutoutLongEdge_PrivacyDot()829     public void testRounding_CutoutLongEdge_PrivacyDot() {
830         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
831                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
832                 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
833 
834         // left cutout
835         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
836 
837         mScreenDecorations.start();
838         // Left window is created for rounded corner, left cutout, and privacy.
839         // Right window is created for rounded corner and privacy dot.
840         // Top, or bottom window should be null.
841         verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
842         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
843         verify(mDotViewController, times(1)).setShowingListener(null);
844     }
845 
846     @Test
testRounding_CutoutShortAndLongEdge_NoPrivacyDot()847     public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() {
848         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
849                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
850                 20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
851 
852         // top and left cutout
853         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
854         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
855 
856         mScreenDecorations.start();
857         // Top window is created for rounded corner and top cutout.
858         // Bottom window is created for rounded corner.
859         // Left window is created for left cutout.
860         // Right window should be null.
861         verifyOverlaysExistAndAdded(true, true, false, true, View.VISIBLE);
862     }
863 
864     @Test
testRounding_CutoutShortAndLongEdge_PrivacyDot()865     public void testRounding_CutoutShortAndLongEdge_PrivacyDot() {
866         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
867                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
868                 20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
869 
870         // top and left cutout
871         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
872         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
873 
874         mScreenDecorations.start();
875         // Top window is created for rounded corner and top cutout.
876         // Bottom window is created for rounded corner.
877         // Left window is created for left cutout.
878         // Right window should be null.
879         verifyOverlaysExistAndAdded(true, true, false, true, View.VISIBLE);
880         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
881         verify(mDotViewController, times(1)).setShowingListener(null);
882     }
883 
884     @Test
testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot()885     public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() {
886         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
887                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
888                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
889 
890         // Set to short edge cutout(top).
891         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
892 
893         mScreenDecorations.start();
894         verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
895 
896         // Switch to long edge cutout(left).
897         mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
898 
899         mScreenDecorations.onConfigurationChanged(new Configuration());
900         verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
901     }
902 
903     @Test
testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot()904     public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() {
905         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
906                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
907                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
908 
909         // Set to short edge cutout(top).
910         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
911 
912         mScreenDecorations.start();
913         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
914         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
915         verify(mDotViewController, times(1)).setShowingListener(null);
916 
917         // Switch to long edge cutout(left).
918         mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
919 
920         mScreenDecorations.onConfigurationChanged(new Configuration());
921         verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
922         verify(mDotViewController, times(2)).initialize(any(), any(), any(), any());
923         verify(mDotViewController, times(2)).setShowingListener(null);
924 
925         // Verify each privacy dot id appears only once
926         mPrivacyDecorProviders.stream().map(DecorProvider::getViewId).forEach(viewId -> {
927             int findCount = 0;
928             for (OverlayWindow overlay: mScreenDecorations.mOverlays) {
929                 if (overlay == null) {
930                     continue;
931                 }
932                 final View view = overlay.getRootView().findViewById(viewId);
933                 if (view != null) {
934                     findCount++;
935                 }
936             }
937             assertEquals(1, findCount);
938         });
939 
940     }
941 
942     @Test
testDelayedCutout_NoPrivacyDot()943     public void testDelayedCutout_NoPrivacyDot() {
944         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
945                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
946                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
947 
948         // No cutout (default)
949 
950         mScreenDecorations.start();
951         verifyOverlaysExistAndAdded(false, false, false, false, null);
952 
953         // top cutout
954         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
955 
956         mScreenDecorations.onConfigurationChanged(new Configuration());
957 
958         // Only top windows should be added.
959         verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
960     }
961 
962     @Test
testDelayedCutout_PrivacyDot()963     public void testDelayedCutout_PrivacyDot() {
964         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
965                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
966                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
967 
968         // no cutout (default)
969 
970         mScreenDecorations.start();
971         // Both top and bottom windows should be added with INVISIBLE because of only privacy dot,
972         // but rounded corners visibility shall be gone because of no rounding.
973         verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
974         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
975         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
976         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
977         verify(mDotViewController, times(1)).setShowingListener(
978                 mScreenDecorations.mPrivacyDotShowingListener);
979 
980         // top cutout
981         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
982 
983         mScreenDecorations.onConfigurationChanged(new Configuration());
984 
985         // Both top and bottom windows should be added with VISIBLE because of privacy dot and
986         // cutout, but rounded corners visibility shall be gone because of no rounding.
987         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
988         verifyRoundedCornerViewsExist(BOUNDS_POSITION_TOP, false);
989         verifyRoundedCornerViewsExist(BOUNDS_POSITION_BOTTOM, false);
990         verify(mDotViewController, times(2)).initialize(any(), any(), any(), any());
991         verify(mDotViewController, times(1)).setShowingListener(null);
992     }
993 
994     @Test
hasRoundedCornerOverlayFlagSet()995     public void hasRoundedCornerOverlayFlagSet() {
996         assertThat(mScreenDecorations.getWindowLayoutParams(1).privateFlags
997                         & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
998                 is(PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY));
999     }
1000 
1001     @Test
testUpdateRoundedCorners()1002     public void testUpdateRoundedCorners() {
1003         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
1004                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
1005                 /* roundedTopDrawable */,
1006                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
1007                 /* roundedBottomDrawable */,
1008                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
1009         mDisplayInfo.rotation = Surface.ROTATION_0;
1010 
1011         mScreenDecorations.start();
1012 
1013         final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
1014         assertEquals(new Size(3, 3), resDelegate.getTopRoundedSize());
1015         assertEquals(new Size(4, 4), resDelegate.getBottomRoundedSize());
1016 
1017         doReturn(2f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
1018         mDisplayInfo.rotation = Surface.ROTATION_270;
1019 
1020         mScreenDecorations.onConfigurationChanged(null);
1021 
1022         assertEquals(new Size(6, 6), resDelegate.getTopRoundedSize());
1023         assertEquals(new Size(8, 8), resDelegate.getBottomRoundedSize());
1024     }
1025 
1026     @Test
testOnlyRoundedCornerRadiusTop()1027     public void testOnlyRoundedCornerRadiusTop() {
1028         setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */,
1029                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1030                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
1031 
1032         mScreenDecorations.start();
1033 
1034         final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
1035         assertEquals(true, resDelegate.getHasTop());
1036         assertEquals(false, resDelegate.getHasBottom());
1037         assertEquals(getDrawableIntrinsicSize(R.drawable.rounded_corner_top),
1038                 resDelegate.getTopRoundedSize());
1039 
1040         final DecorProviderFactory mRoundedCornerFactory = mScreenDecorations.mRoundedCornerFactory;
1041         assertEquals(true, mRoundedCornerFactory.getHasProviders());
1042         final List<DecorProvider> providers = mRoundedCornerFactory.getProviders();
1043         assertEquals(2, providers.size());
1044         assertEquals(true, providers.get(0).getAlignedBounds().contains(BOUNDS_POSITION_TOP));
1045         assertEquals(true, providers.get(1).getAlignedBounds().contains(BOUNDS_POSITION_TOP));    }
1046 
1047     @Test
testOnlyRoundedCornerRadiusBottom()1048     public void testOnlyRoundedCornerRadiusBottom() {
1049         setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */,
1050                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1051                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
1052 
1053         mScreenDecorations.start();
1054 
1055         final RoundedCornerResDelegate resDelegate = mScreenDecorations.mRoundedCornerResDelegate;
1056         assertEquals(false, resDelegate.getHasTop());
1057         assertEquals(true, resDelegate.getHasBottom());
1058         assertEquals(getDrawableIntrinsicSize(R.drawable.rounded_corner_bottom),
1059                 resDelegate.getBottomRoundedSize());
1060 
1061         final DecorProviderFactory mRoundedCornerFactory = mScreenDecorations.mRoundedCornerFactory;
1062         assertEquals(true, mRoundedCornerFactory.getHasProviders());
1063         final List<DecorProvider> providers = mRoundedCornerFactory.getProviders();
1064         assertEquals(2, providers.size());
1065         assertEquals(true, providers.get(0).getAlignedBounds().contains(BOUNDS_POSITION_BOTTOM));
1066         assertEquals(true, providers.get(1).getAlignedBounds().contains(BOUNDS_POSITION_BOTTOM));
1067     }
1068 
1069     @Test
testDebugRoundedCorners_noDeviceCornersSet()1070     public void testDebugRoundedCorners_noDeviceCornersSet() {
1071         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
1072                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1073                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
1074 
1075         mScreenDecorations.start();
1076         // No rounded corners exist at this point
1077         verifyOverlaysExistAndAdded(false, false, false, false, View.VISIBLE);
1078 
1079         // Path from rounded.xml, scaled by 10x to produce 80x80 corners
1080         Path debugPath = PathParser.createPathFromPathData("M8,0H0v8C0,3.6,3.6,0,8,0z");
1081         // WHEN debug corners are added to the delegate
1082         DebugRoundedCornerModel debugCorner = new DebugRoundedCornerModel(
1083                 debugPath,
1084                 80,
1085                 80,
1086                 10f,
1087                 10f
1088         );
1089         mScreenDecorations.mDebugRoundedCornerDelegate
1090                 .applyNewDebugCorners(debugCorner, debugCorner);
1091 
1092         // AND debug mode is entered
1093         mScreenDecorations.setDebug(true);
1094         mExecutor.runAllReady();
1095 
1096         // THEN the debug corners provide decor
1097         List<DecorProvider> providers = mScreenDecorations.getProviders(false);
1098         assertEquals(4, providers.size());
1099 
1100         // Top and bottom overlays contain the debug rounded corners
1101         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
1102     }
1103 
1104     @Test
testDebugRoundedCornersRemoved_noDeviceCornersSet()1105     public void testDebugRoundedCornersRemoved_noDeviceCornersSet() {
1106         // GIVEN a device with no rounded corners defined
1107         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
1108                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1109                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
1110 
1111         mScreenDecorations.start();
1112         // No rounded corners exist at this point
1113         verifyOverlaysExistAndAdded(false, false, false, false, View.VISIBLE);
1114 
1115         // Path from rounded.xml, scaled by 10x to produce 80x80 corners
1116         Path debugPath = PathParser.createPathFromPathData("M8,0H0v8C0,3.6,3.6,0,8,0z");
1117         // WHEN debug corners are added to the delegate
1118         DebugRoundedCornerModel debugCorner = new DebugRoundedCornerModel(
1119                 debugPath,
1120                 80,
1121                 80,
1122                 10f,
1123                 10f
1124         );
1125         mScreenDecorations.mDebugRoundedCornerDelegate
1126                 .applyNewDebugCorners(debugCorner, debugCorner);
1127 
1128         // AND debug mode is entered
1129         mScreenDecorations.setDebug(true);
1130         mExecutor.runAllReady();
1131 
1132         // Top and bottom overlays contain the debug rounded corners
1133         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
1134 
1135         // WHEN debug is exited
1136         mScreenDecorations.setDebug(false);
1137         mExecutor.runAllReady();
1138 
1139         // THEN the decor is removed
1140         verifyOverlaysExistAndAdded(false, false, false, false, View.VISIBLE);
1141         assertThat(mScreenDecorations.mDebugRoundedCornerDelegate.getHasBottom()).isFalse();
1142         assertThat(mScreenDecorations.mDebugRoundedCornerDelegate.getHasTop()).isFalse();
1143     }
1144 
1145     @Test
testRegistration_From_NoOverlay_To_HasOverlays()1146     public void testRegistration_From_NoOverlay_To_HasOverlays() {
1147         doReturn(false).when(mScreenDecorations).hasOverlays();
1148         mScreenDecorations.start();
1149         assertThat(mScreenDecorations.mIsRegistered, is(false));
1150 
1151         doReturn(true).when(mScreenDecorations).hasOverlays();
1152         mScreenDecorations.onConfigurationChanged(new Configuration());
1153         assertThat(mScreenDecorations.mIsRegistered, is(true));
1154     }
1155 
1156     @Test
testRegistration_From_HasOverlays_To_HasOverlays()1157     public void testRegistration_From_HasOverlays_To_HasOverlays() {
1158         doReturn(true).when(mScreenDecorations).hasOverlays();
1159 
1160         mScreenDecorations.start();
1161         assertThat(mScreenDecorations.mIsRegistered, is(true));
1162 
1163         mScreenDecorations.onConfigurationChanged(new Configuration());
1164         assertThat(mScreenDecorations.mIsRegistered, is(true));
1165     }
1166 
1167     @Test
testRegistration_From_HasOverlays_To_NoOverlay()1168     public void testRegistration_From_HasOverlays_To_NoOverlay() {
1169         doReturn(true).when(mScreenDecorations).hasOverlays();
1170 
1171         mScreenDecorations.start();
1172         assertThat(mScreenDecorations.mIsRegistered, is(true));
1173 
1174         doReturn(false).when(mScreenDecorations).hasOverlays();
1175         mScreenDecorations.onConfigurationChanged(new Configuration());
1176         assertThat(mScreenDecorations.mIsRegistered, is(false));
1177     }
1178 
1179     @Test
testSupportHwcLayer_SwitchFrom_NotSupport()1180     public void testSupportHwcLayer_SwitchFrom_NotSupport() {
1181         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
1182                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1183                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
1184 
1185         // top cutout
1186         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
1187 
1188         mScreenDecorations.start();
1189         // should only inflate mOverlays when the hwc doesn't support screen decoration
1190         assertNull(mScreenDecorations.mScreenDecorHwcWindow);
1191         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
1192 
1193         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
1194         decorationSupport.format = PixelFormat.R_8;
1195         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
1196         // Trigger the support hwc screen decoration change by changing the display unique id
1197         mScreenDecorations.mDisplayUniqueId = "test";
1198         mScreenDecorations.mDisplayListener.onDisplayChanged(1);
1199 
1200         // should only inflate hwc layer when the hwc supports screen decoration
1201         assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
1202         verifyOverlaysExistAndAdded(false, false, false, false, null);
1203     }
1204 
1205     @Test
testNotSupportHwcLayer_SwitchFrom_Support()1206     public void testNotSupportHwcLayer_SwitchFrom_Support() {
1207         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
1208                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1209                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
1210         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
1211         decorationSupport.format = PixelFormat.R_8;
1212         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
1213 
1214         // top cutout
1215         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
1216 
1217         mScreenDecorations.start();
1218         // should only inflate hwc layer when the hwc supports screen decoration
1219         assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
1220         verifyOverlaysExistAndAdded(false, false, false, false, null);
1221 
1222         doReturn(null).when(mDisplay).getDisplayDecorationSupport();
1223         // Trigger the support hwc screen decoration change by changing the display unique id
1224         mScreenDecorations.mDisplayUniqueId = "test";
1225         mScreenDecorations.mDisplayListener.onDisplayChanged(1);
1226 
1227         // should only inflate mOverlays when the hwc doesn't support screen decoration
1228         assertNull(mScreenDecorations.mScreenDecorHwcWindow);
1229         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
1230     }
1231 
1232     @Test
faceSensorLocationChangesReloadsFaceScanningOverlay()1233     public void faceSensorLocationChangesReloadsFaceScanningOverlay() {
1234         mFaceScanningProviders = new ArrayList<>();
1235         mFaceScanningProviders.add(mFaceScanningDecorProvider);
1236         when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
1237         when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(true);
1238         ScreenDecorations screenDecorations = new ScreenDecorations(mContext,
1239                 mSecureSettings, mCommandRegistry, mUserTracker, mDisplayTracker,
1240                 mDotViewController,
1241                 mThreadFactory, mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory,
1242                 new ScreenDecorationsLogger(logcatLogBuffer("TestLogBuffer")), mAuthController);
1243         screenDecorations.start();
1244         verify(mAuthController).addCallback(mAuthControllerCallback.capture());
1245         when(mContext.getDisplay()).thenReturn(mDisplay);
1246         when(mDisplay.getDisplayInfo(any())).thenAnswer(new Answer<Boolean>() {
1247             @Override
1248             public Boolean answer(InvocationOnMock invocation) throws Throwable {
1249                 DisplayInfo displayInfo = invocation.getArgument(0);
1250                 int modeId = 1;
1251                 displayInfo.modeId = modeId;
1252                 displayInfo.supportedModes = new Display.Mode[]{new Display.Mode(modeId, 1024, 1024,
1253                         90)};
1254                 return false;
1255             }
1256         });
1257         mExecutor.runAllReady();
1258         clearInvocations(mFaceScanningDecorProvider);
1259 
1260         AuthController.Callback callback = mAuthControllerCallback.getValue();
1261         callback.onFaceSensorLocationChanged();
1262         mExecutor.runAllReady();
1263 
1264         verify(mFaceScanningDecorProvider).onReloadResAndMeasure(any(),
1265                 anyInt(),
1266                 anyInt(),
1267                 anyInt(),
1268                 any());
1269     }
1270 
1271     @Test
testPrivacyDotShowingListenerWorkWellWithNullParameter()1272     public void testPrivacyDotShowingListenerWorkWellWithNullParameter() {
1273         mPrivacyDotShowingListener.onPrivacyDotShown(null);
1274         mPrivacyDotShowingListener.onPrivacyDotHidden(null);
1275     }
1276 
1277     @Test
testAutoShowHideOverlayWindowWhenSupportHwcLayer()1278     public void testAutoShowHideOverlayWindowWhenSupportHwcLayer() {
1279         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
1280                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
1281                 /* roundedTopDrawable */,
1282                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
1283                 /* roundedBottomDrawable */,
1284                 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
1285         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
1286         decorationSupport.format = PixelFormat.R_8;
1287         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
1288 
1289         // top cutout
1290         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
1291 
1292         mScreenDecorations.start();
1293         // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
1294         verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
1295 
1296         // Make sure view found and window visibility changed as well
1297         final View view = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
1298                 .findViewById(R.id.privacy_dot_bottom_right_container);
1299         view.setVisibility(View.VISIBLE);
1300         mPrivacyDotShowingListener.onPrivacyDotShown(view);
1301         assertEquals(View.VISIBLE,
1302                 mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
1303         view.setVisibility(View.INVISIBLE);
1304         mPrivacyDotShowingListener.onPrivacyDotHidden(view);
1305         assertEquals(View.INVISIBLE,
1306                 mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
1307 
1308         // Make sure face scanning view found and window visibility updates on camera protection
1309         // update
1310         final View faceScanView = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
1311                 .findViewById(mFaceScanningDecorProvider.getViewId());
1312         when(mFaceScanningProviderFactory.shouldShowFaceScanningAnim()).thenReturn(true);
1313         faceScanView.setVisibility(View.VISIBLE);
1314         mScreenDecorations.showCameraProtection(new Path(), new Rect());
1315         mExecutor.runAllReady();
1316         assertEquals(View.VISIBLE,
1317                 mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView().getVisibility());
1318     }
1319 
1320     @Test
testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout()1321     public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() {
1322         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
1323                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1324                 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
1325 
1326         // no cutout (default)
1327 
1328         mScreenDecorations.start();
1329         // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
1330         verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
1331 
1332         // Make sure view found and window visibility changed as well
1333         final View view = mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView()
1334                 .findViewById(R.id.privacy_dot_bottom_right_container);
1335         view.setVisibility(View.VISIBLE);
1336         mPrivacyDotShowingListener.onPrivacyDotShown(view);
1337         assertEquals(View.VISIBLE,
1338                 mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
1339         view.setVisibility(View.INVISIBLE);
1340         mPrivacyDotShowingListener.onPrivacyDotHidden(view);
1341         assertEquals(View.INVISIBLE,
1342                 mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM].getRootView().getVisibility());
1343 
1344         // Make sure face scanning view found and window visibility updates on camera protection
1345         // update
1346         final View faceScanView = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
1347                 .findViewById(mFaceScanningDecorProvider.getViewId());
1348         faceScanView.setVisibility(View.VISIBLE);
1349         when(mFaceScanningProviderFactory.shouldShowFaceScanningAnim()).thenReturn(true);
1350         mScreenDecorations.showCameraProtection(new Path(), new Rect());
1351         mExecutor.runAllReady();
1352         assertEquals(View.VISIBLE,
1353                 mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView().getVisibility());
1354     }
1355 
1356     @Test
testHwcLayer_noPrivacyDot_noFaceScanning()1357     public void testHwcLayer_noPrivacyDot_noFaceScanning() {
1358         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
1359                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1360                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
1361         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
1362         decorationSupport.format = PixelFormat.R_8;
1363         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
1364 
1365         // top cutout
1366         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
1367 
1368         mScreenDecorations.start();
1369 
1370         // Should only inflate hwc layer.
1371         assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
1372         verifyOverlaysExistAndAdded(false, false, false, false, null);
1373     }
1374 
1375     @Test
testHwcLayer_PrivacyDot_FaceScanning()1376     public void testHwcLayer_PrivacyDot_FaceScanning() {
1377         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
1378                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1379                 0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
1380         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
1381         decorationSupport.format = PixelFormat.R_8;
1382         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
1383 
1384         // top cutout
1385         mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
1386 
1387         mScreenDecorations.start();
1388 
1389         assertNotNull(mScreenDecorations.mScreenDecorHwcWindow);
1390         // mOverlays are inflated but the visibility should be INVISIBLE.
1391         verifyOverlaysExistAndAdded(false, true, false, true, View.INVISIBLE);
1392         verify(mDotViewController, times(1)).initialize(any(), any(), any(), any());
1393         verify(mDotViewController, times(1)).setShowingListener(
1394                 mScreenDecorations.mPrivacyDotShowingListener);
1395 
1396         verifyFaceScanningViewExists(true);
1397     }
1398 
1399     @Test
testHasSameProvidersWithNullOverlays()1400     public void testHasSameProvidersWithNullOverlays() {
1401         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
1402                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1403                 0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
1404 
1405         mScreenDecorations.start();
1406 
1407         final ArrayList<DecorProvider> newProviders = new ArrayList<>();
1408         assertTrue(mScreenDecorations.hasSameProviders(newProviders));
1409 
1410         newProviders.add(mPrivacyDotTopLeftDecorProvider);
1411         assertFalse(mScreenDecorations.hasSameProviders(newProviders));
1412 
1413         newProviders.add(mPrivacyDotTopRightDecorProvider);
1414         assertFalse(mScreenDecorations.hasSameProviders(newProviders));
1415     }
1416 
1417     @Test
testHasSameProvidersWithPrivacyDots()1418     public void testHasSameProvidersWithPrivacyDots() {
1419         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
1420                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
1421                 0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
1422 
1423         mScreenDecorations.start();
1424 
1425         final ArrayList<DecorProvider> newProviders = new ArrayList<>();
1426         assertFalse(mScreenDecorations.hasSameProviders(newProviders));
1427 
1428         newProviders.add(mPrivacyDotTopLeftDecorProvider);
1429         assertFalse(mScreenDecorations.hasSameProviders(newProviders));
1430 
1431         newProviders.add(mPrivacyDotTopRightDecorProvider);
1432         assertFalse(mScreenDecorations.hasSameProviders(newProviders));
1433 
1434         newProviders.add(mPrivacyDotBottomLeftDecorProvider);
1435         assertFalse(mScreenDecorations.hasSameProviders(newProviders));
1436 
1437         newProviders.add(mPrivacyDotBottomRightDecorProvider);
1438         assertTrue(mScreenDecorations.hasSameProviders(newProviders));
1439     }
1440 
getDrawableIntrinsicSize(@rawableRes int drawableResId)1441     private Size getDrawableIntrinsicSize(@DrawableRes int drawableResId) {
1442         final Drawable d = mContext.getDrawable(drawableResId);
1443         return new Size(d.getIntrinsicWidth(), d.getIntrinsicHeight());
1444     }
1445 
1446     @Nullable
getTestsDrawable(@rawableRes int drawableId)1447     private Drawable getTestsDrawable(@DrawableRes int drawableId) {
1448         try {
1449             return mContext.createPackageContext("com.android.systemui.tests", 0)
1450                     .getDrawable(drawableId);
1451         } catch (PackageManager.NameNotFoundException exception) {
1452             return null;
1453         }
1454     }
1455 
setupResources(int radius, int radiusTop, int radiusBottom, @Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable, int roundedPadding, boolean privacyDot, boolean faceScanning)1456     private void setupResources(int radius, int radiusTop, int radiusBottom,
1457             @Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable,
1458             int roundedPadding, boolean privacyDot, boolean faceScanning) {
1459         mContext.getOrCreateTestableResources().addOverride(
1460                 com.android.internal.R.array.config_displayUniqueIdArray,
1461                 new String[]{});
1462         mContext.getOrCreateTestableResources().addOverride(
1463                 com.android.internal.R.array.config_roundedCornerRadiusArray,
1464                 mMockTypedArray);
1465         mContext.getOrCreateTestableResources().addOverride(
1466                 com.android.internal.R.array.config_roundedCornerTopRadiusArray,
1467                 mMockTypedArray);
1468         mContext.getOrCreateTestableResources().addOverride(
1469                 com.android.internal.R.array.config_roundedCornerBottomRadiusArray,
1470                 mMockTypedArray);
1471         mContext.getOrCreateTestableResources().addOverride(
1472                 R.array.config_roundedCornerDrawableArray,
1473                 mMockTypedArray);
1474         mContext.getOrCreateTestableResources().addOverride(
1475                 R.array.config_roundedCornerTopDrawableArray,
1476                 mMockTypedArray);
1477         mContext.getOrCreateTestableResources().addOverride(
1478                 R.array.config_roundedCornerBottomDrawableArray,
1479                 mMockTypedArray);
1480         mContext.getOrCreateTestableResources().addOverride(
1481                 com.android.internal.R.dimen.rounded_corner_radius, radius);
1482         mContext.getOrCreateTestableResources().addOverride(
1483                 com.android.internal.R.dimen.rounded_corner_radius_top, radiusTop);
1484         mContext.getOrCreateTestableResources().addOverride(
1485                 com.android.internal.R.dimen.rounded_corner_radius_bottom, radiusBottom);
1486         if (roundedTopDrawable != null) {
1487             mContext.getOrCreateTestableResources().addOverride(
1488                     R.drawable.rounded_corner_top,
1489                     roundedTopDrawable);
1490         }
1491         if (roundedBottomDrawable != null) {
1492             mContext.getOrCreateTestableResources().addOverride(
1493                     R.drawable.rounded_corner_bottom,
1494                     roundedBottomDrawable);
1495         }
1496         mContext.getOrCreateTestableResources().addOverride(
1497                 R.dimen.rounded_corner_content_padding, roundedPadding);
1498 
1499         mPrivacyDecorProviders = new ArrayList<>();
1500         if (privacyDot) {
1501             mPrivacyDecorProviders.add(mPrivacyDotTopLeftDecorProvider);
1502             mPrivacyDecorProviders.add(mPrivacyDotTopRightDecorProvider);
1503             mPrivacyDecorProviders.add(mPrivacyDotBottomLeftDecorProvider);
1504             mPrivacyDecorProviders.add(mPrivacyDotBottomRightDecorProvider);
1505         }
1506         when(mPrivacyDotDecorProviderFactory.getProviders()).thenReturn(mPrivacyDecorProviders);
1507         when(mPrivacyDotDecorProviderFactory.getHasProviders()).thenReturn(privacyDot);
1508 
1509         mFaceScanningProviders = new ArrayList<>();
1510         if (faceScanning) {
1511             mFaceScanningProviders.add(mFaceScanningDecorProvider);
1512         }
1513         when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
1514         when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(faceScanning);
1515     }
1516 }
1517