Merge changes If1a0855e,I5a079522 into udc-qpr-dev

* changes:
  fix(non linear font scaling): fix QQS clock text right padding may not proper when font sclaing changed
  fix(non linear font scaling): fix status bar icons and dot be cut off or wrong posistion
This commit is contained in:
Roy Chou
2023-07-11 11:52:51 +00:00
committed by Android (Google) Code Review
5 changed files with 112 additions and 21 deletions

View File

@@ -275,6 +275,7 @@ constructor(
lastInsets?.let { updateConstraintsForInsets(header, it) } lastInsets?.let { updateConstraintsForInsets(header, it) }
updateResources() updateResources()
updateCarrierGroupPadding() updateCarrierGroupPadding()
clock.onDensityOrFontScaleChanged()
} }
} }

View File

@@ -448,9 +448,14 @@ public class NotificationIconContainer extends ViewGroup {
@VisibleForTesting @VisibleForTesting
boolean isOverflowing(boolean isLastChild, float translationX, float layoutEnd, boolean isOverflowing(boolean isLastChild, float translationX, float layoutEnd,
float iconSize) { float iconSize) {
// Layout end, as used here, does not include padding end. if (isLastChild) {
final float overflowX = isLastChild ? layoutEnd : layoutEnd - iconSize; return translationX + iconSize > layoutEnd;
return translationX >= overflowX; } else {
// If the child is not the last child, we need to ensure that we have room for the next
// icon and the dot. The dot could be as large as an icon, so verify that we have room
// for 2 icons.
return translationX + iconSize * 2f > layoutEnd;
}
} }
/** /**
@@ -490,10 +495,7 @@ public class NotificationIconContainer extends ViewGroup {
// First icon to overflow. // First icon to overflow.
if (firstOverflowIndex == -1 && isOverflowing) { if (firstOverflowIndex == -1 && isOverflowing) {
firstOverflowIndex = i; firstOverflowIndex = i;
mVisualOverflowStart = layoutEnd - mIconSize; mVisualOverflowStart = translationX;
if (forceOverflow || mIsStaticLayout) {
mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
}
} }
final float drawingScale = mOnLockScreen && view instanceof StatusBarIconView final float drawingScale = mOnLockScreen && view instanceof StatusBarIconView
? ((StatusBarIconView) view).getIconScaleIncreased() ? ((StatusBarIconView) view).getIconScaleIncreased()

View File

@@ -22,6 +22,8 @@ import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
@@ -73,13 +75,16 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
// Any ignored icon will never be added as a child // Any ignored icon will never be added as a child
private ArrayList<String> mIgnoredSlots = new ArrayList<>(); private ArrayList<String> mIgnoredSlots = new ArrayList<>();
private Configuration mConfiguration;
public StatusIconContainer(Context context) { public StatusIconContainer(Context context) {
this(context, null); this(context, null);
} }
public StatusIconContainer(Context context, AttributeSet attrs) { public StatusIconContainer(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
initDimens(); mConfiguration = new Configuration(context.getResources().getConfiguration());
reloadDimens();
setWillNotDraw(!DEBUG_OVERFLOW); setWillNotDraw(!DEBUG_OVERFLOW);
} }
@@ -100,7 +105,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
return mShouldRestrictIcons; return mShouldRestrictIcons;
} }
private void initDimens() { private void reloadDimens() {
// This is the same value that StatusBarIconView uses // This is the same value that StatusBarIconView uses
mIconDotFrameWidth = getResources().getDimensionPixelSize( mIconDotFrameWidth = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size_sp); com.android.internal.R.dimen.status_bar_icon_size_sp);
@@ -233,6 +238,16 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
child.setTag(R.id.status_bar_view_state_tag, null); child.setTag(R.id.status_bar_view_state_tag, null);
} }
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
final int configDiff = newConfig.diff(mConfiguration);
mConfiguration.setTo(newConfig);
if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) {
reloadDimens();
}
}
/** /**
* Add a name of an icon slot to be ignored. It will not show up nor be measured * Add a name of an icon slot to be ignored. It will not show up nor be measured
* @param slotName name of the icon as it exists in * @param slotName name of the icon as it exists in
@@ -342,13 +357,17 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
int totalVisible = mLayoutStates.size(); int totalVisible = mLayoutStates.size();
int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1; int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;
mUnderflowStart = 0; // Init mUnderflowStart value with the offset to let the dot be placed next to battery icon.
// This is to prevent if the underflow happens at rightest(totalVisible - 1) child then
// break the for loop with mUnderflowStart staying 0(initial value), causing the dot be
// placed at the leftest side.
mUnderflowStart = (int) Math.max(contentStart, width - getPaddingEnd() - mUnderflowWidth);
int visible = 0; int visible = 0;
int firstUnderflowIndex = -1; int firstUnderflowIndex = -1;
for (int i = totalVisible - 1; i >= 0; i--) { for (int i = totalVisible - 1; i >= 0; i--) {
StatusIconState state = mLayoutStates.get(i); StatusIconState state = mLayoutStates.get(i);
// Allow room for underflow if we found we need it in onMeasure // Allow room for underflow if we found we need it in onMeasure
if (mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth)) if ((mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth)))
|| (mShouldRestrictIcons && (visible >= maxVisible))) { || (mShouldRestrictIcons && (visible >= maxVisible))) {
firstUnderflowIndex = i; firstUnderflowIndex = i;
break; break;

View File

@@ -374,6 +374,13 @@ public class Clock extends TextView implements
@Override @Override
public void onDensityOrFontScaleChanged() { public void onDensityOrFontScaleChanged() {
reloadDimens();
}
private void reloadDimens() {
// reset mCachedWidth so the new width would be updated properly when next onMeasure
mCachedWidth = -1;
FontSizeUtils.updateFontSize(this, R.dimen.status_bar_clock_size); FontSizeUtils.updateFontSize(this, R.dimen.status_bar_clock_size);
setPaddingRelative( setPaddingRelative(
mContext.getResources().getDimensionPixelSize( mContext.getResources().getDimensionPixelSize(

View File

@@ -21,6 +21,8 @@ import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
import junit.framework.Assert.assertEquals import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue import junit.framework.Assert.assertTrue
@@ -49,7 +51,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateWidthFor_oneIcon_widthForOneIcon() { fun calculateWidthFor_oneIcon_widthForOneIcon() {
iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f) iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10); iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f), assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f),
/* actual= */ 30f) /* actual= */ 30f)
@@ -59,7 +61,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateWidthFor_fourIcons_widthForFourIcons() { fun calculateWidthFor_fourIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f) iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10); iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f), assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f),
/* actual= */ 60f) /* actual= */ 60f)
@@ -69,7 +71,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateWidthFor_fiveIcons_widthForFourIcons() { fun calculateWidthFor_fiveIcons_widthForFourIcons() {
iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f) iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10); iconContainer.setIconSize(10)
assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f), assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f),
/* actual= */ 60f) /* actual= */ 60f)
} }
@@ -78,7 +80,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() { fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f) iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10); iconContainer.setIconSize(10)
val icon = mockStatusBarIcon() val icon = mockStatusBarIcon()
iconContainer.addView(icon) iconContainer.addView(icon)
@@ -99,7 +101,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() { fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f) iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10); iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon() val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon() val iconTwo = mockStatusBarIcon()
@@ -128,7 +130,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() { fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() {
iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingStart(10f)
iconContainer.setActualPaddingEnd(10f) iconContainer.setActualPaddingEnd(10f)
iconContainer.setIconSize(10); iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon() val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon() val iconTwo = mockStatusBarIcon()
@@ -153,6 +155,55 @@ class NotificationIconContainerTest : SysuiTestCase() {
assertTrue(iconContainer.areIconsOverflowing()) assertTrue(iconContainer.areIconsOverflowing())
} }
@Test
fun calculateIconXTranslations_givenWidthEnoughForThreeIcons_atCorrectXWithoutOverflowDot() {
iconContainer.setActualPaddingStart(0f)
iconContainer.setActualPaddingEnd(0f)
iconContainer.setActualLayoutWidth(30)
iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
val iconThree = mockStatusBarIcon()
iconContainer.addView(iconOne)
iconContainer.addView(iconTwo)
iconContainer.addView(iconThree)
assertEquals(3, iconContainer.childCount)
iconContainer.calculateIconXTranslations()
assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
assertEquals(20f, iconContainer.getIconState(iconThree).xTranslation)
assertFalse(iconContainer.areIconsOverflowing())
}
@Test
fun calculateIconXTranslations_givenWidthNotEnoughForFourIcons_atCorrectXWithOverflowDot() {
iconContainer.setActualPaddingStart(0f)
iconContainer.setActualPaddingEnd(0f)
iconContainer.setActualLayoutWidth(35)
iconContainer.setIconSize(10)
val iconOne = mockStatusBarIcon()
val iconTwo = mockStatusBarIcon()
val iconThree = mockStatusBarIcon()
val iconFour = mockStatusBarIcon()
iconContainer.addView(iconOne)
iconContainer.addView(iconTwo)
iconContainer.addView(iconThree)
iconContainer.addView(iconFour)
assertEquals(4, iconContainer.childCount)
iconContainer.calculateIconXTranslations()
assertEquals(0f, iconContainer.getIconState(iconOne).xTranslation)
assertEquals(10f, iconContainer.getIconState(iconTwo).xTranslation)
assertEquals(STATE_DOT, iconContainer.getIconState(iconThree).visibleState)
assertEquals(STATE_HIDDEN, iconContainer.getIconState(iconFour).visibleState)
assertTrue(iconContainer.areIconsOverflowing())
}
@Test @Test
fun shouldForceOverflow_appearingAboveSpeedBump_true() { fun shouldForceOverflow_appearingAboveSpeedBump_true() {
val forceOverflow = iconContainer.shouldForceOverflow( val forceOverflow = iconContainer.shouldForceOverflow(
@@ -161,7 +212,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
/* iconAppearAmount= */ 1f, /* iconAppearAmount= */ 1f,
/* maxVisibleIcons= */ 5 /* maxVisibleIcons= */ 5
) )
assertTrue(forceOverflow); assertTrue(forceOverflow)
} }
@Test @Test
@@ -172,7 +223,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
/* iconAppearAmount= */ 0f, /* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5 /* maxVisibleIcons= */ 5
) )
assertTrue(forceOverflow); assertTrue(forceOverflow)
} }
@Test @Test
@@ -183,7 +234,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
/* iconAppearAmount= */ 0f, /* iconAppearAmount= */ 0f,
/* maxVisibleIcons= */ 5 /* maxVisibleIcons= */ 5
) )
assertFalse(forceOverflow); assertFalse(forceOverflow)
} }
@Test @Test
@@ -209,6 +260,17 @@ class NotificationIconContainerTest : SysuiTestCase() {
assertTrue(isOverflowing) assertTrue(isOverflowing)
} }
@Test
fun isOverflowing_lastChildXGreaterThanDotX_true() {
val isOverflowing = iconContainer.isOverflowing(
/* isLastChild= */ true,
/* translationX= */ 9f,
/* layoutEnd= */ 10f,
/* iconSize= */ 2f,
)
assertTrue(isOverflowing)
}
@Test @Test
fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() { fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() {
val isOverflowing = iconContainer.isOverflowing( val isOverflowing = iconContainer.isOverflowing(
@@ -253,7 +315,7 @@ class NotificationIconContainerTest : SysuiTestCase() {
assertTrue(isOverflowing) assertTrue(isOverflowing)
} }
private fun mockStatusBarIcon() : StatusBarIconView { private fun mockStatusBarIcon(): StatusBarIconView {
val iconView = mock(StatusBarIconView::class.java) val iconView = mock(StatusBarIconView::class.java)
whenever(iconView.width).thenReturn(10) whenever(iconView.width).thenReturn(10)