From 3cdb32cc1fb39e7515ee49dd0bf62da3841fbb61 Mon Sep 17 00:00:00 2001 From: Brandon Dayauon Date: Tue, 22 Aug 2023 21:26:37 -0700 Subject: [PATCH] Do a vertical check for two line text, if it clips dont show two line. Added extra 16dp to the cell height in DeviceProfile as per spec: https://docs.google.com/presentation/d/1dSt-zY_wRrOmd9a9nsQG458CIK0RUqVJsHJxLHP_0Nc/edit#slide=id.g237e909075a_2_6 Updated tests andincluded vertical check to see if two line can be fully rendered without being clipped. Otherwise just show one line. Since existing cell height is 104dp, we add 16dp to be up to spec (120dp) - Clean up FeatureFlag ENABLE_TWOLINE_ALLAPPS and now use aconfig flag bug: 270390937 Test: manually - photos Regular font: https://screenshot.googleplex.com/ArUcgZgHqR4ZWBQ Bigger font than regular that makes text to one line because it wouldve truncate: https://screenshot.googleplex.com/6s8EdMAbBLsYhLi Bigger font than regular with predicted app row (twoline): https://screenshot.googleplex.com/38TEQei5GvPiCc7 Super big font: https://screenshot.googleplex.com/3JUYYprJRQ32Hsq big display and regular font: https://screenshot.googleplex.com/55rBKVQ8htSe9Vc big display and bigger than regular font: https://screenshot.googleplex.com/3atzKzJUbfM7YQW flag: is off Change-Id: I6998ea5da35d3e00ac75327d16b5ca676fb11c1a --- .../appprediction/PredictionRowView.java | 5 + src/com/android/launcher3/BubbleTextView.java | 71 ++-- src/com/android/launcher3/DeviceProfile.java | 4 + .../launcher3/allapps/BaseAllAppsAdapter.java | 11 +- .../launcher3/config/FeatureFlags.java | 3 + .../launcher3/ui/BubbleTextViewTest.java | 310 ++++++++++-------- 6 files changed, 226 insertions(+), 178 deletions(-) diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java index f82474a8e8..1440498e15 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -36,6 +36,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.allapps.FloatingHeaderRow; import com.android.launcher3.allapps.FloatingHeaderView; import com.android.launcher3.anim.AlphaUpdateListener; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.keyboard.FocusIndicatorHelper; import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper; import com.android.launcher3.model.data.ItemInfo; @@ -126,6 +127,10 @@ public class PredictionRowView int verticalPadding = getResources().getDimensionPixelSize( R.dimen.all_apps_predicted_icon_vertical_padding); int totalHeight = iconHeight + iconPadding + textHeight + verticalPadding * 2; + if (FeatureFlags.enableTwolineAllapps()) { + // Add extra textHeight to the existing total height. + totalHeight += textHeight; + } return getVisibility() == GONE ? 0 : totalHeight + getPaddingTop() + getPaddingBottom(); } diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index bd004e91a5..ab9836f59e 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import static android.text.Layout.Alignment.ALIGN_NORMAL; import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2; import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING; import static com.android.launcher3.config.FeatureFlags.enableCursorHoverStates; @@ -39,6 +40,7 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.icu.text.MessageFormat; +import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; @@ -148,6 +150,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this); private final ActivityContext mActivity; private FastBitmapDrawable mIcon; + private DeviceProfile mDeviceProfile; private boolean mCenterVertically; protected int mDisplay; @@ -206,35 +209,35 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false); mIsRtl = (getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); - DeviceProfile grid = mActivity.getDeviceProfile(); + mDeviceProfile = mActivity.getDeviceProfile(); mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE); final int defaultIconSize; if (mDisplay == DISPLAY_WORKSPACE) { - setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); - setCompoundDrawablePadding(grid.iconDrawablePaddingPx); - defaultIconSize = grid.iconSizePx; - setCenterVertically(grid.iconCenterVertically); + setTextSize(TypedValue.COMPLEX_UNIT_PX, mDeviceProfile.iconTextSizePx); + setCompoundDrawablePadding(mDeviceProfile.iconDrawablePaddingPx); + defaultIconSize = mDeviceProfile.iconSizePx; + setCenterVertically(mDeviceProfile.iconCenterVertically); } else if (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW || mDisplay == DISPLAY_SEARCH_RESULT_APP_ROW) { - setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); - setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx); - defaultIconSize = grid.allAppsIconSizePx; + setTextSize(TypedValue.COMPLEX_UNIT_PX, mDeviceProfile.allAppsIconTextSizePx); + setCompoundDrawablePadding(mDeviceProfile.allAppsIconDrawablePaddingPx); + defaultIconSize = mDeviceProfile.allAppsIconSizePx; } else if (mDisplay == DISPLAY_FOLDER) { - setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.folderChildTextSizePx); - setCompoundDrawablePadding(grid.folderChildDrawablePaddingPx); - defaultIconSize = grid.folderChildIconSizePx; + setTextSize(TypedValue.COMPLEX_UNIT_PX, mDeviceProfile.folderChildTextSizePx); + setCompoundDrawablePadding(mDeviceProfile.folderChildDrawablePaddingPx); + defaultIconSize = mDeviceProfile.folderChildIconSizePx; } else if (mDisplay == DISPLAY_SEARCH_RESULT) { - setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); + setTextSize(TypedValue.COMPLEX_UNIT_PX, mDeviceProfile.allAppsIconTextSizePx); defaultIconSize = getResources().getDimensionPixelSize(R.dimen.search_row_icon_size); } else if (mDisplay == DISPLAY_SEARCH_RESULT_SMALL) { defaultIconSize = getResources().getDimensionPixelSize( R.dimen.search_row_small_icon_size); } else if (mDisplay == DISPLAY_TASKBAR) { - defaultIconSize = grid.iconSizePx; + defaultIconSize = mDeviceProfile.iconSizePx; } else { // widget_selection or shortcut_popup - defaultIconSize = grid.iconSizePx; + defaultIconSize = mDeviceProfile.iconSizePx; } mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false); @@ -274,8 +277,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, mDotParams.scale = 0f; mForceHideDot = false; setBackground(null); - if (Flags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() - || FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()) { + if (FeatureFlags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()) { setMaxLines(1); } @@ -407,8 +409,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, * Only if actual text can be displayed in two line, the {@code true} value will be effective. */ protected boolean shouldUseTwoLine() { - return ((Flags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) - && mDisplay == DISPLAY_ALL_APPS) + return ((FeatureFlags.enableTwolineAllapps()) + && (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW)) || (FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get() && mDisplay == DISPLAY_SEARCH_RESULT); } @@ -691,21 +693,28 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = MeasureSpec.getSize(heightMeasureSpec); if (mCenterVertically) { Paint.FontMetrics fm = getPaint().getFontMetrics(); int cellHeightPx = mIconSize + getCompoundDrawablePadding() + (int) Math.ceil(fm.bottom - fm.top); - int height = MeasureSpec.getSize(heightMeasureSpec); setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(), getPaddingBottom()); } // Only apply two line for all_apps and device search only if necessary. if (shouldUseTwoLine() && (mLastOriginalText != null)) { + int allowedVerticalSpace = height - getPaddingTop() - getPaddingBottom() + - mDeviceProfile.allAppsIconSizePx + - mDeviceProfile.allAppsIconDrawablePaddingPx; CharSequence modifiedString = modifyTitleToSupportMultiLine( MeasureSpec.getSize(widthMeasureSpec) - getCompoundPaddingLeft() - getCompoundPaddingRight(), + allowedVerticalSpace, mLastOriginalText, - getPaint(), mBreakPointsIntArray); + getPaint(), + mBreakPointsIntArray, + getLineSpacingMultiplier(), + getLineSpacingExtra()); if (!TextUtils.equals(modifiedString, mLastModifiedText)) { mLastModifiedText = modifiedString; setText(modifiedString); @@ -785,7 +794,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, * many words as it can until the limit is reached. Once the limit is reached, we decide to * either return the original title or continue on a new line. How to get the new string is by * iterating through the list of break points and determining if the strings between the break - * points can fit within the line it is in. + * points can fit within the line it is in. We will show the modified string if there is enough + * horizontal and vertical space, otherwise this method will just return the original string. * Example assuming each character takes up one spot: * title = "Battery Stats", breakpoint = [6], stringPtr = 0, limitedWidth = 7 * We get the current word -> from sublist(0, breakpoint[i]+1) so sublist (0,7) -> Battery, @@ -794,8 +804,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, * if the first char is a SPACE, we trim to append "Stats". So resulting string would be * "Battery\nStats" */ - public static CharSequence modifyTitleToSupportMultiLine(int limitedWidth, CharSequence title, - TextPaint paint, IntArray breakPoints) { + public static CharSequence modifyTitleToSupportMultiLine(int limitedWidth, int limitedHeight, + CharSequence title, TextPaint paint, IntArray breakPoints, float spacingMultiplier, + float spacingExtra) { // current title is less than the width allowed so we can just skip if (title == null || paint.measureText(title, 0, title.length()) <= limitedWidth) { return title; @@ -816,11 +827,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, if (runningWidth <= limitedWidth) { newString.append(currentWord); } else { - // there is no more space - if (i == 0) { - // if the first words exceeds width, just return as the first line will ellipse - return title; - } else { + if (i != 0) { // If putting word onto a new line, make sure there is no space or new line // character in the beginning of the current word and just put in the rest of // the characters. @@ -834,8 +841,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, : EMPTY; } newString.append(NEW_LINE).append(lastCharacters); - return newString.toString(); + StaticLayout staticLayout = new StaticLayout(newString, paint, limitedWidth, + ALIGN_NORMAL, spacingMultiplier, spacingExtra, false); + if (staticLayout.getHeight() < limitedHeight) { + return newString.toString(); + } } + // if the first words exceeds width, just return as the first line will ellipse + return title; } if (i >= breakPoints.size()) { // no need to look forward into the string if we've already finished processing diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index c05afc94a7..bf35a0fc32 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -1133,6 +1133,10 @@ public class DeviceProfile { if (isVerticalBarLayout()) { hideWorkspaceLabelsIfNotEnoughSpace(); } + if (FeatureFlags.enableTwolineAllapps()) { + // Add extra textHeight to the existing allAppsCellHeight. + allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx); + } updateHotseatSizes(iconSizePx); diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java index 769c787335..005e6dfe87 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java @@ -29,7 +29,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.Flags; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; @@ -138,7 +137,6 @@ public abstract class BaseAllAppsAdapter ex protected final OnClickListener mOnIconClickListener; protected final OnLongClickListener mOnIconLongClickListener; protected OnFocusChangeListener mIconFocusListener; - private final int mExtraTextHeight; public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater, AlphabeticalAppsList apps, SearchAdapterProvider adapterProvider) { @@ -150,8 +148,6 @@ public abstract class BaseAllAppsAdapter ex mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener(); mAdapterProvider = adapterProvider; - mExtraTextHeight = Utilities.calculateTextHeight( - mActivityContext.getDeviceProfile().allAppsIconTextSizePx); } /** Checks if the passed viewType represents all apps divider. */ @@ -177,9 +173,7 @@ public abstract class BaseAllAppsAdapter ex public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case VIEW_TYPE_ICON: - int layout = - !(Flags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) - ? R.layout.all_apps_icon + int layout = !FeatureFlags.enableTwolineAllapps() ? R.layout.all_apps_icon : R.layout.all_apps_icon_twoline; BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate( layout, parent, false); @@ -190,9 +184,6 @@ public abstract class BaseAllAppsAdapter ex // Ensure the all apps icon height matches the workspace icons in portrait mode. icon.getLayoutParams().height = mActivityContext.getDeviceProfile().allAppsCellHeightPx; - if (Flags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) { - icon.getLayoutParams().height += mExtraTextHeight; - } return new ViewHolder(icon); case VIEW_TYPE_EMPTY_SEARCH: return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search, diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 2da85e123f..ea763495a0 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -243,6 +243,9 @@ public final class FeatureFlags { // Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS. public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937, "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps."); + public static boolean enableTwolineAllapps() { + return ENABLE_TWOLINE_ALLAPPS.get() || Flags.enableTwolineAllapps(); + } public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693, "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps"); diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java index bba8c89a05..914f363f41 100644 --- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java +++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java @@ -20,7 +20,6 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.android.launcher3.BubbleTextView.DISPLAY_ALL_APPS; import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW; -import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -36,7 +35,6 @@ import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.search.StringMatcherUtility; import com.android.launcher3.util.ActivityContextWrapper; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.TestUtil; import com.android.launcher3.util.rule.StaticMockitoRule; import com.android.launcher3.views.BaseDragLayer; @@ -75,6 +73,10 @@ public class BubbleTextViewTest { "LEGO®\nBuilder"; private static final String EMPTY_STRING = ""; private static final int CHAR_CNT = 7; + private static final int MAX_HEIGHT = Integer.MAX_VALUE; + private static final int LIMITED_HEIGHT = 357; /* allowedHeight in Pixel6 */ + private static final float SPACE_MULTIPLIER = 1; + private static final float SPACE_EXTRA = 0; private BubbleTextView mBubbleTextView; private ItemInfoWithIcon mItemInfoWithIcon; @@ -111,160 +113,150 @@ public class BubbleTextViewTest { @Test public void testEmptyString_flagOn() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { - mItemInfoWithIcon.title = EMPTY_STRING; - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + mItemInfoWithIcon.title = EMPTY_STRING; + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines()); } @Test public void testEmptyString_flagOff() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { - mItemInfoWithIcon.title = EMPTY_STRING; - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(false); + mItemInfoWithIcon.title = EMPTY_STRING; + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); } @Test public void testStringWithSpaceLongerThanCharLimit_flagOn() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { - // test string: "Battery Stats" - mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "Battery Stats" + mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); } @Test public void testStringWithSpaceLongerThanCharLimit_flagOff() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { - // test string: "Battery Stats" - mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(false); + // test string: "Battery Stats" + mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); } @Test public void testLongStringNoSpaceLongerThanCharLimit_flagOn() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { - // test string: "flutterappflorafy" - mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "flutterappflorafy" + mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); } @Test public void testLongStringNoSpaceLongerThanCharLimit_flagOff() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { - // test string: "flutterappflorafy" - mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(false); + // test string: "flutterappflorafy" + mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); } @Test public void testLongStringWithSpaceLongerThanCharLimit_flagOn() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { - // test string: "System UWB Field Test" - mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "System UWB Field Test" + mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); } @Test public void testLongStringWithSpaceLongerThanCharLimit_flagOff() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { - // test string: "System UWB Field Test" - mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(false); + // test string: "System UWB Field Test" + mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); } @Test public void testLongStringSymbolLongerThanCharLimit_flagOn() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { - // test string: "LEGO®Builder" - mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "LEGO®Builder" + mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); } @Test public void testLongStringSymbolLongerThanCharLimit_flagOff() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { - // test string: "LEGO®Builder" - mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(false); + // test string: "LEGO®Builder" + mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); } @Test @@ -273,8 +265,11 @@ public class BubbleTextViewTest { IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER); CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, + MAX_HEIGHT, TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), - breakPoints); + breakPoints, + SPACE_MULTIPLIER, + SPACE_EXTRA); assertEquals(TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT, newString); } @@ -283,9 +278,11 @@ public class BubbleTextViewTest { // test string: "flutterappflorafy" IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER); - CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, + CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, 0, TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), - breakPoints); + breakPoints, + SPACE_MULTIPLIER, + SPACE_EXTRA); assertEquals(TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, newString); } @@ -295,8 +292,11 @@ public class BubbleTextViewTest { IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER); CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, + MAX_HEIGHT, TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), - breakPoints); + breakPoints, + SPACE_MULTIPLIER, + SPACE_EXTRA); assertEquals(TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT, newString); } @@ -305,25 +305,57 @@ public class BubbleTextViewTest { // test string: "LEGO®Builder" IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT, MATCHER); - CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, + CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine( + mLimitedWidth, + MAX_HEIGHT, TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), - breakPoints); + breakPoints, + SPACE_MULTIPLIER, + SPACE_EXTRA); assertEquals(TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT, newString); } @Test - public void testEnsurePredictionRowIsOneLine() { - try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { - // test string: "Battery Stats" - mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; - mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW); - mBubbleTextView.applyLabel(mItemInfoWithIcon); - mBubbleTextView.setTypeface(Typeface.MONOSPACE); - mBubbleTextView.measure(mLimitedWidth, 0); - mBubbleTextView.onPreDraw(); - assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); - } catch (Exception e) { - throw new RuntimeException(e); - } + public void testEnsurePredictionRowIsTwoLine() { + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "Battery Stats" + mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW); + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); + } + + @Test + public void modifyTitleToSupportMultiLine_whenLimitedHeight_shouldBeOneLine() { + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "LEGO®Builder" + mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); + } + + @Test + public void modifyTitleToSupportMultiLine_whenUnlimitedHeight_shouldBeTwoLine() { + Mockito.when(Flags.enableTwolineAllapps()).thenReturn(true); + // test string: "LEGO®Builder" + mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; + mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); + mBubbleTextView.applyLabel(mItemInfoWithIcon); + mBubbleTextView.setTypeface(Typeface.MONOSPACE); + mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT); + + mBubbleTextView.onPreDraw(); + + assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); } }