Update clock burn-in so it doesn't clash with udpfs
* update the UDFPS icon burn-in parameters to be in pixels because we don't want display density to increase the position movement * when the clock is centered aligned, we want to make sure it doesn't overlap with the udfps icon Test: atest SystemUITests, manually update clock times with with DozeUi.BURN_IN_TESTING_ENABLED enabled and see clock doesn't interfere with the UDFPS icon. Fixes: 192423460 Change-Id: I6f95fe3ad763971b804129b517f4c98192ab3674
This commit is contained in:
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Minimum margin between clock and top of screen or ambient indication -->
|
<!-- Minimum margin between clock and top of screen or ambient indication -->
|
||||||
<dimen name="keyguard_clock_top_margin">76dp</dimen>
|
<dimen name="keyguard_clock_top_margin">38dp</dimen>
|
||||||
|
|
||||||
<!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
|
<!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
|
||||||
<dimen name="large_clock_text_size">200dp</dimen>
|
<dimen name="large_clock_text_size">200dp</dimen>
|
||||||
|
|||||||
@@ -750,9 +750,7 @@
|
|||||||
<!-- The margin between the status view and the notifications on Keyguard.-->
|
<!-- The margin between the status view and the notifications on Keyguard.-->
|
||||||
<dimen name="keyguard_status_view_bottom_margin">20dp</dimen>
|
<dimen name="keyguard_status_view_bottom_margin">20dp</dimen>
|
||||||
<!-- Minimum margin between clock and status bar -->
|
<!-- Minimum margin between clock and status bar -->
|
||||||
<dimen name="keyguard_clock_top_margin">36dp</dimen>
|
<dimen name="keyguard_clock_top_margin">18dp</dimen>
|
||||||
<!-- The margin between top of clock and bottom of lock icon. -->
|
|
||||||
<dimen name="keyguard_clock_lock_margin">16dp</dimen>
|
|
||||||
<!-- The amount to shift the clocks during a small/large transition -->
|
<!-- The amount to shift the clocks during a small/large transition -->
|
||||||
<dimen name="keyguard_clock_switch_y_shift">10dp</dimen>
|
<dimen name="keyguard_clock_switch_y_shift">10dp</dimen>
|
||||||
<!-- When large clock is showing, offset the smartspace by this amount -->
|
<!-- When large clock is showing, offset the smartspace by this amount -->
|
||||||
@@ -1157,9 +1155,9 @@
|
|||||||
<dimen name="default_burn_in_prevention_offset">15dp</dimen>
|
<dimen name="default_burn_in_prevention_offset">15dp</dimen>
|
||||||
|
|
||||||
<!-- The maximum offset for the under-display fingerprint sensor (UDFPS) icon in either
|
<!-- The maximum offset for the under-display fingerprint sensor (UDFPS) icon in either
|
||||||
direction that elements aer moved to prevent burn-in on AOD-->
|
direction that elements are moved to prevent burn-in on AOD-->
|
||||||
<dimen name="udfps_burn_in_offset_x">2dp</dimen>
|
<dimen name="udfps_burn_in_offset_x">7px</dimen>
|
||||||
<dimen name="udfps_burn_in_offset_y">8dp</dimen>
|
<dimen name="udfps_burn_in_offset_y">28px</dimen>
|
||||||
|
|
||||||
<dimen name="corner_size">8dp</dimen>
|
<dimen name="corner_size">8dp</dimen>
|
||||||
<dimen name="top_padding">0dp</dimen>
|
<dimen name="top_padding">0dp</dimen>
|
||||||
|
|||||||
@@ -72,13 +72,16 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
* Clock for both small and large sizes
|
* Clock for both small and large sizes
|
||||||
*/
|
*/
|
||||||
private AnimatableClockController mClockViewController;
|
private AnimatableClockController mClockViewController;
|
||||||
private FrameLayout mClockFrame;
|
private FrameLayout mClockFrame; // top aligned clock
|
||||||
private AnimatableClockController mLargeClockViewController;
|
private AnimatableClockController mLargeClockViewController;
|
||||||
private FrameLayout mLargeClockFrame;
|
private FrameLayout mLargeClockFrame; // centered clock
|
||||||
|
|
||||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||||
private final KeyguardBypassController mBypassController;
|
private final KeyguardBypassController mBypassController;
|
||||||
|
|
||||||
|
private int mLargeClockTopMargin = 0;
|
||||||
|
private int mKeyguardClockTopMargin = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener for changes to the color palette.
|
* Listener for changes to the color palette.
|
||||||
*
|
*
|
||||||
@@ -177,6 +180,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
}
|
}
|
||||||
mColorExtractor.addOnColorsChangedListener(mColorsListener);
|
mColorExtractor.addOnColorsChangedListener(mColorsListener);
|
||||||
mView.updateColors(getGradientColors());
|
mView.updateColors(getGradientColors());
|
||||||
|
mKeyguardClockTopMargin =
|
||||||
|
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||||
|
|
||||||
if (mOnlyClock) {
|
if (mOnlyClock) {
|
||||||
View ksa = mView.findViewById(R.id.keyguard_status_area);
|
View ksa = mView.findViewById(R.id.keyguard_status_area);
|
||||||
@@ -241,6 +246,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
*/
|
*/
|
||||||
public void onDensityOrFontScaleChanged() {
|
public void onDensityOrFontScaleChanged() {
|
||||||
mView.onDensityOrFontScaleChanged();
|
mView.onDensityOrFontScaleChanged();
|
||||||
|
mKeyguardClockTopMargin =
|
||||||
|
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||||
|
|
||||||
updateClockLayout();
|
updateClockLayout();
|
||||||
}
|
}
|
||||||
@@ -249,9 +256,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
if (mSmartspaceController.isEnabled()) {
|
if (mSmartspaceController.isEnabled()) {
|
||||||
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
|
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
|
||||||
MATCH_PARENT);
|
MATCH_PARENT);
|
||||||
lp.topMargin = getContext().getResources().getDimensionPixelSize(
|
mLargeClockTopMargin = getContext().getResources().getDimensionPixelSize(
|
||||||
R.dimen.keyguard_large_clock_top_margin);
|
R.dimen.keyguard_large_clock_top_margin);
|
||||||
|
lp.topMargin = mLargeClockTopMargin;
|
||||||
mLargeClockFrame.setLayoutParams(lp);
|
mLargeClockFrame.setLayoutParams(lp);
|
||||||
|
} else {
|
||||||
|
mLargeClockTopMargin = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,6 +373,28 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get y-bottom position of the currently visible clock on the keyguard.
|
||||||
|
* We can't directly getBottom() because clock changes positions in AOD for burn-in
|
||||||
|
*/
|
||||||
|
int getClockBottom(int statusBarHeaderHeight) {
|
||||||
|
if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
|
||||||
|
View clock = mLargeClockFrame.findViewById(
|
||||||
|
com.android.systemui.R.id.animatable_clock_view_large);
|
||||||
|
int frameHeight = mLargeClockFrame.getHeight();
|
||||||
|
int clockHeight = clock.getHeight();
|
||||||
|
return frameHeight / 2 + clockHeight / 2;
|
||||||
|
} else {
|
||||||
|
return mClockFrame.findViewById(
|
||||||
|
com.android.systemui.R.id.animatable_clock_view).getHeight()
|
||||||
|
+ statusBarHeaderHeight + mKeyguardClockTopMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isClockTopAligned() {
|
||||||
|
return mLargeClockFrame.getVisibility() != View.VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateAodIcons() {
|
private void updateAodIcons() {
|
||||||
NotificationIconContainer nic = (NotificationIconContainer)
|
NotificationIconContainer nic = (NotificationIconContainer)
|
||||||
mView.findViewById(
|
mView.findViewById(
|
||||||
|
|||||||
@@ -186,6 +186,20 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
|||||||
return mView.getHeight() - mKeyguardClockSwitchController.getNotificationIconAreaHeight();
|
return mView.getHeight() - mKeyguardClockSwitchController.getNotificationIconAreaHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get y-bottom position of the currently visible clock.
|
||||||
|
*/
|
||||||
|
public int getClockBottom(int statusBarHeaderHeight) {
|
||||||
|
return mKeyguardClockSwitchController.getClockBottom(statusBarHeaderHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the currently displayed clock is top aligned (as opposed to center aligned)
|
||||||
|
*/
|
||||||
|
public boolean isClockTopAligned() {
|
||||||
|
return mKeyguardClockSwitchController.isClockTopAligned();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether the view accessibility importance mode.
|
* Set whether the view accessibility importance mode.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -56,6 +56,21 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
*/
|
*/
|
||||||
private int mUserSwitchPreferredY;
|
private int mUserSwitchPreferredY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not there is a custom clock face on keyguard.
|
||||||
|
*/
|
||||||
|
private boolean mHasCustomClock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the NSSL contains any visible notifications.
|
||||||
|
*/
|
||||||
|
private boolean mHasVisibleNotifs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of notification stack: Sum of height of each notification.
|
||||||
|
*/
|
||||||
|
private int mNotificationStackHeight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
|
* Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
|
||||||
* avatar.
|
* avatar.
|
||||||
@@ -112,6 +127,25 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
|
|
||||||
private boolean mIsSplitShade;
|
private boolean mIsSplitShade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Top location of the udfps icon. This includes the worst case (highest) burn-in
|
||||||
|
* offset that would make the top physically highest on the screen.
|
||||||
|
*
|
||||||
|
* Set to -1 if udfps is not enrolled on the device.
|
||||||
|
*/
|
||||||
|
private float mUdfpsTop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bottom y-position of the currently visible clock
|
||||||
|
*/
|
||||||
|
private float mClockBottom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, try to keep clock aligned to the top of the display. Else, assume the clock
|
||||||
|
* is center aligned.
|
||||||
|
*/
|
||||||
|
private boolean mIsClockTopAligned;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the dimension values.
|
* Refreshes the dimension values.
|
||||||
*/
|
*/
|
||||||
@@ -120,7 +154,7 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
R.dimen.keyguard_status_view_bottom_margin);
|
R.dimen.keyguard_status_view_bottom_margin);
|
||||||
|
|
||||||
mContainerTopPadding =
|
mContainerTopPadding =
|
||||||
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) / 2;
|
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||||
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
|
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
|
||||||
R.dimen.burn_in_prevention_offset_x);
|
R.dimen.burn_in_prevention_offset_x);
|
||||||
mBurnInPreventionOffsetYClock = res.getDimensionPixelSize(
|
mBurnInPreventionOffsetYClock = res.getDimensionPixelSize(
|
||||||
@@ -134,7 +168,7 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
|
int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
|
||||||
float dark, float overStretchAmount, boolean bypassEnabled,
|
float dark, float overStretchAmount, boolean bypassEnabled,
|
||||||
int unlockedStackScrollerPadding, float qsExpansion, int cutoutTopInset,
|
int unlockedStackScrollerPadding, float qsExpansion, int cutoutTopInset,
|
||||||
boolean isSplitShade) {
|
boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) {
|
||||||
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
|
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
|
||||||
userSwitchHeight);
|
userSwitchHeight);
|
||||||
mPanelExpansion = panelExpansion;
|
mPanelExpansion = panelExpansion;
|
||||||
@@ -148,6 +182,9 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
mQsExpansion = qsExpansion;
|
mQsExpansion = qsExpansion;
|
||||||
mCutoutTopInset = cutoutTopInset;
|
mCutoutTopInset = cutoutTopInset;
|
||||||
mIsSplitShade = isSplitShade;
|
mIsSplitShade = isSplitShade;
|
||||||
|
mUdfpsTop = udfpsTop;
|
||||||
|
mClockBottom = clockBottom;
|
||||||
|
mIsClockTopAligned = isClockTopAligned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(Result result) {
|
public void run(Result result) {
|
||||||
@@ -202,8 +239,34 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
if (clockY - mBurnInPreventionOffsetYClock < mCutoutTopInset) {
|
if (clockY - mBurnInPreventionOffsetYClock < mCutoutTopInset) {
|
||||||
shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYClock);
|
shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYClock);
|
||||||
}
|
}
|
||||||
float clockYDark = clockY + burnInPreventionOffsetY() + shift;
|
|
||||||
|
|
||||||
|
int burnInPreventionOffsetY = mBurnInPreventionOffsetYClock; // requested offset
|
||||||
|
final boolean hasUdfps = mUdfpsTop > -1;
|
||||||
|
if (hasUdfps && !mIsClockTopAligned) {
|
||||||
|
// ensure clock doesn't overlap with the udfps icon
|
||||||
|
if (mUdfpsTop < mClockBottom) {
|
||||||
|
// sometimes the clock textView extends beyond udfps, so let's just use the
|
||||||
|
// space above the KeyguardStatusView/clock as our burn-in offset
|
||||||
|
burnInPreventionOffsetY = (int) (clockY - mCutoutTopInset) / 2;
|
||||||
|
if (mBurnInPreventionOffsetYClock < burnInPreventionOffsetY) {
|
||||||
|
burnInPreventionOffsetY = mBurnInPreventionOffsetYClock;
|
||||||
|
}
|
||||||
|
shift = -burnInPreventionOffsetY;
|
||||||
|
} else {
|
||||||
|
float upperSpace = clockY - mCutoutTopInset;
|
||||||
|
float lowerSpace = mUdfpsTop - mClockBottom;
|
||||||
|
// center the burn-in offset within the upper + lower space
|
||||||
|
burnInPreventionOffsetY = (int) (lowerSpace + upperSpace) / 2;
|
||||||
|
if (mBurnInPreventionOffsetYClock < burnInPreventionOffsetY) {
|
||||||
|
burnInPreventionOffsetY = mBurnInPreventionOffsetYClock;
|
||||||
|
}
|
||||||
|
shift = (lowerSpace - upperSpace) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float clockYDark = clockY
|
||||||
|
+ burnInPreventionOffsetY(burnInPreventionOffsetY)
|
||||||
|
+ shift;
|
||||||
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mOverStretchAmount);
|
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mOverStretchAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,9 +298,7 @@ public class KeyguardClockPositionAlgorithm {
|
|||||||
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
|
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float burnInPreventionOffsetY() {
|
private float burnInPreventionOffsetY(int offset) {
|
||||||
int offset = mBurnInPreventionOffsetYClock;
|
|
||||||
|
|
||||||
return getBurnInOffset(offset * 2, false /* xAxis */) - offset;
|
return getBurnInOffset(offset * 2, false /* xAxis */) - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ import android.graphics.PointF;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.hardware.biometrics.BiometricSourceType;
|
||||||
|
import android.hardware.biometrics.SensorLocationInternal;
|
||||||
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
@@ -568,6 +571,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
*/
|
*/
|
||||||
private float mKeyguardOnlyContentAlpha = 1.0f;
|
private float mKeyguardOnlyContentAlpha = 1.0f;
|
||||||
|
|
||||||
|
private float mUdfpsMaxYBurnInOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we currently in gesture navigation
|
* Are we currently in gesture navigation
|
||||||
*/
|
*/
|
||||||
@@ -907,6 +912,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
mView.getContext());
|
mView.getContext());
|
||||||
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
|
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
|
||||||
R.dimen.notification_side_paddings);
|
R.dimen.notification_side_paddings);
|
||||||
|
mUdfpsMaxYBurnInOffset = mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
|
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
|
||||||
@@ -1265,7 +1271,17 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
float darkamount =
|
float darkamount =
|
||||||
mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
|
mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
|
||||||
? 1.0f : mInterpolatedDarkAmount;
|
? 1.0f : mInterpolatedDarkAmount;
|
||||||
mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
|
|
||||||
|
float udfpsAodTopLocation = -1f;
|
||||||
|
if (mUpdateMonitor.isUdfpsEnrolled() && mAuthController.getUdfpsProps().size() > 0) {
|
||||||
|
FingerprintSensorPropertiesInternal props = mAuthController.getUdfpsProps().get(0);
|
||||||
|
final SensorLocationInternal location = props.getLocation();
|
||||||
|
udfpsAodTopLocation = location.sensorLocationY - location.sensorRadius
|
||||||
|
- mUdfpsMaxYBurnInOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
mClockPositionAlgorithm.setup(
|
||||||
|
mStatusBarHeaderHeightKeyguard,
|
||||||
expandedFraction,
|
expandedFraction,
|
||||||
mKeyguardStatusViewController.getLockscreenHeight(),
|
mKeyguardStatusViewController.getLockscreenHeight(),
|
||||||
userIconHeight,
|
userIconHeight,
|
||||||
@@ -1274,7 +1290,10 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
bypassEnabled, getUnlockedStackScrollerPadding(),
|
bypassEnabled, getUnlockedStackScrollerPadding(),
|
||||||
computeQsExpansionFraction(),
|
computeQsExpansionFraction(),
|
||||||
mDisplayTopInset,
|
mDisplayTopInset,
|
||||||
mShouldUseSplitNotificationShade);
|
mShouldUseSplitNotificationShade,
|
||||||
|
udfpsAodTopLocation,
|
||||||
|
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
|
||||||
|
mKeyguardStatusViewController.isClockTopAligned());
|
||||||
mClockPositionAlgorithm.run(mClockPositionResult);
|
mClockPositionAlgorithm.run(mClockPositionResult);
|
||||||
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
|
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
|
||||||
boolean animateClock = animate || mAnimateNextPositionUpdate;
|
boolean animateClock = animate || mAnimateNextPositionUpdate;
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
|||||||
when(mNotificationIcons.getLayoutParams()).thenReturn(
|
when(mNotificationIcons.getLayoutParams()).thenReturn(
|
||||||
mock(RelativeLayout.LayoutParams.class));
|
mock(RelativeLayout.LayoutParams.class));
|
||||||
when(mView.getContext()).thenReturn(getContext());
|
when(mView.getContext()).thenReturn(getContext());
|
||||||
|
when(mView.getResources()).thenReturn(mResources);
|
||||||
|
|
||||||
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
|
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
|
||||||
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
|
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
|
||||||
@@ -127,7 +128,6 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
|||||||
when(mLargeClockView.getContext()).thenReturn(getContext());
|
when(mLargeClockView.getContext()).thenReturn(getContext());
|
||||||
|
|
||||||
when(mView.isAttachedToWindow()).thenReturn(true);
|
when(mView.isAttachedToWindow()).thenReturn(true);
|
||||||
when(mResources.getString(anyInt())).thenReturn("h:mm");
|
|
||||||
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
|
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
|
||||||
mController = new KeyguardClockSwitchController(
|
mController = new KeyguardClockSwitchController(
|
||||||
mView,
|
mView,
|
||||||
|
|||||||
@@ -16,42 +16,80 @@
|
|||||||
|
|
||||||
package com.android.systemui.statusbar.phone;
|
package com.android.systemui.statusbar.phone;
|
||||||
|
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.AdditionalAnswers.returnsFirstArg;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.doze.util.BurnInHelperKt;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.MockitoSession;
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||||
private static final int SCREEN_HEIGHT = 2000;
|
private static final int SCREEN_HEIGHT = 2000;
|
||||||
private static final int EMPTY_MARGIN = 0;
|
|
||||||
private static final int EMPTY_HEIGHT = 0;
|
private static final int EMPTY_HEIGHT = 0;
|
||||||
private static final float ZERO_DRAG = 0.f;
|
private static final float ZERO_DRAG = 0.f;
|
||||||
private static final float OPAQUE = 1.f;
|
private static final float OPAQUE = 1.f;
|
||||||
private static final float TRANSPARENT = 0.f;
|
private static final float TRANSPARENT = 0.f;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Resources mResources;
|
||||||
|
|
||||||
private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
|
private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
|
||||||
private KeyguardClockPositionAlgorithm.Result mClockPosition;
|
private KeyguardClockPositionAlgorithm.Result mClockPosition;
|
||||||
|
|
||||||
|
private MockitoSession mStaticMockSession;
|
||||||
|
private int mNotificationStackHeight;
|
||||||
|
|
||||||
private float mPanelExpansion;
|
private float mPanelExpansion;
|
||||||
|
private int mKeyguardStatusBarHeaderHeight;
|
||||||
private int mKeyguardStatusHeight;
|
private int mKeyguardStatusHeight;
|
||||||
private float mDark;
|
private float mDark;
|
||||||
private float mQsExpansion;
|
private float mQsExpansion;
|
||||||
private int mCutoutTopInsetPx = 0;
|
private int mCutoutTopInset = 0;
|
||||||
private boolean mIsSplitShade = false;
|
private boolean mIsSplitShade = false;
|
||||||
|
private float mUdfpsTop = -1;
|
||||||
|
private float mClockBottom = SCREEN_HEIGHT / 2;
|
||||||
|
private boolean mClockTopAligned;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mStaticMockSession = mockitoSession()
|
||||||
|
.mockStatic(BurnInHelperKt.class)
|
||||||
|
.startMocking();
|
||||||
|
|
||||||
mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
|
mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
|
||||||
|
when(mResources.getDimensionPixelSize(anyInt())).thenReturn(0);
|
||||||
|
mClockPositionAlgorithm.loadDimens(mResources);
|
||||||
|
|
||||||
mClockPosition = new KeyguardClockPositionAlgorithm.Result();
|
mClockPosition = new KeyguardClockPositionAlgorithm.Result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
mStaticMockSession.finishMocking();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void clockPositionTopOfScreenOnAOD() {
|
public void clockPositionTopOfScreenOnAOD() {
|
||||||
// GIVEN on AOD and clock has 0 height
|
// GIVEN on AOD and clock has 0 height
|
||||||
@@ -71,7 +109,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
|||||||
// GIVEN on AOD and clock has 0 height
|
// GIVEN on AOD and clock has 0 height
|
||||||
givenAOD();
|
givenAOD();
|
||||||
mKeyguardStatusHeight = EMPTY_HEIGHT;
|
mKeyguardStatusHeight = EMPTY_HEIGHT;
|
||||||
mCutoutTopInsetPx = 300;
|
mCutoutTopInset = 300;
|
||||||
// WHEN the clock position algorithm is run
|
// WHEN the clock position algorithm is run
|
||||||
positionClock();
|
positionClock();
|
||||||
// THEN the clock Y position is below the cutout
|
// THEN the clock Y position is below the cutout
|
||||||
@@ -271,6 +309,155 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
|||||||
assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT);
|
assertThat(mClockPosition.clockAlpha).isEqualTo(TRANSPARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clockPositionMinimizesBurnInMovementToAvoidUdfpsOnAOD() {
|
||||||
|
// GIVEN a center aligned clock
|
||||||
|
mClockTopAligned = false;
|
||||||
|
|
||||||
|
// GIVEN the clock + udfps are 100px apart
|
||||||
|
mClockBottom = SCREEN_HEIGHT - 500;
|
||||||
|
mUdfpsTop = SCREEN_HEIGHT - 400;
|
||||||
|
|
||||||
|
// GIVEN it's AOD and the burn-in y value is 200
|
||||||
|
givenAOD();
|
||||||
|
givenMaxBurnInOffset(200);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the highest burn in offset
|
||||||
|
givenHighestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN the worst-case clock Y position is shifted only by 100 (not the full 200),
|
||||||
|
// so that it's at the same location as mUdfpsTop
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(100);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the lowest burn in offset
|
||||||
|
givenLowestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN lowest case starts at 0
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clockPositionShiftsToAvoidUdfpsOnAOD_usesSpaceAboveClock() {
|
||||||
|
// GIVEN a center aligned clock
|
||||||
|
mClockTopAligned = false;
|
||||||
|
|
||||||
|
// GIVEN there's space at the top of the screen on LS (that's available to be used for
|
||||||
|
// burn-in on AOD)
|
||||||
|
mKeyguardStatusBarHeaderHeight = 150;
|
||||||
|
|
||||||
|
// GIVEN the bottom of the clock is beyond the top of UDFPS
|
||||||
|
mClockBottom = SCREEN_HEIGHT - 300;
|
||||||
|
mUdfpsTop = SCREEN_HEIGHT - 400;
|
||||||
|
|
||||||
|
// GIVEN it's AOD and the burn-in y value is 200
|
||||||
|
givenAOD();
|
||||||
|
givenMaxBurnInOffset(200);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the highest burn in offset
|
||||||
|
givenHighestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN the algo should shift the clock up and use the area above the clock for
|
||||||
|
// burn-in since the burn in offset > space above clock
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(mKeyguardStatusBarHeaderHeight);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the lowest burn in offset
|
||||||
|
givenLowestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN lowest case starts at mCutoutTopInset (0 in this case)
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(mCutoutTopInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clockPositionShiftsToAvoidUdfpsOnAOD_usesMaxBurnInOffset() {
|
||||||
|
// GIVEN a center aligned clock
|
||||||
|
mClockTopAligned = false;
|
||||||
|
|
||||||
|
// GIVEN there's 200px space at the top of the screen on LS (that's available to be used for
|
||||||
|
// burn-in on AOD) but 50px are taken up by the cutout
|
||||||
|
mKeyguardStatusBarHeaderHeight = 200;
|
||||||
|
mCutoutTopInset = 50;
|
||||||
|
|
||||||
|
// GIVEN the bottom of the clock is beyond the top of UDFPS
|
||||||
|
mClockBottom = SCREEN_HEIGHT - 300;
|
||||||
|
mUdfpsTop = SCREEN_HEIGHT - 400;
|
||||||
|
|
||||||
|
// GIVEN it's AOD and the burn-in y value is only 25px (less than space above clock)
|
||||||
|
givenAOD();
|
||||||
|
int maxYBurnInOffset = 25;
|
||||||
|
givenMaxBurnInOffset(maxYBurnInOffset);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the highest burn in offset
|
||||||
|
givenHighestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN the algo should shift the clock up and use the area above the clock for
|
||||||
|
// burn-in
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(mKeyguardStatusBarHeaderHeight);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the lowest burn in offset
|
||||||
|
givenLowestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN lowest case starts above mKeyguardStatusBarHeaderHeight
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(
|
||||||
|
mKeyguardStatusBarHeaderHeight - 2 * maxYBurnInOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clockPositionShiftsToMaximizeUdfpsBurnInMovement() {
|
||||||
|
// GIVEN a center aligned clock
|
||||||
|
mClockTopAligned = false;
|
||||||
|
|
||||||
|
// GIVEN there's 200px space at the top of the screen on LS (that's available to be used for
|
||||||
|
// burn-in on AOD) but 50px are taken up by the cutout
|
||||||
|
mKeyguardStatusBarHeaderHeight = 200;
|
||||||
|
mCutoutTopInset = 50;
|
||||||
|
int upperSpaceAvailable = mKeyguardStatusBarHeaderHeight - mCutoutTopInset;
|
||||||
|
|
||||||
|
// GIVEN the bottom of the clock and the top of UDFPS are 100px apart
|
||||||
|
mClockBottom = SCREEN_HEIGHT - 500;
|
||||||
|
mUdfpsTop = SCREEN_HEIGHT - 400;
|
||||||
|
float lowerSpaceAvailable = mUdfpsTop - mClockBottom;
|
||||||
|
|
||||||
|
// GIVEN it's AOD and the burn-in y value is 200
|
||||||
|
givenAOD();
|
||||||
|
givenMaxBurnInOffset(200);
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the highest burn in offset
|
||||||
|
givenHighestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN the algo should shift the clock up and use both the area above
|
||||||
|
// the clock and below the clock (vertically centered in its allowed area)
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(
|
||||||
|
(int) (mCutoutTopInset + upperSpaceAvailable + lowerSpaceAvailable));
|
||||||
|
|
||||||
|
// WHEN the clock position algorithm is run with the lowest burn in offset
|
||||||
|
givenLowestBurnInOffset();
|
||||||
|
positionClock();
|
||||||
|
|
||||||
|
// THEN lowest case starts at mCutoutTopInset
|
||||||
|
assertThat(mClockPosition.clockY).isEqualTo(mCutoutTopInset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void givenHighestBurnInOffset() {
|
||||||
|
when(BurnInHelperKt.getBurnInOffset(anyInt(), anyBoolean())).then(returnsFirstArg());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void givenLowestBurnInOffset() {
|
||||||
|
when(BurnInHelperKt.getBurnInOffset(anyInt(), anyBoolean())).thenReturn(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void givenMaxBurnInOffset(int offset) {
|
||||||
|
when(mResources.getDimensionPixelSize(R.dimen.burn_in_prevention_offset_y_clock))
|
||||||
|
.thenReturn(offset);
|
||||||
|
mClockPositionAlgorithm.loadDimens(mResources);
|
||||||
|
}
|
||||||
|
|
||||||
private void givenAOD() {
|
private void givenAOD() {
|
||||||
mPanelExpansion = 1.f;
|
mPanelExpansion = 1.f;
|
||||||
mDark = 1.f;
|
mDark = 1.f;
|
||||||
@@ -281,12 +468,28 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
|||||||
mDark = 0.f;
|
mDark = 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup and run the clock position algorithm.
|
||||||
|
*
|
||||||
|
* mClockPosition.clockY will contain the top y-coordinate for the clock position
|
||||||
|
*/
|
||||||
private void positionClock() {
|
private void positionClock() {
|
||||||
mClockPositionAlgorithm.setup(EMPTY_MARGIN, mPanelExpansion, mKeyguardStatusHeight,
|
mClockPositionAlgorithm.setup(
|
||||||
0 /* userSwitchHeight */, 0 /* userSwitchPreferredY */,
|
mKeyguardStatusBarHeaderHeight,
|
||||||
mDark, ZERO_DRAG, false /* bypassEnabled */,
|
mPanelExpansion,
|
||||||
0 /* unlockedStackScrollerPadding */, mQsExpansion,
|
mKeyguardStatusHeight,
|
||||||
mCutoutTopInsetPx, mIsSplitShade);
|
0 /* userSwitchHeight */,
|
||||||
|
0 /* userSwitchPreferredY */,
|
||||||
|
mDark,
|
||||||
|
ZERO_DRAG,
|
||||||
|
false /* bypassEnabled */,
|
||||||
|
0 /* unlockedStackScrollerPadding */,
|
||||||
|
mQsExpansion,
|
||||||
|
mCutoutTopInset,
|
||||||
|
mIsSplitShade,
|
||||||
|
mUdfpsTop,
|
||||||
|
mClockBottom,
|
||||||
|
mClockTopAligned);
|
||||||
mClockPositionAlgorithm.run(mClockPosition);
|
mClockPositionAlgorithm.run(mClockPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user