Loading packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt +3 −3 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField val displayInfo = DisplayInfo() @JvmField protected var pendingRotationChange = false @JvmField protected var pendingConfigChange = false @JvmField protected val paint = Paint() @JvmField protected val cutoutPath = Path() Loading Loading @@ -145,7 +145,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) open fun updateCutout() { if (pendingRotationChange) { if (pendingConfigChange) { return } cutoutPath.reset() Loading Loading @@ -225,7 +225,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { } protected open fun updateProtectionBoundingPath() { if (pendingRotationChange) { if (pendingConfigChange) { return } val m = Matrix() Loading packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +73 −27 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.provider.Settings.Secure; import android.util.DisplayUtils; import android.util.Log; import android.util.Size; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayCutout.BoundsPosition; import android.view.DisplayInfo; Loading Loading @@ -151,12 +152,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab private SettingObserver mColorInversionSetting; private DelayableExecutor mExecutor; private Handler mHandler; boolean mPendingRotationChange; boolean mPendingConfigChange; @VisibleForTesting String mDisplayUniqueId; private int mTintColor = Color.BLACK; @VisibleForTesting protected DisplayDecorationSupport mHwcScreenDecorationSupport; private Display.Mode mDisplayMode; private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback = new CameraAvailabilityListener.CameraTransitionCallback() { Loading Loading @@ -324,6 +326,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mWindowManager = mContext.getSystemService(WindowManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class); mRotation = mContext.getDisplay().getRotation(); mDisplayMode = mContext.getDisplay().getMode(); mDisplayUniqueId = mContext.getDisplay().getUniqueId(); mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(), mDisplayUniqueId); Loading @@ -349,8 +352,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @Override public void onDisplayChanged(int displayId) { final int newRotation = mContext.getDisplay().getRotation(); final Display.Mode newDisplayMode = mContext.getDisplay().getMode(); if ((mOverlays != null || mScreenDecorHwcWindow != null) && mRotation != newRotation) { && (mRotation != newRotation || displayModeChanged(mDisplayMode, newDisplayMode))) { // We cannot immediately update the orientation. Otherwise // WindowManager is still deferring layout until it has finished dispatching // the config changes, which may cause divergence between what we draw Loading @@ -358,10 +363,16 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab // Instead we wait until either: // - we are trying to redraw. This because WM resized our window and told us to. // - the config change has been dispatched, so WM is no longer deferring layout. mPendingRotationChange = true; mPendingConfigChange = true; if (DEBUG) { Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at " + mRotation); if (mRotation != newRotation) { Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at " + mRotation); } if (displayModeChanged(mDisplayMode, newDisplayMode)) { Log.i(TAG, "Resolution changed, deferring " + newDisplayMode + ", staying at " + mDisplayMode); } } if (mOverlays != null) { Loading @@ -369,7 +380,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab if (mOverlays[i] != null) { final ViewGroup overlayView = mOverlays[i].getRootView(); overlayView.getViewTreeObserver().addOnPreDrawListener( new RestartingPreDrawListener(overlayView, i, newRotation)); new RestartingPreDrawListener( overlayView, i, newRotation, newDisplayMode)); } } } Loading @@ -379,7 +391,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab new RestartingPreDrawListener( mScreenDecorHwcWindow, -1, // Pass -1 for views with no specific position. newRotation)); newRotation, newDisplayMode)); } if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingConfigChange = true; } } Loading Loading @@ -435,7 +450,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab }; mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); updateOrientation(); updateConfiguration(); } @Nullable Loading Loading @@ -807,6 +822,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } } private static boolean displayModeChanged(Display.Mode oldMode, Display.Mode newMode) { if (oldMode == null) { return true; } // We purposely ignore refresh rate and id changes here, because we don't need to // invalidate for those, and they can trigger the refresh rate to increase return oldMode.getPhysicalWidth() != newMode.getPhysicalWidth() || oldMode.getPhysicalHeight() != newMode.getPhysicalHeight(); } private int getOverlayWindowGravity(@BoundsPosition int pos) { final int rotated = getBoundPositionFromRotation(pos, mRotation); switch (rotated) { Loading Loading @@ -913,8 +939,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mExecutor.execute(() -> { int oldRotation = mRotation; mPendingRotationChange = false; updateOrientation(); mPendingConfigChange = false; updateConfiguration(); if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation); setupDecorations(); if (mOverlays != null) { Loading @@ -941,7 +967,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab pw.println(" DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS); pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled()); pw.println(" isOnlyPrivacyDotInSwLayer:" + isOnlyPrivacyDotInSwLayer()); pw.println(" mPendingRotationChange:" + mPendingRotationChange); pw.println(" mPendingConfigChange:" + mPendingConfigChange); if (mHwcScreenDecorationSupport != null) { pw.println(" mHwcScreenDecorationSupport:"); pw.println(" format=" Loading Loading @@ -973,7 +999,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mRoundedCornerResDelegate.dump(pw, args); } private void updateOrientation() { private void updateConfiguration() { Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(), "must call on " + mHandler.getLooper().getThread() + ", but was " + Thread.currentThread()); Loading @@ -982,11 +1008,14 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab if (mRotation != newRotation) { mDotViewController.setNewRotation(newRotation); } final Display.Mode newMod = mContext.getDisplay().getMode(); if (!mPendingRotationChange && newRotation != mRotation) { if (!mPendingConfigChange && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) { mRotation = newRotation; mDisplayMode = newMod; if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingRotationChange = false; mScreenDecorHwcLayer.pendingConfigChange = false; mScreenDecorHwcLayer.updateRotation(mRotation); updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerDrawable(); Loading Loading @@ -1197,7 +1226,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @Override public void updateCutout() { if (!isAttachedToWindow() || pendingRotationChange) { if (!isAttachedToWindow() || pendingConfigChange) { return; } mPosition = getBoundPositionFromRotation(mInitialPosition, mRotation); Loading Loading @@ -1338,40 +1367,47 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab private final View mView; private final int mTargetRotation; private final Display.Mode mTargetDisplayMode; // Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific // position. private final int mPosition; private RestartingPreDrawListener(View view, @BoundsPosition int position, int targetRotation) { int targetRotation, Display.Mode targetDisplayMode) { mView = view; mTargetRotation = targetRotation; mTargetDisplayMode = targetDisplayMode; mPosition = position; } @Override public boolean onPreDraw() { mView.getViewTreeObserver().removeOnPreDrawListener(this); if (mTargetRotation == mRotation) { if (mTargetRotation == mRotation && !displayModeChanged(mDisplayMode, mTargetDisplayMode)) { if (DEBUG) { final String title = mPosition < 0 ? "ScreenDecorHwcLayer" : getWindowTitleByPos(mPosition); Log.i(TAG, title + " already in target rot " + mTargetRotation + ", allow draw without restarting it"); + mTargetRotation + " and in target resolution " + mTargetDisplayMode.getPhysicalWidth() + "x" + mTargetDisplayMode.getPhysicalHeight() + ", allow draw without restarting it"); } return true; } mPendingRotationChange = false; mPendingConfigChange = false; // This changes the window attributes - we need to restart the traversal for them to // take effect. updateOrientation(); updateConfiguration(); if (DEBUG) { final String title = mPosition < 0 ? "ScreenDecorHwcLayer" : getWindowTitleByPos(mPosition); Log.i(TAG, title + " restarting listener fired, restarting draw for rot " + mRotation); + " restarting listener fired, restarting draw for rot " + mRotation + ", resolution " + mDisplayMode.getPhysicalWidth() + "x" + mDisplayMode.getPhysicalHeight()); } mView.invalidate(); return false; Loading @@ -1379,8 +1415,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } /** * A pre-draw listener, that validates that the rotation we draw in matches the displays * rotation before continuing the draw. * A pre-draw listener, that validates that the rotation and display resolution we draw in * matches the display's rotation and resolution before continuing the draw. * * This is to prevent a race condition, where we have not received the display changed event * yet, and would thus draw in an old orientation. Loading @@ -1396,11 +1432,21 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @Override public boolean onPreDraw() { final int displayRotation = mContext.getDisplay().getRotation(); if (displayRotation != mRotation && !mPendingRotationChange) { final Display.Mode displayMode = mContext.getDisplay().getMode(); if (displayRotation != mRotation && displayModeChanged(mDisplayMode, displayMode) && !mPendingConfigChange) { if (DEBUG) { if (displayRotation != mRotation) { Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot " + displayRotation + ". Restarting draw"); } if (displayModeChanged(mDisplayMode, displayMode)) { Log.i(TAG, "Drawing at " + mDisplayMode.getPhysicalWidth() + "x" + mDisplayMode.getPhysicalHeight() + ", but display is at " + displayMode.getPhysicalWidth() + "x" + displayMode.getPhysicalHeight() + ". Restarting draw"); } } mView.invalidate(); return false; } Loading packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -159,6 +159,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { when(mContext.getDisplay()).thenReturn(mDisplay); // Not support hwc layer by default doReturn(null).when(mDisplay).getDisplayDecorationSupport(); doReturn(mDisplayMode).when(mDisplay).getMode(); when(mMockTypedArray.length()).thenReturn(0); mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl( Loading Loading
packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt +3 −3 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField val displayInfo = DisplayInfo() @JvmField protected var pendingRotationChange = false @JvmField protected var pendingConfigChange = false @JvmField protected val paint = Paint() @JvmField protected val cutoutPath = Path() Loading Loading @@ -145,7 +145,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) open fun updateCutout() { if (pendingRotationChange) { if (pendingConfigChange) { return } cutoutPath.reset() Loading Loading @@ -225,7 +225,7 @@ open class DisplayCutoutBaseView : View, RegionInterceptableView { } protected open fun updateProtectionBoundingPath() { if (pendingRotationChange) { if (pendingConfigChange) { return } val m = Matrix() Loading
packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +73 −27 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ import android.provider.Settings.Secure; import android.util.DisplayUtils; import android.util.Log; import android.util.Size; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayCutout.BoundsPosition; import android.view.DisplayInfo; Loading Loading @@ -151,12 +152,13 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab private SettingObserver mColorInversionSetting; private DelayableExecutor mExecutor; private Handler mHandler; boolean mPendingRotationChange; boolean mPendingConfigChange; @VisibleForTesting String mDisplayUniqueId; private int mTintColor = Color.BLACK; @VisibleForTesting protected DisplayDecorationSupport mHwcScreenDecorationSupport; private Display.Mode mDisplayMode; private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback = new CameraAvailabilityListener.CameraTransitionCallback() { Loading Loading @@ -324,6 +326,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mWindowManager = mContext.getSystemService(WindowManager.class); mDisplayManager = mContext.getSystemService(DisplayManager.class); mRotation = mContext.getDisplay().getRotation(); mDisplayMode = mContext.getDisplay().getMode(); mDisplayUniqueId = mContext.getDisplay().getUniqueId(); mRoundedCornerResDelegate = new RoundedCornerResDelegate(mContext.getResources(), mDisplayUniqueId); Loading @@ -349,8 +352,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @Override public void onDisplayChanged(int displayId) { final int newRotation = mContext.getDisplay().getRotation(); final Display.Mode newDisplayMode = mContext.getDisplay().getMode(); if ((mOverlays != null || mScreenDecorHwcWindow != null) && mRotation != newRotation) { && (mRotation != newRotation || displayModeChanged(mDisplayMode, newDisplayMode))) { // We cannot immediately update the orientation. Otherwise // WindowManager is still deferring layout until it has finished dispatching // the config changes, which may cause divergence between what we draw Loading @@ -358,10 +363,16 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab // Instead we wait until either: // - we are trying to redraw. This because WM resized our window and told us to. // - the config change has been dispatched, so WM is no longer deferring layout. mPendingRotationChange = true; mPendingConfigChange = true; if (DEBUG) { Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at " + mRotation); if (mRotation != newRotation) { Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at " + mRotation); } if (displayModeChanged(mDisplayMode, newDisplayMode)) { Log.i(TAG, "Resolution changed, deferring " + newDisplayMode + ", staying at " + mDisplayMode); } } if (mOverlays != null) { Loading @@ -369,7 +380,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab if (mOverlays[i] != null) { final ViewGroup overlayView = mOverlays[i].getRootView(); overlayView.getViewTreeObserver().addOnPreDrawListener( new RestartingPreDrawListener(overlayView, i, newRotation)); new RestartingPreDrawListener( overlayView, i, newRotation, newDisplayMode)); } } } Loading @@ -379,7 +391,10 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab new RestartingPreDrawListener( mScreenDecorHwcWindow, -1, // Pass -1 for views with no specific position. newRotation)); newRotation, newDisplayMode)); } if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingConfigChange = true; } } Loading Loading @@ -435,7 +450,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab }; mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); updateOrientation(); updateConfiguration(); } @Nullable Loading Loading @@ -807,6 +822,17 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } } private static boolean displayModeChanged(Display.Mode oldMode, Display.Mode newMode) { if (oldMode == null) { return true; } // We purposely ignore refresh rate and id changes here, because we don't need to // invalidate for those, and they can trigger the refresh rate to increase return oldMode.getPhysicalWidth() != newMode.getPhysicalWidth() || oldMode.getPhysicalHeight() != newMode.getPhysicalHeight(); } private int getOverlayWindowGravity(@BoundsPosition int pos) { final int rotated = getBoundPositionFromRotation(pos, mRotation); switch (rotated) { Loading Loading @@ -913,8 +939,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mExecutor.execute(() -> { int oldRotation = mRotation; mPendingRotationChange = false; updateOrientation(); mPendingConfigChange = false; updateConfiguration(); if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation); setupDecorations(); if (mOverlays != null) { Loading @@ -941,7 +967,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab pw.println(" DEBUG_DISABLE_SCREEN_DECORATIONS:" + DEBUG_DISABLE_SCREEN_DECORATIONS); pw.println(" mIsPrivacyDotEnabled:" + isPrivacyDotEnabled()); pw.println(" isOnlyPrivacyDotInSwLayer:" + isOnlyPrivacyDotInSwLayer()); pw.println(" mPendingRotationChange:" + mPendingRotationChange); pw.println(" mPendingConfigChange:" + mPendingConfigChange); if (mHwcScreenDecorationSupport != null) { pw.println(" mHwcScreenDecorationSupport:"); pw.println(" format=" Loading Loading @@ -973,7 +999,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab mRoundedCornerResDelegate.dump(pw, args); } private void updateOrientation() { private void updateConfiguration() { Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(), "must call on " + mHandler.getLooper().getThread() + ", but was " + Thread.currentThread()); Loading @@ -982,11 +1008,14 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab if (mRotation != newRotation) { mDotViewController.setNewRotation(newRotation); } final Display.Mode newMod = mContext.getDisplay().getMode(); if (!mPendingRotationChange && newRotation != mRotation) { if (!mPendingConfigChange && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) { mRotation = newRotation; mDisplayMode = newMod; if (mScreenDecorHwcLayer != null) { mScreenDecorHwcLayer.pendingRotationChange = false; mScreenDecorHwcLayer.pendingConfigChange = false; mScreenDecorHwcLayer.updateRotation(mRotation); updateHwLayerRoundedCornerExistAndSize(); updateHwLayerRoundedCornerDrawable(); Loading Loading @@ -1197,7 +1226,7 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @Override public void updateCutout() { if (!isAttachedToWindow() || pendingRotationChange) { if (!isAttachedToWindow() || pendingConfigChange) { return; } mPosition = getBoundPositionFromRotation(mInitialPosition, mRotation); Loading Loading @@ -1338,40 +1367,47 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab private final View mView; private final int mTargetRotation; private final Display.Mode mTargetDisplayMode; // Pass -1 for ScreenDecorHwcLayer since it's a fullscreen window and has no specific // position. private final int mPosition; private RestartingPreDrawListener(View view, @BoundsPosition int position, int targetRotation) { int targetRotation, Display.Mode targetDisplayMode) { mView = view; mTargetRotation = targetRotation; mTargetDisplayMode = targetDisplayMode; mPosition = position; } @Override public boolean onPreDraw() { mView.getViewTreeObserver().removeOnPreDrawListener(this); if (mTargetRotation == mRotation) { if (mTargetRotation == mRotation && !displayModeChanged(mDisplayMode, mTargetDisplayMode)) { if (DEBUG) { final String title = mPosition < 0 ? "ScreenDecorHwcLayer" : getWindowTitleByPos(mPosition); Log.i(TAG, title + " already in target rot " + mTargetRotation + ", allow draw without restarting it"); + mTargetRotation + " and in target resolution " + mTargetDisplayMode.getPhysicalWidth() + "x" + mTargetDisplayMode.getPhysicalHeight() + ", allow draw without restarting it"); } return true; } mPendingRotationChange = false; mPendingConfigChange = false; // This changes the window attributes - we need to restart the traversal for them to // take effect. updateOrientation(); updateConfiguration(); if (DEBUG) { final String title = mPosition < 0 ? "ScreenDecorHwcLayer" : getWindowTitleByPos(mPosition); Log.i(TAG, title + " restarting listener fired, restarting draw for rot " + mRotation); + " restarting listener fired, restarting draw for rot " + mRotation + ", resolution " + mDisplayMode.getPhysicalWidth() + "x" + mDisplayMode.getPhysicalHeight()); } mView.invalidate(); return false; Loading @@ -1379,8 +1415,8 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab } /** * A pre-draw listener, that validates that the rotation we draw in matches the displays * rotation before continuing the draw. * A pre-draw listener, that validates that the rotation and display resolution we draw in * matches the display's rotation and resolution before continuing the draw. * * This is to prevent a race condition, where we have not received the display changed event * yet, and would thus draw in an old orientation. Loading @@ -1396,11 +1432,21 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab @Override public boolean onPreDraw() { final int displayRotation = mContext.getDisplay().getRotation(); if (displayRotation != mRotation && !mPendingRotationChange) { final Display.Mode displayMode = mContext.getDisplay().getMode(); if (displayRotation != mRotation && displayModeChanged(mDisplayMode, displayMode) && !mPendingConfigChange) { if (DEBUG) { if (displayRotation != mRotation) { Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot " + displayRotation + ". Restarting draw"); } if (displayModeChanged(mDisplayMode, displayMode)) { Log.i(TAG, "Drawing at " + mDisplayMode.getPhysicalWidth() + "x" + mDisplayMode.getPhysicalHeight() + ", but display is at " + displayMode.getPhysicalWidth() + "x" + displayMode.getPhysicalHeight() + ". Restarting draw"); } } mView.invalidate(); return false; } Loading
packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -159,6 +159,7 @@ public class ScreenDecorationsTest extends SysuiTestCase { when(mContext.getDisplay()).thenReturn(mDisplay); // Not support hwc layer by default doReturn(null).when(mDisplay).getDisplayDecorationSupport(); doReturn(mDisplayMode).when(mDisplay).getMode(); when(mMockTypedArray.length()).thenReturn(0); mPrivacyDotTopLeftDecorProvider = spy(new PrivacyDotCornerDecorProviderImpl( Loading