Fix heads-up notification being sometimes clipped when pulsing

The NSSL top padding is aligned with the clock top. The clock position moves throughout
time to avoid pixel burn-in and sometimes the position is above NSSL bounds, which makes the HUN be clipped.

The solution is to account for burn-in vertical shift when calculating NSSL position.
This means smartspace with clock will not always be aligned with HUN but it's agreed to be the best solution.

Also small renaming of burn-in related fields.

Test: KeyguardClockPositionAlgorithmTest.java
Test: Manually on-device with simulating biggest burn-in shift up
Fixes: 260084123
Change-Id: I211b15affef1c84d0b8524134b3af02894faf536
This commit is contained in:
Michal Brzezinski
2023-02-01 18:00:32 +00:00
parent 8ec492a739
commit 5c7cee2b3a
2 changed files with 39 additions and 16 deletions

View File

@@ -89,14 +89,19 @@ public class KeyguardClockPositionAlgorithm {
private float mPanelExpansion;
/**
* Burn-in prevention x translation.
* Max burn-in prevention x translation.
*/
private int mBurnInPreventionOffsetX;
private int mMaxBurnInPreventionOffsetX;
/**
* Burn-in prevention y translation for clock layouts.
* Max burn-in prevention y translation for clock layouts.
*/
private int mBurnInPreventionOffsetYClock;
private int mMaxBurnInPreventionOffsetYClock;
/**
* Current burn-in prevention y translation.
*/
private float mCurrentBurnInOffsetY;
/**
* Doze/AOD transition amount.
@@ -155,9 +160,9 @@ public class KeyguardClockPositionAlgorithm {
mContainerTopPadding =
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin);
mBurnInPreventionOffsetX = res.getDimensionPixelSize(
mMaxBurnInPreventionOffsetX = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_x);
mBurnInPreventionOffsetYClock = res.getDimensionPixelSize(
mMaxBurnInPreventionOffsetYClock = res.getDimensionPixelSize(
R.dimen.burn_in_prevention_offset_y_clock);
}
@@ -215,7 +220,10 @@ public class KeyguardClockPositionAlgorithm {
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
return clockYPosition - mSplitShadeTopNotificationsMargin + mUserSwitchHeight;
// mCurrentBurnInOffsetY is subtracted to make notifications not follow clock adjustment
// for burn-in. It can make pulsing notification go too high and it will get clipped
return clockYPosition - mSplitShadeTopNotificationsMargin + mUserSwitchHeight
- (int) mCurrentBurnInOffsetY;
} else {
return clockYPosition + mKeyguardStatusHeight;
}
@@ -255,11 +263,11 @@ public class KeyguardClockPositionAlgorithm {
// This will keep the clock at the top but out of the cutout area
float shift = 0;
if (clockY - mBurnInPreventionOffsetYClock < mCutoutTopInset) {
shift = mCutoutTopInset - (clockY - mBurnInPreventionOffsetYClock);
if (clockY - mMaxBurnInPreventionOffsetYClock < mCutoutTopInset) {
shift = mCutoutTopInset - (clockY - mMaxBurnInPreventionOffsetYClock);
}
int burnInPreventionOffsetY = mBurnInPreventionOffsetYClock; // requested offset
int burnInPreventionOffsetY = mMaxBurnInPreventionOffsetYClock; // requested offset
final boolean hasUdfps = mUdfpsTop > -1;
if (hasUdfps && !mIsClockTopAligned) {
// ensure clock doesn't overlap with the udfps icon
@@ -267,8 +275,8 @@ public class KeyguardClockPositionAlgorithm {
// 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;
if (mMaxBurnInPreventionOffsetYClock < burnInPreventionOffsetY) {
burnInPreventionOffsetY = mMaxBurnInPreventionOffsetYClock;
}
shift = -burnInPreventionOffsetY;
} else {
@@ -276,16 +284,18 @@ public class KeyguardClockPositionAlgorithm {
float lowerSpace = mUdfpsTop - mClockBottom;
// center the burn-in offset within the upper + lower space
burnInPreventionOffsetY = (int) (lowerSpace + upperSpace) / 2;
if (mBurnInPreventionOffsetYClock < burnInPreventionOffsetY) {
burnInPreventionOffsetY = mBurnInPreventionOffsetYClock;
if (mMaxBurnInPreventionOffsetYClock < burnInPreventionOffsetY) {
burnInPreventionOffsetY = mMaxBurnInPreventionOffsetYClock;
}
shift = (lowerSpace - upperSpace) / 2;
}
}
float fullyDarkBurnInOffset = burnInPreventionOffsetY(burnInPreventionOffsetY);
float clockYDark = clockY
+ burnInPreventionOffsetY(burnInPreventionOffsetY)
+ fullyDarkBurnInOffset
+ shift;
mCurrentBurnInOffsetY = MathUtils.lerp(0, fullyDarkBurnInOffset, darkAmount);
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mOverStretchAmount);
}
@@ -325,7 +335,7 @@ public class KeyguardClockPositionAlgorithm {
}
private float burnInPreventionOffsetX() {
return getBurnInOffset(mBurnInPreventionOffsetX, true /* xAxis */);
return getBurnInOffset(mMaxBurnInPreventionOffsetX, true /* xAxis */);
}
public static class Result {

View File

@@ -263,6 +263,19 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
}
@Test
public void notifPositionAlignedWithClockAndBurnInOffsetInSplitShadeMode() {
setSplitShadeTopMargin(100); // this makes clock to be at 100
givenAOD();
mIsSplitShade = true;
givenMaxBurnInOffset(100);
givenHighestBurnInOffset(); // this makes clock to be at 200
// WHEN the position algorithm is run
positionClock();
// THEN the notif padding adjusts for burn-in offset: clock position - burn-in offset
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(100);
}
@Test
public void clockPositionedDependingOnMarginInSplitShade() {
setSplitShadeTopMargin(400);