From cfc7d522319cae861a281bd8fa4cadd3eb16962f Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Mon, 8 May 2023 16:30:46 +0000 Subject: [PATCH] fix(non linear font scaling)!: fix QS text being cut off when 200% font scaling Originally the QS tile height is fixed to 80dp and may contain 2 textViews in tile content. When font scaling changed to 200%, the height from 80dp is not enough for the textViews. Therefore, in TileLayout, we estimate the needed height for the tile under given font scaling, and compare with the height from resources/dimens. The larger height would become the exact tile height, to have a proper tile height for full tile content view. Bug: b/272072639 Test: manually - attached video in bug atest TileLayoutTest atest QuickQSPanelTest Change-Id: I6054ef1a6fd0fc28522181f5bc7774cb0abaf14a --- .../com/android/systemui/qs/QuickQSPanel.java | 13 ++++- .../com/android/systemui/qs/TileLayout.java | 38 ++++++++++--- .../android/systemui/qs/TileLayoutTest.java | 53 +++++++++++++++++++ 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 46724adee848a..d8899796b336c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -24,6 +24,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.LinearLayout; import com.android.internal.logging.UiEventLogger; +import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; @@ -198,12 +199,22 @@ public class QuickQSPanel extends QSPanel { @Override public boolean updateResources() { - mCellHeightResId = R.dimen.qs_quick_tile_size; + mResourceCellHeightResId = R.dimen.qs_quick_tile_size; boolean b = super.updateResources(); mMaxAllowedRows = getResources().getInteger(R.integer.quick_qs_panel_max_rows); return b; } + @Override + protected void estimateCellHeight() { + FontSizeUtils.updateFontSize(mTempTextView, R.dimen.qs_tile_text_size); + int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + mTempTextView.measure(unspecifiedSpec, unspecifiedSpec); + int padding = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_padding); + // the QQS only have 1 label + mEstimatedCellHeight = mTempTextView.getMeasuredHeight() + padding * 2; + } + @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 269a158c6b87c..19bf0188c9d24 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -9,10 +9,12 @@ import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.TextView; import androidx.annotation.Nullable; import com.android.internal.logging.UiEventLogger; +import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.qs.QSPanel.QSTileLayout; import com.android.systemui.qs.QSPanelControllerBase.TileRecord; @@ -29,9 +31,10 @@ public class TileLayout extends ViewGroup implements QSTileLayout { protected int mColumns; protected int mCellWidth; - protected int mCellHeightResId = R.dimen.qs_tile_height; + protected int mResourceCellHeightResId = R.dimen.qs_tile_height; + protected int mResourceCellHeight; + protected int mEstimatedCellHeight; protected int mCellHeight; - protected int mMaxCellHeight; protected int mCellMarginHorizontal; protected int mCellMarginVertical; protected int mSidePadding; @@ -49,6 +52,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout { private float mSquishinessFraction = 1f; protected int mLastTileBottom; + protected TextView mTempTextView; + public TileLayout(Context context) { this(context, null); } @@ -57,6 +62,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout { super(context, attrs); mLessRows = ((Settings.System.getInt(context.getContentResolver(), "qs_less_rows", 0) != 0) || useQsMediaPlayer(context)); + mTempTextView = new TextView(context); updateResources(); } @@ -120,14 +126,19 @@ public class TileLayout extends ViewGroup implements QSTileLayout { } public boolean updateResources() { - final Resources res = mContext.getResources(); + Resources res = getResources(); mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns)); - mMaxCellHeight = mContext.getResources().getDimensionPixelSize(mCellHeightResId); + mResourceCellHeight = res.getDimensionPixelSize(mResourceCellHeightResId); mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal); mSidePadding = useSidePadding() ? mCellMarginHorizontal / 2 : 0; mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical); mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows)); - if (mLessRows) mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1); + if (mLessRows) { + mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1); + } + // update estimated cell height under current font scaling + mTempTextView.dispatchConfigurationChanged(mContext.getResources().getConfiguration()); + estimateCellHeight(); if (updateColumns()) { requestLayout(); return true; @@ -211,8 +222,23 @@ public class TileLayout extends ViewGroup implements QSTileLayout { return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY); } + // Estimate the height for the tile with 2 labels (general case) under current font scaling. + protected void estimateCellHeight() { + FontSizeUtils.updateFontSize(mTempTextView, R.dimen.qs_tile_text_size); + int unspecifiedSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + mTempTextView.measure(unspecifiedSpec, unspecifiedSpec); + int padding = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_padding); + mEstimatedCellHeight = mTempTextView.getMeasuredHeight() * 2 + padding * 2; + } + protected int getCellHeight() { - return mMaxCellHeight; + // Compare estimated height with resource height and return the larger one. + // If estimated height > resource height, it means the resource height is not enough + // for the tile content under current font scaling. Therefore, we need to use the estimated + // height to have a full tile content view. + // If estimated height <= resource height, we can use the resource height for tile to keep + // the same UI as original behavior. + return Math.max(mResourceCellHeight, mEstimatedCellHeight); } private void layoutTileRecords(int numRecords, boolean forLayout) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java index 35c8cc70953d3..87892539ccfe0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java @@ -28,8 +28,11 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.test.suitebuilder.annotation.SmallTest; +import android.testing.TestableLooper; +import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; import androidx.test.runner.AndroidJUnit4; @@ -48,6 +51,7 @@ import org.mockito.Mockito; @SmallTest @RunWith(AndroidJUnit4.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) public class TileLayoutTest extends SysuiTestCase { private Resources mResources; private int mLayoutSizeForOneTile; @@ -228,4 +232,53 @@ public class TileLayoutTest extends SysuiTestCase { assertEquals(false, mTileLayout.updateResources()); } + + @Test + public void fontScalingChanged_updateResources_cellHeightEnoughForTileContent() { + final float originalFontScale = mContext.getResources().getConfiguration().fontScale; + float[] testScales = {0.8f, 1.0f, 1.4f, 1.6f, 2.0f}; + for (float scale: testScales) { + changeFontScaling_updateResources_cellHeightEnoughForTileContent(scale); + } + + changeFontScaling(originalFontScale); + } + + private void changeFontScaling_updateResources_cellHeightEnoughForTileContent(float scale) { + changeFontScaling(scale); + + QSPanelControllerBase.TileRecord tileRecord = createTileRecord(); + mTileLayout.addTile(tileRecord); + + FakeTileView tileView = new FakeTileView(mContext); + QSTile.State state = new QSTile.State(); + state.label = "TEST LABEL"; + state.secondaryLabel = "TEST SECONDARY LABEL"; + tileView.changeState(state); + + mTileLayout.updateResources(); + + int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + tileView.measure(spec, spec); + assertTrue(mTileLayout.getCellHeight() >= tileView.getMeasuredHeight()); + + mTileLayout.removeTile(tileRecord); + } + + private static class FakeTileView extends QSTileViewImpl { + FakeTileView(Context context) { + super(context, new QSIconViewImpl(context), /* collapsed= */ false); + } + + void changeState(QSTile.State state) { + handleStateChanged(state); + } + } + + private void changeFontScaling(float scale) { + Configuration configuration = new Configuration(mContext.getResources().getConfiguration()); + configuration.fontScale = scale; + // updateConfiguration could help update on both resource configuration and displayMetrics + mContext.getResources().updateConfiguration(configuration, null, null); + } }