From e2c531408d11c6e778a2cf9d81963b2e52e84e65 Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Wed, 12 Apr 2023 06:48:04 +0000 Subject: [PATCH] fix(non linear font scaling): fix status bar ui broken when 200% font scaling As the bug description, the status bar date and battery persentage text ui are broken when 200% font scaling. We adjust the related dimens and update mechanism to assure the textview fontsize/height are correctly updated when font scaling changed. Besides, we adjust the StatusBarIconView/OngoingPrivacyChip to make the status bar icon image size would also updated to proper size when font scaling changed. Bug: 272071029 Test: manually - video attached in bug atest frameworks/base/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ atest StatusBarIconViewTest Change-Id: I6c4a32eff6473a0dc7cf819dad44fb75a34836c4 --- core/res/res/values/dimens.xml | 8 +- .../status_bar_mobile_signal_group_inner.xml | 21 ++--- .../res/layout/combined_qs_header.xml | 3 +- .../layout/status_bar_wifi_group_inner.xml | 12 +-- .../SystemUI/res/values-sw720dp/dimens.xml | 2 +- packages/SystemUI/res/values/dimens.xml | 51 ++++++------ .../systemui/privacy/OngoingPrivacyChip.kt | 9 ++ .../systemui/statusbar/StatusBarIconView.java | 46 +++++++---- .../phone/NotificationIconContainer.java | 19 +++-- .../phone/StatusBarIconController.java | 19 ++--- .../phone/StatusBarIconControllerImpl.java | 1 + .../statusbar/phone/StatusIconContainer.java | 27 +++++- .../phone/NotificationIconContainerTest.kt | 82 ++++++++++++++++--- 13 files changed, 202 insertions(+), 98 deletions(-) diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index b1b1edf85a09b..6cb9bd563ff4d 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -96,12 +96,12 @@ 96dp - 22dip + 18sp - 15dp + 15sp - 17dp + 17sp 48sp @@ -330,7 +330,7 @@ 16dp - 18dp + 18sp 3dp diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml index 29832a081612d..934fa6f54286a 100644 --- a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml +++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml @@ -30,7 +30,7 @@ diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml index 441f963a855ae..e989372adde3c 100644 --- a/packages/SystemUI/res/layout/combined_qs_header.xml +++ b/packages/SystemUI/res/layout/combined_qs_header.xml @@ -126,8 +126,7 @@ @@ -62,7 +62,7 @@ @@ -75,7 +75,7 @@ diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml index 20864591ae5a6..f40615eb46d04 100644 --- a/packages/SystemUI/res/values-sw720dp/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp/dimens.xml @@ -17,7 +17,7 @@ --> - 1dp + 1sp 28dp 40dp diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index a2eba81155c7e..9e3e838a8d145 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -122,26 +122,26 @@ @*android:dimen/status_bar_icon_size - 2.5dp + 2.5sp - 13.0dp + 13.0sp - 7.8dp + so the width of the icon should be 13.0sp * (12.0 / 20.0) --> + 7.8sp - - 1dp + 1sp 14sp - 7dp + 7sp 0dp @@ -153,16 +153,19 @@ 2dp - 2.5dp + 2.5sp - @*android:dimen/status_bar_system_icon_size + 13sp + + + 13sp - 4dp + 4sp - 0dp + 2sp 1.0 @@ -310,7 +313,7 @@ 56dp - 15dp + 15sp @@ -321,22 +324,22 @@ 90% - 0dp + 0sp - 8dp + 8sp - 8dp + 8sp - 0dp + 0sp - 2dp + 2sp - 3dp + 3sp @@ -617,8 +620,8 @@ 20dp 48dp - 24dp - 24dp + 24sp + 24sp 20dp 88dp @@ -820,7 +823,7 @@ - 2dp + 2sp @@ -1040,13 +1043,13 @@ 0px - 24dp + 24sp 8dp 4dp - 16dp + 16sp 28dp diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt index 79167f276576d..166ba9fba1667 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -15,6 +15,7 @@ package com.android.systemui.privacy import android.content.Context +import android.content.res.Configuration import android.util.AttributeSet import android.view.Gravity.CENTER_VERTICAL import android.view.Gravity.END @@ -102,6 +103,11 @@ class OngoingPrivacyChip @JvmOverloads constructor( R.string.ongoing_privacy_chip_content_multiple_apps, typesText) } + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + updateResources() + } + private fun updateResources() { iconMargin = context.resources .getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin) @@ -110,8 +116,11 @@ class OngoingPrivacyChip @JvmOverloads constructor( iconColor = Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary) + val height = context.resources + .getDimensionPixelSize(R.dimen.ongoing_appops_chip_height) val padding = context.resources .getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding) + iconsContainer.layoutParams.height = height iconsContainer.setPaddingRelative(padding, 0, padding, 0) iconsContainer.background = context.getDrawable(R.drawable.statusbar_privacy_chip_bg) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 91c08a062b546..a4262fa6d3672 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -26,6 +26,7 @@ import android.annotation.IntDef; import android.app.ActivityManager; import android.app.Notification; import android.content.Context; +import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; @@ -75,9 +76,9 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi */ private static final float DARK_ALPHA_BOOST = 0.67f; /** - * Status icons are currently drawn with the intention of being 17dp tall, but we - * want to scale them (in a way that doesn't require an asset dump) down 2dp. So - * 17dp * (15 / 17) = 15dp, the new height. After the first call to {@link #reloadDimens} all + * Status icons are currently drawn with the intention of being 17sp tall, but we + * want to scale them (in a way that doesn't require an asset dump) down 2sp. So + * 17sp * (15 / 17) = 15sp, the new height. After the first call to {@link #reloadDimens} all * values will be in px. */ private float mSystemIconDesiredHeight = 15f; @@ -144,7 +145,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi private String mNumberText; private StatusBarNotification mNotification; private final boolean mBlocked; - private int mDensity; + private Configuration mConfiguration; private boolean mNightMode; private float mIconScale = 1.0f; private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -198,9 +199,8 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi mNumberPain.setAntiAlias(true); setNotification(sbn); setScaleType(ScaleType.CENTER); - mDensity = context.getResources().getDisplayMetrics().densityDpi; - Configuration configuration = context.getResources().getConfiguration(); - mNightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK) + mConfiguration = new Configuration(context.getResources().getConfiguration()); + mNightMode = (mConfiguration.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; initializeDecorColor(); reloadDimens(); @@ -214,7 +214,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi mAlwaysScaleIcon = true; reloadDimens(); maybeUpdateIconScaleDimens(); - mDensity = context.getResources().getDisplayMetrics().densityDpi; + mConfiguration = new Configuration(context.getResources().getConfiguration()); } /** Should always be preceded by {@link #reloadDimens()} */ @@ -231,12 +231,17 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi private void updateIconScaleForNotifications() { final float imageBounds = mIncreasedSize ? mStatusBarIconDrawingSizeIncreased : mStatusBarIconDrawingSize; - final int outerBounds = mStatusBarIconSize; - mIconScale = imageBounds / (float)outerBounds; + float iconHeight = getIconHeight(); + if (iconHeight != 0) { + mIconScale = imageBounds / iconHeight; + } else { + final int outerBounds = mStatusBarIconSize; + mIconScale = imageBounds / (float) outerBounds; + } updatePivot(); } - // Makes sure that all icons are scaled to the same height (15dp). If we cannot get a height + // Makes sure that all icons are scaled to the same height (15sp). If we cannot get a height // for the icon, it uses the default SCALE (15f / 17f) which is the old behavior private void updateIconScaleForSystemIcons() { float iconHeight = getIconHeight(); @@ -267,12 +272,10 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - int density = newConfig.densityDpi; - if (density != mDensity) { - mDensity = density; - reloadDimens(); - updateDrawable(); - maybeUpdateIconScaleDimens(); + final int configDiff = newConfig.diff(mConfiguration); + mConfiguration.setTo(newConfig); + if ((configDiff & (ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_FONT_SCALE)) != 0) { + updateIconDimens(); } boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; @@ -282,6 +285,15 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } } + /** + * Update the icon dimens and drawable with current resources + */ + public void updateIconDimens() { + reloadDimens(); + updateDrawable(); + maybeUpdateIconScaleDimens(); + } + private void reloadDimens() { boolean applyRadius = mDotRadius == mStaticDotRadius; Resources res = getResources(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index bef422ce3004f..92b01ce97c53b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -306,7 +306,7 @@ public class NotificationIconContainer extends ViewGroup { public void applyIconStates() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); - ViewState childState = mIconStates.get(child); + IconState childState = mIconStates.get(child); if (childState != null) { childState.applyToView(child); } @@ -339,6 +339,7 @@ public class NotificationIconContainer extends ViewGroup { } } if (child instanceof StatusBarIconView) { + ((StatusBarIconView) child).updateIconDimens(); ((StatusBarIconView) child).setDozing(mDozing, false, 0); } } @@ -447,9 +448,14 @@ public class NotificationIconContainer extends ViewGroup { @VisibleForTesting boolean isOverflowing(boolean isLastChild, float translationX, float layoutEnd, float iconSize) { - // Layout end, as used here, does not include padding end. - final float overflowX = isLastChild ? layoutEnd : layoutEnd - iconSize; - return translationX >= overflowX; + if (isLastChild) { + return translationX + iconSize > layoutEnd; + } 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; + } } /** @@ -489,10 +495,7 @@ public class NotificationIconContainer extends ViewGroup { // First icon to overflow. if (firstOverflowIndex == -1 && isOverflowing) { firstOverflowIndex = i; - mVisualOverflowStart = layoutEnd - mIconSize; - if (forceOverflow || mIsStaticLayout) { - mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart); - } + mVisualOverflowStart = translationX; } final float drawingScale = mOnLockScreen && view instanceof StatusBarIconView ? ((StatusBarIconView) view).getIconScaleIncreased() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index a8a834f1e8f49..678873c0165cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -203,8 +203,7 @@ public interface StatusBarIconController { @Override protected LayoutParams onCreateLayoutParams() { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); + LinearLayout.LayoutParams lp = super.onCreateLayoutParams(); lp.setMargins(mIconHPadding, 0, mIconHPadding, 0); return lp; } @@ -370,7 +369,7 @@ public interface StatusBarIconController { private final MobileIconsViewModel mMobileIconsViewModel; protected final Context mContext; - protected final int mIconSize; + protected int mIconSize; // Whether or not these icons show up in dumpsys protected boolean mShouldLog = false; private StatusBarIconController mController; @@ -395,10 +394,10 @@ public interface StatusBarIconController { mStatusBarPipelineFlags = statusBarPipelineFlags; mMobileContextProvider = mobileContextProvider; mContext = group.getContext(); - mIconSize = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_icon_size); mLocation = location; + reloadDimens(); + if (statusBarPipelineFlags.runNewMobileIconsBackend()) { // This starts the flow for the new pipeline, and will notify us of changes if // {@link StatusBarPipelineFlags#useNewMobileIcons} is also true. @@ -609,13 +608,9 @@ public interface StatusBarIconController { mGroup.removeAllViews(); } - protected void onDensityOrFontScaleChanged() { - for (int i = 0; i < mGroup.getChildCount(); i++) { - View child = mGroup.getChildAt(i); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); - child.setLayoutParams(lp); - } + protected void reloadDimens() { + mIconSize = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_icon_size); } private void setHeightAndCenter(ImageView imageView, int height) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 3a184239ac436..80d5651a65dc0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -109,6 +109,7 @@ public class StatusBarIconControllerImpl implements Tunable, } group.setController(this); + group.reloadDimens(); mIconGroups.add(group); List allSlots = mStatusBarIconList.getSlots(); for (int i = 0; i < allSlots.size(); i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index 26c17674ab101..ddbfd43f9bf64 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -22,6 +22,8 @@ import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -72,13 +74,16 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { // Any ignored icon will never be added as a child private ArrayList mIgnoredSlots = new ArrayList<>(); + private Configuration mConfiguration; + public StatusIconContainer(Context context) { this(context, null); } public StatusIconContainer(Context context, AttributeSet attrs) { super(context, attrs); - initDimens(); + mConfiguration = new Configuration(context.getResources().getConfiguration()); + reloadDimens(); setWillNotDraw(!DEBUG_OVERFLOW); } @@ -95,7 +100,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { return mShouldRestrictIcons; } - private void initDimens() { + private void reloadDimens() { // This is the same value that StatusBarIconView uses mIconDotFrameWidth = getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); @@ -211,6 +216,16 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { 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 * @param slotName name of the icon as it exists in @@ -348,13 +363,17 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { int totalVisible = mLayoutStates.size(); 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. + // It 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 firstUnderflowIndex = -1; for (int i = totalVisible - 1; i >= 0; i--) { StatusIconState state = mLayoutStates.get(i); // 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))) { firstUnderflowIndex = i; break; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt index b80b825d87dc1..c282c1ef0cf63 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt @@ -21,6 +21,8 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase 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.assertFalse import junit.framework.Assert.assertTrue @@ -49,7 +51,7 @@ class NotificationIconContainerTest : SysuiTestCase() { fun calculateWidthFor_oneIcon_widthForOneIcon() { iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingEnd(10f) - iconContainer.setIconSize(10); + iconContainer.setIconSize(10) assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 1f), /* actual= */ 30f) @@ -59,7 +61,7 @@ class NotificationIconContainerTest : SysuiTestCase() { fun calculateWidthFor_fourIcons_widthForFourIcons() { iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingEnd(10f) - iconContainer.setIconSize(10); + iconContainer.setIconSize(10) assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 4f), /* actual= */ 60f) @@ -69,7 +71,7 @@ class NotificationIconContainerTest : SysuiTestCase() { fun calculateWidthFor_fiveIcons_widthForFourIcons() { iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingEnd(10f) - iconContainer.setIconSize(10); + iconContainer.setIconSize(10) assertEquals(/* expected= */ iconContainer.calculateWidthFor(/* numIcons= */ 5f), /* actual= */ 60f) } @@ -78,7 +80,7 @@ class NotificationIconContainerTest : SysuiTestCase() { fun calculateIconXTranslations_shortShelfOneIcon_atCorrectXWithoutOverflowDot() { iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingEnd(10f) - iconContainer.setIconSize(10); + iconContainer.setIconSize(10) val icon = mockStatusBarIcon() iconContainer.addView(icon) @@ -99,7 +101,7 @@ class NotificationIconContainerTest : SysuiTestCase() { fun calculateIconXTranslations_shortShelfFourIcons_atCorrectXWithoutOverflowDot() { iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingEnd(10f) - iconContainer.setIconSize(10); + iconContainer.setIconSize(10) val iconOne = mockStatusBarIcon() val iconTwo = mockStatusBarIcon() @@ -128,7 +130,7 @@ class NotificationIconContainerTest : SysuiTestCase() { fun calculateIconXTranslations_shortShelfFiveIcons_atCorrectXWithOverflowDot() { iconContainer.setActualPaddingStart(10f) iconContainer.setActualPaddingEnd(10f) - iconContainer.setIconSize(10); + iconContainer.setIconSize(10) val iconOne = mockStatusBarIcon() val iconTwo = mockStatusBarIcon() @@ -153,6 +155,55 @@ class NotificationIconContainerTest : SysuiTestCase() { 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 fun shouldForceOverflow_appearingAboveSpeedBump_true() { val forceOverflow = iconContainer.shouldForceOverflow( @@ -161,7 +212,7 @@ class NotificationIconContainerTest : SysuiTestCase() { /* iconAppearAmount= */ 1f, /* maxVisibleIcons= */ 5 ) - assertTrue(forceOverflow); + assertTrue(forceOverflow) } @Test @@ -172,7 +223,7 @@ class NotificationIconContainerTest : SysuiTestCase() { /* iconAppearAmount= */ 0f, /* maxVisibleIcons= */ 5 ) - assertTrue(forceOverflow); + assertTrue(forceOverflow) } @Test @@ -183,7 +234,7 @@ class NotificationIconContainerTest : SysuiTestCase() { /* iconAppearAmount= */ 0f, /* maxVisibleIcons= */ 5 ) - assertFalse(forceOverflow); + assertFalse(forceOverflow) } @Test @@ -209,6 +260,17 @@ class NotificationIconContainerTest : SysuiTestCase() { assertTrue(isOverflowing) } + @Test + fun isOverflowing_lastChildXGreaterThanDotX_true() { + val isOverflowing = iconContainer.isOverflowing( + /* isLastChild= */ true, + /* translationX= */ 9f, + /* layoutEnd= */ 10f, + /* iconSize= */ 2f, + ) + assertTrue(isOverflowing) + } + @Test fun isOverflowing_lastChildXGreaterThanLayoutEnd_true() { val isOverflowing = iconContainer.isOverflowing( @@ -253,7 +315,7 @@ class NotificationIconContainerTest : SysuiTestCase() { assertTrue(isOverflowing) } - private fun mockStatusBarIcon() : StatusBarIconView { + private fun mockStatusBarIcon(): StatusBarIconView { val iconView = mock(StatusBarIconView::class.java) whenever(iconView.width).thenReturn(10)