From 46c55f2975d969a43e91cd33081b01405b11f5a0 Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Fri, 26 May 2023 06:58:37 +0000 Subject: [PATCH] feat(non linear font scaling): scale status bar icons when font scaling changed When font scaling changed to larger, such as 200%, the status bar notification/system icons would be too smaller, compared with clock/battery text size. Therefore, we also scale the status bar icons when font scaling changed. Besides, we adjust OngoingPrivacyChip to ensure the image in chip also scaled with font scaling. Bug: 282111042 Test: manually - video attached in bug atest frameworks/base/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ atest StatusBarIconViewTest Change-Id: I9b876ec9703a3d7310c434b1c025c297e8d5a39d --- core/res/res/values/dimens.xml | 4 +- core/res/res/values/symbols.xml | 1 + .../status_bar_mobile_signal_group_inner.xml | 23 +- .../res/layout/heads_up_status_bar_layout.xml | 4 +- packages/SystemUI/res/layout/status_bar.xml | 2 +- .../layout/status_bar_wifi_group_inner.xml | 12 +- .../SystemUI/res/values-sw720dp/dimens.xml | 2 +- packages/SystemUI/res/values/dimens.xml | 43 ++-- .../systemui/privacy/OngoingPrivacyChip.kt | 18 ++ .../systemui/statusbar/StatusBarIconView.java | 121 ++++++++-- .../statusbar/StatusBarMobileView.java | 2 +- .../systemui/statusbar/StatusBarWifiView.java | 2 +- .../phone/NotificationIconAreaController.java | 2 +- .../phone/NotificationIconContainer.java | 8 +- .../phone/StatusBarIconController.java | 16 +- .../phone/StatusBarIconControllerImpl.java | 1 + .../statusbar/phone/StatusIconContainer.java | 2 +- .../shared/ui/view/ModernStatusBarView.kt | 2 +- .../statusbar/StatusBarIconViewTest.java | 217 ++++++++++++++++++ 19 files changed, 406 insertions(+), 76 deletions(-) diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 24da59a378f81..b129321008d83 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -95,8 +95,10 @@ 96dp 96dp - + 22dip + + 22sp 15dp diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml index d053a7a0d0bb3..28f98f4821fa0 100644 --- a/packages/SystemUI/res/values-sw720dp/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp/dimens.xml @@ -20,7 +20,7 @@ 10dp - 1dp + 1sp 28dp 40dp diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 3bd7a0664d5ab..e1e6c99026509 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -121,24 +121,26 @@ 0dp 6dp - + + @*android:dimen/status_bar_icon_size_sp + @*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 @@ -153,19 +155,26 @@ 0dp - 2dp + 2sp - 2.5dp + 2.5sp + + 17sp - @*android:dimen/status_bar_system_icon_size + 13sp + + + 17sp + + 13sp - 4dp + 4sp - 0dp + 0sp 1.0 @@ -335,7 +344,7 @@ 8dp - 0dp + 0sp 8dp @@ -347,10 +356,10 @@ 0dp - 2dp + 2sp - 3dp + 3sp @@ -838,7 +847,7 @@ - 2dp + 2sp @@ -1064,7 +1073,7 @@ 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 c3b5db42e08dc..310d23407d5da 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt @@ -15,6 +15,8 @@ package com.android.systemui.privacy import android.content.Context +import android.content.pm.ActivityInfo +import android.content.res.Configuration import android.util.AttributeSet import android.view.Gravity.CENTER_VERTICAL import android.view.Gravity.END @@ -35,6 +37,7 @@ class OngoingPrivacyChip @JvmOverloads constructor( defStyleRes: Int = 0 ) : LaunchableFrameLayout(context, attrs, defStyleAttrs, defStyleRes), BackgroundAnimatableView { + private var configuration: Configuration private var iconMargin = 0 private var iconSize = 0 private var iconColor = 0 @@ -54,6 +57,7 @@ class OngoingPrivacyChip @JvmOverloads constructor( clipChildren = true clipToPadding = true iconsContainer = requireViewById(R.id.icons_container) + configuration = Configuration(context.resources.configuration) updateResources() } @@ -102,6 +106,17 @@ class OngoingPrivacyChip @JvmOverloads constructor( R.string.ongoing_privacy_chip_content_multiple_apps, typesText) } + override fun onConfigurationChanged(newConfig: Configuration?) { + super.onConfigurationChanged(newConfig) + if (newConfig != null) { + val diff = newConfig.diff(configuration) + configuration.setTo(newConfig) + if (diff.and(ActivityInfo.CONFIG_DENSITY.or(ActivityInfo.CONFIG_FONT_SCALE)) != 0) { + updateResources() + } + } + } + private fun updateResources() { iconMargin = context.resources .getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin) @@ -110,8 +125,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 4356a3fb29d80..cff71d2edd238 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; @@ -46,12 +47,14 @@ import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.ViewDebug; +import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Interpolator; import androidx.core.graphics.ColorUtils; import com.android.app.animation.Interpolators; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.R; @@ -131,8 +134,11 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi }; private int mStatusBarIconDrawingSizeIncreased = 1; - private int mStatusBarIconDrawingSize = 1; - private int mStatusBarIconSize = 1; + @VisibleForTesting int mStatusBarIconDrawingSize = 1; + + @VisibleForTesting int mOriginalStatusBarIconSize = 1; + @VisibleForTesting int mNewStatusBarIconSize = 1; + @VisibleForTesting float mScaleToFitNewIconSize = 1; private StatusBarIcon mIcon; @ViewDebug.ExportedProperty private String mSlot; private Drawable mNumberBackground; @@ -142,7 +148,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); @@ -196,9 +202,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(); @@ -206,7 +211,8 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } /** Should always be preceded by {@link #reloadDimens()} */ - private void maybeUpdateIconScaleDimens() { + @VisibleForTesting + public void maybeUpdateIconScaleDimens() { // We do not resize and scale system icons (on the right), only notification icons (on the // left). if (isNotification()) { @@ -217,22 +223,63 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } private void updateIconScaleForNotifications() { + float iconScale; + // we need to scale the image size to be same as the original size + // (fit mOriginalStatusBarIconSize), then we can scale it with mScaleToFitNewIconSize + // to fit mNewStatusBarIconSize + float scaleToOriginalDrawingSize = 1.0f; + ViewGroup.LayoutParams lp = getLayoutParams(); + if (getDrawable() != null && (lp != null && lp.width > 0 && lp.height > 0)) { + final int iconViewWidth = lp.width; + final int iconViewHeight = lp.height; + // first we estimate the image exact size when put the drawable in scaled iconView size, + // then we can compute the scaleToOriginalDrawingSize to make the image size fit in + // mOriginalStatusBarIconSize + final int drawableWidth = getDrawable().getIntrinsicWidth(); + final int drawableHeight = getDrawable().getIntrinsicHeight(); + float scaleToFitIconView = Math.min( + (float) iconViewWidth / drawableWidth, + (float) iconViewHeight / drawableHeight); + // if the drawable size <= the icon view size, the drawable won't be scaled + if (scaleToFitIconView > 1.0f) { + scaleToFitIconView = 1.0f; + } + final float scaledImageWidth = drawableWidth * scaleToFitIconView; + final float scaledImageHeight = drawableHeight * scaleToFitIconView; + // if the scaled image size <= mOriginalStatusBarIconSize, we don't need to enlarge it + scaleToOriginalDrawingSize = Math.min( + (float) mOriginalStatusBarIconSize / scaledImageWidth, + (float) mOriginalStatusBarIconSize / scaledImageHeight); + if (scaleToOriginalDrawingSize > 1.0f) { + scaleToOriginalDrawingSize = 1.0f; + } + } + iconScale = scaleToOriginalDrawingSize; + final float imageBounds = mIncreasedSize ? mStatusBarIconDrawingSizeIncreased : mStatusBarIconDrawingSize; - final int outerBounds = mStatusBarIconSize; - mIconScale = imageBounds / (float)outerBounds; + final int originalOuterBounds = mOriginalStatusBarIconSize; + iconScale = iconScale * (imageBounds / (float) originalOuterBounds); + + // scale image to fit new icon size + mIconScale = iconScale * mScaleToFitNewIconSize; + updatePivot(); } // Makes sure that all icons are scaled to the same height (15dp). 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 iconScale; float iconHeight = getIconHeight(); if (iconHeight != 0) { - mIconScale = mSystemIconDesiredHeight / iconHeight; + iconScale = mSystemIconDesiredHeight / iconHeight; } else { - mIconScale = mSystemIconDefaultScale; + iconScale = mSystemIconDefaultScale; } + + // scale image to fit new icon size + mIconScale = iconScale * mScaleToFitNewIconSize; } private float getIconHeight() { @@ -255,12 +302,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; @@ -270,11 +315,22 @@ 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(); mStaticDotRadius = res.getDimensionPixelSize(R.dimen.overflow_dot_radius); - mStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size); + mOriginalStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size); + mNewStatusBarIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size_sp); + mScaleToFitNewIconSize = (float) mNewStatusBarIconSize / mOriginalStatusBarIconSize; mStatusBarIconDrawingSizeIncreased = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size_dark); mStatusBarIconDrawingSize = @@ -482,12 +538,30 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi updateDrawable(); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (!isNotification()) { + // for system icons, calculated measured width from super is for image drawable real + // width (17dp). We may scale the image with font scale, so we also need to scale the + // measured width so that scaled measured width and image width would be fit. + int measuredWidth = getMeasuredWidth(); + int measuredHeight = getMeasuredHeight(); + setMeasuredDimension((int) (measuredWidth * mScaleToFitNewIconSize), measuredHeight); + } + } + @Override protected void onDraw(Canvas canvas) { + // In this method, for width/height division computation we intend to discard the + // fractional part as the original behavior. if (mIconAppearAmount > 0.0f) { canvas.save(); + int px = getWidth() / 2; + int py = getHeight() / 2; canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount, - getWidth() / 2, getHeight() / 2); + (float) px, (float) py); super.onDraw(canvas); canvas.restore(); } @@ -504,10 +578,15 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi } else { float fadeOutAmount = mDotAppearAmount - 1.0f; alpha = alpha * (1.0f - fadeOutAmount); - radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount); + int end = getWidth() / 4; + radius = NotificationUtils.interpolate(mDotRadius, (float) end, fadeOutAmount); } mDotPaint.setAlpha((int) (alpha * 255)); - canvas.drawCircle(mStatusBarIconSize / 2, getHeight() / 2, radius, mDotPaint); + int cx = mNewStatusBarIconSize / 2; + int cy = getHeight() / 2; + canvas.drawCircle( + (float) cx, (float) cy, + radius, mDotPaint); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java index fdad101ae0f65..d6f6c2c281de7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java @@ -135,7 +135,7 @@ public class StatusBarMobileView extends BaseStatusBarFrameLayout implements Dar mDotView = new StatusBarIconView(mContext, mSlot, null); mDotView.setVisibleState(STATE_DOT); - int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size); + int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size_sp); LayoutParams lp = new LayoutParams(width, width); lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START; addView(mDotView, lp); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java index decc70d175b86..8d7214d6bd759 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java @@ -164,7 +164,7 @@ public class StatusBarWifiView extends BaseStatusBarFrameLayout implements DarkR mDotView = new StatusBarIconView(mContext, mSlot, null); mDotView.setVisibleState(STATE_DOT); - int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size); + int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size_sp); LayoutParams lp = new LayoutParams(width, width); lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START; addView(mDotView, lp); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 2fd244e1357f1..0fde3ab3d19ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -239,7 +239,7 @@ public class NotificationIconAreaController implements private void reloadDimens(Context context) { Resources res = context.getResources(); - mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); + mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size_sp); mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin); mAodIconAppearTranslation = res.getDimensionPixelSize( R.dimen.shelf_appear_translation); 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..15ca37a222e52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -339,6 +339,7 @@ public class NotificationIconContainer extends ViewGroup { } } if (child instanceof StatusBarIconView) { + ((StatusBarIconView) child).updateIconDimens(); ((StatusBarIconView) child).setDozing(mDozing, false, 0); } } @@ -537,9 +538,10 @@ public class NotificationIconContainer extends ViewGroup { IconState iconState = mIconStates.get(mIsolatedIcon); if (iconState != null) { // Most of the time the icon isn't yet added when this is called but only happening - // later - iconState.setXTranslation(mIsolatedIconLocation.left - mAbsolutePosition[0] - - (1 - mIsolatedIcon.getIconScale()) * mIsolatedIcon.getWidth() / 2.0f); + // later. The isolated icon position left should equal to the mIsolatedIconLocation + // to ensure the icon be put at the center of the HUN icon placeholder, + // {@See HeadsUpAppearanceController#updateIsolatedIconLocation}. + iconState.setXTranslation(mIsolatedIconLocation.left - mAbsolutePosition[0]); iconState.visibleState = StatusBarIconView.STATE_ICON; } } 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 b14fe90cd1b3b..59583ddf3e34a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -370,7 +370,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 +395,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 +609,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_sp); } 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 604b1f5008db3..3074abec860d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -103,7 +103,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { private void initDimens() { // This is the same value that StatusBarIconView uses mIconDotFrameWidth = getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_icon_size); + com.android.internal.R.dimen.status_bar_icon_size_sp); mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding); mIconSpacing = getResources().getDimensionPixelSize(R.dimen.status_bar_system_icon_spacing); int radius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt index 1a1340484bfc3..83738544ee84d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/view/ModernStatusBarView.kt @@ -118,7 +118,7 @@ open class ModernStatusBarView(context: Context, attrs: AttributeSet?) : it.visibleState = STATE_DOT } - val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size) + val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size_sp) val lp = LayoutParams(width, width) lp.gravity = Gravity.CENTER_VERTICAL or Gravity.START addView(dotView, lp) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java index 1b1f4e41f200d..8d016e30c0c12 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java @@ -45,6 +45,7 @@ import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.UserHandle; import android.service.notification.StatusBarNotification; +import android.view.ViewGroup; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -65,6 +66,8 @@ import org.mockito.ArgumentMatcher; @RunWith(AndroidJUnit4.class) public class StatusBarIconViewTest extends SysuiTestCase { + private static final int TEST_STATUS_BAR_HEIGHT = 150; + @Rule public ExpectedException mThrown = ExpectedException.none(); @@ -184,4 +187,218 @@ public class StatusBarIconViewTest extends SysuiTestCase { // no crash, good } + + @Test + public void testUpdateIconScale_constrainedDrawableSizeLessThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // the icon view layout size would be 60x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, dpIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 50x50. When put the drawable into iconView whose + // layout size is 60x150, the drawable size would not be constrained and thus keep 50x50 + setIconDrawableWithSize(/* width= */ 50, /* height= */ 50); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN both the constrained drawable width/height are less than dpIconSize, + // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize + float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize; + assertEquals(scaleToFitDrawingSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_constrainedDrawableHeightLargerThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // the icon view layout size would be 60x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, dpIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 50x100. When put the drawable into iconView whose + // layout size is 60x150, the drawable size would not be constrained and thus keep 50x100 + setIconDrawableWithSize(/* width= */ 50, /* height= */ 100); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN constrained drawable larger side length 100 >= dpIconSize + // THEN the icon is scaled down from larger side length 100 to ensure both side + // length fit in dpDrawingSize. + float scaleToFitDrawingSize = (float) dpDrawingSize / 100; + assertEquals(scaleToFitDrawingSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_constrainedDrawableWidthLargerThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // the icon view layout size would be 60x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, dpIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 100x50. When put the drawable into iconView whose + // layout size is 60x150, the drawable size would be constrained to 60x30 + setIconDrawableWithSize(/* width= */ 100, /* height= */ 50); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN constrained drawable larger side length 60 >= dpIconSize + // THEN the icon is scaled down from larger side length 60 to ensure both side + // length fit in dpDrawingSize. + float scaleToFitDrawingSize = (float) dpDrawingSize / 60; + assertEquals(scaleToFitDrawingSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_smallerFontAndConstrainedDrawableSizeLessThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // smaller font scaling causes the spIconSize < dpIconSize + int spIconSize = 40; + // the icon view layout size would be 40x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, spIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 50x50. When put the drawable into iconView whose + // layout size is 40x150, the drawable size would be constrained to 40x40 + setIconDrawableWithSize(/* width= */ 50, /* height= */ 50); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN both the constrained drawable width/height are less than dpIconSize, + // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize + float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize; + // THEN the scaled icon should be scaled down further to fit spIconSize + float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; + assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_smallerFontAndConstrainedDrawableHeightLargerThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // smaller font scaling causes the spIconSize < dpIconSize + int spIconSize = 40; + // the icon view layout size would be 40x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, spIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 50x100. When put the drawable into iconView whose + // layout size is 40x150, the drawable size would be constrained to 40x80 + setIconDrawableWithSize(/* width= */ 50, /* height= */ 100); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN constrained drawable larger side length 80 >= dpIconSize + // THEN the icon is scaled down from larger side length 80 to ensure both side + // length fit in dpDrawingSize. + float scaleToFitDrawingSize = (float) dpDrawingSize / 80; + // THEN the scaled icon should be scaled down further to fit spIconSize + float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; + assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_largerFontAndConstrainedDrawableSizeLessThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // larger font scaling causes the spIconSize > dpIconSize + int spIconSize = 80; + // the icon view layout size would be 80x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, spIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 50x50. When put the drawable into iconView whose + // layout size is 80x150, the drawable size would not be constrained and thus keep 50x50 + setIconDrawableWithSize(/* width= */ 50, /* height= */ 50); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN both the constrained drawable width/height are less than dpIconSize, + // THEN the icon is scaled down from dpIconSize to fit the dpDrawingSize + float scaleToFitDrawingSize = (float) dpDrawingSize / dpIconSize; + // THEN the scaled icon should be scaled up to fit spIconSize + float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; + assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_largerFontAndConstrainedDrawableHeightLargerThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // larger font scaling causes the spIconSize > dpIconSize + int spIconSize = 80; + // the icon view layout size would be 80x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, spIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 50x100. When put the drawable into iconView whose + // layout size is 80x150, the drawable size would not be constrained and thus keep 50x100 + setIconDrawableWithSize(/* width= */ 50, /* height= */ 100); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN constrained drawable larger side length 100 >= dpIconSize + // THEN the icon is scaled down from larger side length 100 to ensure both side + // length fit in dpDrawingSize. + float scaleToFitDrawingSize = (float) dpDrawingSize / 100; + // THEN the scaled icon should be scaled up to fit spIconSize + float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; + assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, mIconView.getIconScale(), 0.01f); + } + + @Test + public void testUpdateIconScale_largerFontAndConstrainedDrawableWidthLargerThanDpIconSize() { + int dpIconSize = 60; + int dpDrawingSize = 30; + // larger font scaling causes the spIconSize > dpIconSize + int spIconSize = 80; + // the icon view layout size would be 80x150 + // (the height is always 150 due to TEST_STATUS_BAR_HEIGHT) + setUpIconView(dpIconSize, dpDrawingSize, spIconSize); + mIconView.setNotification(mock(StatusBarNotification.class)); + // the raw drawable size is 100x50. When put the drawable into iconView whose + // layout size is 80x150, the drawable size would not be constrained and thus keep 80x40 + setIconDrawableWithSize(/* width= */ 100, /* height= */ 50); + mIconView.maybeUpdateIconScaleDimens(); + + // WHEN constrained drawable larger side length 80 >= dpIconSize + // THEN the icon is scaled down from larger side length 80 to ensure both side + // length fit in dpDrawingSize. + float scaleToFitDrawingSize = (float) dpDrawingSize / 80; + // THEN the scaled icon should be scaled up to fit spIconSize + float scaleToFitSpIconSize = (float) spIconSize / dpIconSize; + assertEquals(scaleToFitDrawingSize * scaleToFitSpIconSize, + mIconView.getIconScale(), 0.01f); + } + + /** + * Setup iconView dimens for testing. The result icon view layout width would + * be spIconSize and height would be 150. + * + * @param dpIconSize corresponding to status_bar_icon_size + * @param dpDrawingSize corresponding to status_bar_icon_drawing_size + * @param spIconSize corresponding to status_bar_icon_size_sp under different font scaling + */ + private void setUpIconView(int dpIconSize, int dpDrawingSize, int spIconSize) { + mIconView.setIncreasedSize(false); + mIconView.mOriginalStatusBarIconSize = dpIconSize; + mIconView.mStatusBarIconDrawingSize = dpDrawingSize; + + mIconView.mNewStatusBarIconSize = spIconSize; + mIconView.mScaleToFitNewIconSize = (float) spIconSize / dpIconSize; + + // the layout width would be spIconSize + 2 * iconPadding, and we assume iconPadding + // is 0 here. + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(spIconSize, TEST_STATUS_BAR_HEIGHT); + mIconView.setLayoutParams(lp); + } + + private void setIconDrawableWithSize(int width, int height) { + Bitmap bitmap = Bitmap.createBitmap( + width, height, Bitmap.Config.ARGB_8888); + Icon icon = Icon.createWithBitmap(bitmap); + mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", + icon, 0, 0, ""); + // Since we only want to verify icon scale logic here, we directly use + // {@link StatusBarIconView#setImageDrawable(Drawable)} to set the image drawable + // to iconView instead of call {@link StatusBarIconView#set(StatusBarIcon)}. It's to prevent + // the icon drawable size being scaled down when internally calling + // {@link StatusBarIconView#getIcon(Context,Context,StatusBarIcon)}. + mIconView.setImageDrawable(icon.loadDrawable(mContext)); + } }