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>
|
||||
<!-- 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) -->
|
||||
<dimen name="large_clock_text_size">200dp</dimen>
|
||||
|
||||
@@ -750,9 +750,7 @@
|
||||
<!-- The margin between the status view and the notifications on Keyguard.-->
|
||||
<dimen name="keyguard_status_view_bottom_margin">20dp</dimen>
|
||||
<!-- Minimum margin between clock and status bar -->
|
||||
<dimen name="keyguard_clock_top_margin">36dp</dimen>
|
||||
<!-- The margin between top of clock and bottom of lock icon. -->
|
||||
<dimen name="keyguard_clock_lock_margin">16dp</dimen>
|
||||
<dimen name="keyguard_clock_top_margin">18dp</dimen>
|
||||
<!-- The amount to shift the clocks during a small/large transition -->
|
||||
<dimen name="keyguard_clock_switch_y_shift">10dp</dimen>
|
||||
<!-- When large clock is showing, offset the smartspace by this amount -->
|
||||
@@ -1157,9 +1155,9 @@
|
||||
<dimen name="default_burn_in_prevention_offset">15dp</dimen>
|
||||
|
||||
<!-- The maximum offset for the under-display fingerprint sensor (UDFPS) icon in either
|
||||
direction that elements aer moved to prevent burn-in on AOD-->
|
||||
<dimen name="udfps_burn_in_offset_x">2dp</dimen>
|
||||
<dimen name="udfps_burn_in_offset_y">8dp</dimen>
|
||||
direction that elements are moved to prevent burn-in on AOD-->
|
||||
<dimen name="udfps_burn_in_offset_x">7px</dimen>
|
||||
<dimen name="udfps_burn_in_offset_y">28px</dimen>
|
||||
|
||||
<dimen name="corner_size">8dp</dimen>
|
||||
<dimen name="top_padding">0dp</dimen>
|
||||
|
||||
@@ -72,13 +72,16 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
* Clock for both small and large sizes
|
||||
*/
|
||||
private AnimatableClockController mClockViewController;
|
||||
private FrameLayout mClockFrame;
|
||||
private FrameLayout mClockFrame; // top aligned clock
|
||||
private AnimatableClockController mLargeClockViewController;
|
||||
private FrameLayout mLargeClockFrame;
|
||||
private FrameLayout mLargeClockFrame; // centered clock
|
||||
|
||||
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
private final KeyguardBypassController mBypassController;
|
||||
|
||||
private int mLargeClockTopMargin = 0;
|
||||
private int mKeyguardClockTopMargin = 0;
|
||||
|
||||
/**
|
||||
* Listener for changes to the color palette.
|
||||
*
|
||||
@@ -177,6 +180,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
}
|
||||
mColorExtractor.addOnColorsChangedListener(mColorsListener);
|
||||
mView.updateColors(getGradientColors());
|
||||
mKeyguardClockTopMargin =
|
||||
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||
|
||||
if (mOnlyClock) {
|
||||
View ksa = mView.findViewById(R.id.keyguard_status_area);
|
||||
@@ -241,6 +246,8 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
*/
|
||||
public void onDensityOrFontScaleChanged() {
|
||||
mView.onDensityOrFontScaleChanged();
|
||||
mKeyguardClockTopMargin =
|
||||
mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||
|
||||
updateClockLayout();
|
||||
}
|
||||
@@ -249,9 +256,12 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
if (mSmartspaceController.isEnabled()) {
|
||||
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
|
||||
MATCH_PARENT);
|
||||
lp.topMargin = getContext().getResources().getDimensionPixelSize(
|
||||
mLargeClockTopMargin = getContext().getResources().getDimensionPixelSize(
|
||||
R.dimen.keyguard_large_clock_top_margin);
|
||||
lp.topMargin = mLargeClockTopMargin;
|
||||
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() {
|
||||
NotificationIconContainer nic = (NotificationIconContainer)
|
||||
mView.findViewById(
|
||||
|
||||
@@ -186,6 +186,20 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -56,6 +56,21 @@ public class KeyguardClockPositionAlgorithm {
|
||||
*/
|
||||
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
|
||||
* avatar.
|
||||
@@ -112,6 +127,25 @@ public class KeyguardClockPositionAlgorithm {
|
||||
|
||||
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.
|
||||
*/
|
||||
@@ -120,7 +154,7 @@ public class KeyguardClockPositionAlgorithm {
|
||||
R.dimen.keyguard_status_view_bottom_margin);
|
||||
|
||||
mContainerTopPadding =
|
||||
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) / 2;
|
||||
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
|
||||
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
|
||||
R.dimen.burn_in_prevention_offset_x);
|
||||
mBurnInPreventionOffsetYClock = res.getDimensionPixelSize(
|
||||
@@ -134,7 +168,7 @@ public class KeyguardClockPositionAlgorithm {
|
||||
int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
|
||||
float dark, float overStretchAmount, boolean bypassEnabled,
|
||||
int unlockedStackScrollerPadding, float qsExpansion, int cutoutTopInset,
|
||||
boolean isSplitShade) {
|
||||
boolean isSplitShade, float udfpsTop, float clockBottom, boolean isClockTopAligned) {
|
||||
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
|
||||
userSwitchHeight);
|
||||
mPanelExpansion = panelExpansion;
|
||||
@@ -148,6 +182,9 @@ public class KeyguardClockPositionAlgorithm {
|
||||
mQsExpansion = qsExpansion;
|
||||
mCutoutTopInset = cutoutTopInset;
|
||||
mIsSplitShade = isSplitShade;
|
||||
mUdfpsTop = udfpsTop;
|
||||
mClockBottom = clockBottom;
|
||||
mIsClockTopAligned = isClockTopAligned;
|
||||
}
|
||||
|
||||
public void run(Result result) {
|
||||
@@ -202,8 +239,34 @@ public class KeyguardClockPositionAlgorithm {
|
||||
if (clockY - mBurnInPreventionOffsetYClock < mCutoutTopInset) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -235,9 +298,7 @@ public class KeyguardClockPositionAlgorithm {
|
||||
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
|
||||
}
|
||||
|
||||
private float burnInPreventionOffsetY() {
|
||||
int offset = mBurnInPreventionOffsetYClock;
|
||||
|
||||
private float burnInPreventionOffsetY(int offset) {
|
||||
return getBurnInOffset(offset * 2, false /* xAxis */) - offset;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
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.Handler;
|
||||
import android.os.PowerManager;
|
||||
@@ -568,6 +571,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
*/
|
||||
private float mKeyguardOnlyContentAlpha = 1.0f;
|
||||
|
||||
private float mUdfpsMaxYBurnInOffset;
|
||||
|
||||
/**
|
||||
* Are we currently in gesture navigation
|
||||
*/
|
||||
@@ -907,6 +912,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
mView.getContext());
|
||||
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
|
||||
R.dimen.notification_side_paddings);
|
||||
mUdfpsMaxYBurnInOffset = mResources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
|
||||
}
|
||||
|
||||
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
|
||||
@@ -1265,7 +1271,17 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
float darkamount =
|
||||
mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
|
||||
? 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,
|
||||
mKeyguardStatusViewController.getLockscreenHeight(),
|
||||
userIconHeight,
|
||||
@@ -1274,7 +1290,10 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
bypassEnabled, getUnlockedStackScrollerPadding(),
|
||||
computeQsExpansionFraction(),
|
||||
mDisplayTopInset,
|
||||
mShouldUseSplitNotificationShade);
|
||||
mShouldUseSplitNotificationShade,
|
||||
udfpsAodTopLocation,
|
||||
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
|
||||
mKeyguardStatusViewController.isClockTopAligned());
|
||||
mClockPositionAlgorithm.run(mClockPositionResult);
|
||||
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
|
||||
boolean animateClock = animate || mAnimateNextPositionUpdate;
|
||||
|
||||
@@ -119,6 +119,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
when(mNotificationIcons.getLayoutParams()).thenReturn(
|
||||
mock(RelativeLayout.LayoutParams.class));
|
||||
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_large)).thenReturn(mLargeClockView);
|
||||
@@ -127,7 +128,6 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
when(mLargeClockView.getContext()).thenReturn(getContext());
|
||||
|
||||
when(mView.isAttachedToWindow()).thenReturn(true);
|
||||
when(mResources.getString(anyInt())).thenReturn("h:mm");
|
||||
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
|
||||
mController = new KeyguardClockSwitchController(
|
||||
mView,
|
||||
|
||||
@@ -16,42 +16,80 @@
|
||||
|
||||
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 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 androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.doze.util.BurnInHelperKt;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.MockitoSession;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||
private static final int SCREEN_HEIGHT = 2000;
|
||||
private static final int EMPTY_MARGIN = 0;
|
||||
private static final int EMPTY_HEIGHT = 0;
|
||||
private static final float ZERO_DRAG = 0.f;
|
||||
private static final float OPAQUE = 1.f;
|
||||
private static final float TRANSPARENT = 0.f;
|
||||
|
||||
@Mock
|
||||
private Resources mResources;
|
||||
|
||||
private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
|
||||
private KeyguardClockPositionAlgorithm.Result mClockPosition;
|
||||
|
||||
private MockitoSession mStaticMockSession;
|
||||
private int mNotificationStackHeight;
|
||||
|
||||
private float mPanelExpansion;
|
||||
private int mKeyguardStatusBarHeaderHeight;
|
||||
private int mKeyguardStatusHeight;
|
||||
private float mDark;
|
||||
private float mQsExpansion;
|
||||
private int mCutoutTopInsetPx = 0;
|
||||
private int mCutoutTopInset = 0;
|
||||
private boolean mIsSplitShade = false;
|
||||
private float mUdfpsTop = -1;
|
||||
private float mClockBottom = SCREEN_HEIGHT / 2;
|
||||
private boolean mClockTopAligned;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mStaticMockSession = mockitoSession()
|
||||
.mockStatic(BurnInHelperKt.class)
|
||||
.startMocking();
|
||||
|
||||
mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
|
||||
when(mResources.getDimensionPixelSize(anyInt())).thenReturn(0);
|
||||
mClockPositionAlgorithm.loadDimens(mResources);
|
||||
|
||||
mClockPosition = new KeyguardClockPositionAlgorithm.Result();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mStaticMockSession.finishMocking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clockPositionTopOfScreenOnAOD() {
|
||||
// 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
|
||||
givenAOD();
|
||||
mKeyguardStatusHeight = EMPTY_HEIGHT;
|
||||
mCutoutTopInsetPx = 300;
|
||||
mCutoutTopInset = 300;
|
||||
// WHEN the clock position algorithm is run
|
||||
positionClock();
|
||||
// THEN the clock Y position is below the cutout
|
||||
@@ -271,6 +309,155 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||
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() {
|
||||
mPanelExpansion = 1.f;
|
||||
mDark = 1.f;
|
||||
@@ -281,12 +468,28 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
|
||||
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() {
|
||||
mClockPositionAlgorithm.setup(EMPTY_MARGIN, mPanelExpansion, mKeyguardStatusHeight,
|
||||
0 /* userSwitchHeight */, 0 /* userSwitchPreferredY */,
|
||||
mDark, ZERO_DRAG, false /* bypassEnabled */,
|
||||
0 /* unlockedStackScrollerPadding */, mQsExpansion,
|
||||
mCutoutTopInsetPx, mIsSplitShade);
|
||||
mClockPositionAlgorithm.setup(
|
||||
mKeyguardStatusBarHeaderHeight,
|
||||
mPanelExpansion,
|
||||
mKeyguardStatusHeight,
|
||||
0 /* userSwitchHeight */,
|
||||
0 /* userSwitchPreferredY */,
|
||||
mDark,
|
||||
ZERO_DRAG,
|
||||
false /* bypassEnabled */,
|
||||
0 /* unlockedStackScrollerPadding */,
|
||||
mQsExpansion,
|
||||
mCutoutTopInset,
|
||||
mIsSplitShade,
|
||||
mUdfpsTop,
|
||||
mClockBottom,
|
||||
mClockTopAligned);
|
||||
mClockPositionAlgorithm.run(mClockPosition);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user