Merge "Support two line text in AllApps/OnDeviceSearch w/ feature flag" into tm-qpr-dev

This commit is contained in:
Brandon Dayauon
2023-03-10 17:21:37 +00:00
committed by Android (Google) Code Review
7 changed files with 533 additions and 8 deletions
-1
View File
@@ -19,7 +19,6 @@
android:id="@+id/icon"
android:singleLine="false"
android:lines="2"
android:inputType="textMultiLine"
launcher:iconDisplay="all_apps"
launcher:centerVertically="true" />
+118 -3
View File
@@ -52,8 +52,10 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
import com.android.launcher3.dragndrop.DraggableView;
@@ -71,6 +73,8 @@ import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.search.StringMatcherUtility;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.views.ActivityContext;
@@ -97,11 +101,19 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
private static final float MIN_LETTER_SPACING = -0.05f;
private static final int MAX_SEARCH_LOOP_COUNT = 20;
private static final Character NEW_LINE = '\n';
private static final String EMPTY = "";
private static final StringMatcherUtility.StringMatcher MATCHER =
StringMatcherUtility.StringMatcher.getInstance();
private static final int[] STATE_PRESSED = new int[]{android.R.attr.state_pressed};
private float mScaleForReorderBounce = 1f;
private IntArray mBreakPointsIntArray;
private CharSequence mLastOriginalText;
private CharSequence mLastModifiedText;
private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
= new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
@Override
@@ -134,7 +146,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
private FastBitmapDrawable mIcon;
private boolean mCenterVertically;
protected final int mDisplay;
protected int mDisplay;
private final CheckLongPressHelper mLongPressHelper;
@@ -255,6 +267,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
mDotParams.scale = 0f;
mForceHideDot = false;
setBackground(null);
setSingleLine(true);
setMaxLines(1);
setTag(null);
if (mIconLoadRequest != null) {
@@ -382,8 +396,15 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
}
@UiThread
private void applyLabel(ItemInfoWithIcon info) {
setText(info.title);
@VisibleForTesting
public void applyLabel(ItemInfoWithIcon info) {
CharSequence label = info.title;
if (label != null) {
mLastOriginalText = label;
mLastModifiedText = mLastOriginalText;
mBreakPointsIntArray = StringMatcherUtility.getListOfBreakpoints(label, MATCHER);
setText(label);
}
if (info.contentDescription != null) {
setContentDescription(info.isDisabled()
? getContext().getString(R.string.disabled_app_label, info.contentDescription)
@@ -391,6 +412,12 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
}
}
/** This is used for testing to forcefully set the display to ALL_APPS */
@VisibleForTesting
public void setDisplayAllApps() {
mDisplay = DISPLAY_ALL_APPS;
}
/**
* Overrides the default long press timeout.
*/
@@ -637,6 +664,27 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
getPaddingBottom());
}
// only apply two line for all_apps
if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() && (mLastOriginalText != null)
&& (mDisplay == DISPLAY_ALL_APPS)) {
CharSequence modifiedString = modifyTitleToSupportMultiLine(
MeasureSpec.getSize(widthMeasureSpec) - getCompoundPaddingLeft()
- getCompoundPaddingRight(),
mLastOriginalText,
getPaint(), mBreakPointsIntArray);
if (!TextUtils.equals(modifiedString, mLastModifiedText)) {
mLastModifiedText = modifiedString;
setText(modifiedString);
// if text contains NEW_LINE, set max lines to 2
if (TextUtils.indexOf(modifiedString, NEW_LINE) != -1) {
setSingleLine(false);
setMaxLines(2);
} else {
setSingleLine(true);
setMaxLines(1);
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -697,6 +745,73 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
return ObjectAnimator.ofFloat(this, TEXT_ALPHA_PROPERTY, toAlpha);
}
/**
* Generate a new string that will support two line text depending on the current string.
* This method calculates the limited width of a text view and creates a string to fit as
* 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.
* 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,
* now stringPtr = 7 then from sublist(7) the current string is " Stats" and the runningWidth
* at this point exceeds limitedWidth and so we put " Stats" onto the next line (after checking
* 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) {
// 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;
}
float currentWordWidth, runningWidth = 0;
CharSequence currentWord;
StringBuilder newString = new StringBuilder();
int stringPtr = 0;
for (int i = 0; i < breakPoints.size()+1; i++) {
if (i < breakPoints.size()) {
currentWord = title.subSequence(stringPtr, breakPoints.get(i)+1);
} else {
// last word from recent breakpoint until the end of the string
currentWord = title.subSequence(stringPtr, title.length());
}
currentWordWidth = paint.measureText(currentWord,0, currentWord.length());
runningWidth += currentWordWidth;
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 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.
CharSequence lastCharacters = title.subSequence(stringPtr, title.length());
int beginningLetterType =
Character.getType(Character.codePointAt(lastCharacters,0));
if (beginningLetterType == Character.SPACE_SEPARATOR
|| beginningLetterType == Character.LINE_SEPARATOR) {
lastCharacters = lastCharacters.length() > 1
? lastCharacters.subSequence(1, lastCharacters.length())
: EMPTY;
}
newString.append(NEW_LINE).append(lastCharacters);
return newString.toString();
}
}
if (i >= breakPoints.size()) {
// no need to look forward into the string if we've already finished processing
break;
}
stringPtr = breakPoints.get(i)+1;
}
return newString.toString();
}
@Override
public void cancelLongPress() {
super.cancelLongPress();
@@ -33,6 +33,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.SearchAdapterProvider;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.views.ActivityContext;
@@ -140,7 +141,7 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
protected final OnClickListener mOnIconClickListener;
protected OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
protected OnFocusChangeListener mIconFocusListener;
private final int mExtraHeight;
private final int mExtraTextHeight;
public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
@@ -152,7 +153,8 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
mOnIconClickListener = mActivityContext.getItemOnClickListener();
mAdapterProvider = adapterProvider;
mExtraHeight = res.getDimensionPixelSize(R.dimen.all_apps_height_extra);
mExtraTextHeight = Utilities.calculateTextHeight(
mActivityContext.getDeviceProfile().allAppsIconTextSizePx);
}
/**
@@ -197,7 +199,7 @@ public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> ex
icon.getLayoutParams().height =
mActivityContext.getDeviceProfile().allAppsCellHeightPx;
if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
icon.getLayoutParams().height += mExtraHeight;
icon.getLayoutParams().height += mExtraTextHeight;
}
return new ViewHolder(icon);
case VIEW_TYPE_EMPTY_SEARCH:
@@ -113,6 +113,10 @@ public final class FeatureFlags {
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
"ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps.");
public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
"ENABLE_TWOLINE_DEVICESEARCH", false,
"Enable two line label for icons with labels on device search.");
public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = getReleaseFlag(
270391397, "ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", false,
"Allows on device search in all apps logging");
@@ -16,13 +16,20 @@
package com.android.launcher3.search;
import android.text.TextUtils;
import com.android.launcher3.util.IntArray;
import java.text.Collator;
import java.util.stream.IntStream;
/**
* Utilities for matching query string to target string.
*/
public class StringMatcherUtility {
private static final Character SPACE = ' ';
/**
* Returns {@code true} if {@code query} is a prefix of a substring in {@code target}. How to
* break target to valid substring is defined in the given {@code matcher}.
@@ -58,6 +65,41 @@ public class StringMatcherUtility {
return false;
}
/**
* Returns a list of breakpoints wherever the string contains a break. For example:
* "t-mobile" would have breakpoints at [0, 1]
* "Agar.io" would have breakpoints at [3, 4]
* "LEGO®Builder" would have a breakpoint at [4]
*/
public static IntArray getListOfBreakpoints(CharSequence input, StringMatcher matcher) {
int inputLength = input.length();
if ((inputLength <= 2) || TextUtils.indexOf(input, SPACE) != -1) {
// when there is a space in the string, return a list where the elements are the
// position of the spaces - 1. This is to make the logic consistent where breakpoints
// are placed
return IntArray.wrap(IntStream.range(0, inputLength)
.filter(i -> input.charAt(i) == SPACE)
.map(i -> i - 1)
.toArray());
}
IntArray listOfBreakPoints = new IntArray();
int prevType;
int thisType = Character.getType(Character.codePointAt(input, 0));
int nextType = Character.getType(Character.codePointAt(input, 1));
for (int i = 1; i < inputLength; i++) {
prevType = thisType;
thisType = nextType;
nextType = i < (inputLength - 1)
? Character.getType(Character.codePointAt(input, i + 1))
: Character.UNASSIGNED;
if (matcher.isBreak(thisType, prevType, nextType)) {
// breakpoint is at previous
listOfBreakPoints.add(i-1);
}
}
return listOfBreakPoints;
}
/**
* Performs locale sensitive string comparison using {@link Collator}.
*/
@@ -118,7 +160,11 @@ public class StringMatcherUtility {
}
switch (thisType) {
case Character.UPPERCASE_LETTER:
if (nextType == Character.UPPERCASE_LETTER) {
// takes care of the case where there are consistent uppercase letters as well
// as a special symbol following the capitalize letters for example: LEGO®
if (nextType != Character.UPPERCASE_LETTER && nextType != Character.OTHER_SYMBOL
&& nextType != Character.DECIMAL_DIGIT_NUMBER
&& nextType != Character.UNASSIGNED) {
return true;
}
// Follow through
@@ -15,8 +15,10 @@
*/
package com.android.launcher3.search;
import static com.android.launcher3.search.StringMatcherUtility.getListOfBreakpoints;
import static com.android.launcher3.search.StringMatcherUtility.matches;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -25,6 +27,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
import com.android.launcher3.search.StringMatcherUtility.StringMatcherSpace;
import com.android.launcher3.util.IntArray;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -138,4 +141,96 @@ public class StringMatcherUtilityTest {
assertFalse(matches("phant", "elephant", MATCHER_SPACE));
assertFalse(matches("elephants", "elephant", MATCHER_SPACE));
}
@Test
public void testStringWithProperBreaks() {
// empty string
assertEquals(IntArray.wrap(), getListOfBreakpoints("", MATCHER));
// should be "D Dz" that's why breakpoint is at 0
assertEquals(IntArray.wrap(0), getListOfBreakpoints("DDz", MATCHER));
// test all caps and all lower-case
assertEquals(IntArray.wrap(), getListOfBreakpoints("SNKRS", MATCHER));
assertEquals(IntArray.wrap(), getListOfBreakpoints("flutterappflorafy", MATCHER));
assertEquals(IntArray.wrap(), getListOfBreakpoints("LEGO®", MATCHER));
// test camel case
// breakpoint at 9 to be "flutterapp Florafy"
assertEquals(IntArray.wrap(9), getListOfBreakpoints("flutterappFlorafy", MATCHER));
// breakpoint at 4 to be "Metro Zone"
assertEquals(IntArray.wrap(4), getListOfBreakpoints("MetroZone", MATCHER));
// breakpoint at 4,5 to be "metro X Zone"
assertEquals(IntArray.wrap(4,5), getListOfBreakpoints("metroXZone", MATCHER));
// breakpoint at 0 to be "G Pay"
assertEquals(IntArray.wrap(0), getListOfBreakpoints("GPay", MATCHER));
// breakpoint at 4 to be "Whats App"
assertEquals(IntArray.wrap(4), getListOfBreakpoints("WhatsApp", MATCHER));
// breakpoint at 2 to be "aaa A"
assertEquals(IntArray.wrap(2), getListOfBreakpoints("aaaA", MATCHER));
// breakpoint at 4,12,16 to be "Other Launcher Test App"
assertEquals(IntArray.wrap(4,12,16),
getListOfBreakpoints("OtherLauncherTestApp", MATCHER));
// test with TITLECASE_LETTER
// should be "DDz" that's why there are no break points
assertEquals(IntArray.wrap(), getListOfBreakpoints("", MATCHER));
// breakpoint at 0 to be "D DDž"
assertEquals(IntArray.wrap(0), getListOfBreakpoints("DDDž", MATCHER));
// breakpoint at 0 because there is a space to be "Dž DD"
assertEquals(IntArray.wrap(0), getListOfBreakpoints("Dž DD", MATCHER));
// breakpoint at 1 to be "Dw Dz"
assertEquals(IntArray.wrap(1), getListOfBreakpoints("DwDz", MATCHER));
// breakpoint at 0,2 to be "Dw Dz"
assertEquals(IntArray.wrap(0,2), getListOfBreakpoints("wDwDz", MATCHER));
// breakpoint at 1,3 to be "ᾋw Dw Dz"
assertEquals(IntArray.wrap(1,3), getListOfBreakpoints("ᾋwDwDz", MATCHER));
// breakpoint at 0,2,4 to be "ᾋ ᾋw Dw Dz"
assertEquals(IntArray.wrap(0,2,4), getListOfBreakpoints("ᾋᾋwDwDz", MATCHER));
// breakpoint at 0,2,4 to be "ᾋ ᾋw Dw Dz®"
assertEquals(IntArray.wrap(0,2,4), getListOfBreakpoints("ᾋᾋwDwDz®", MATCHER));
// test with numbers and symbols
// breakpoint at 3,11 to be "Test Activity 13"
assertEquals(IntArray.wrap(3,11), getListOfBreakpoints("TestActivity13", MATCHER));
// breakpoint at 3, 4, 12, 13 as the breakpoints are at the dashes
assertEquals(IntArray.wrap(3,4,12,13),
getListOfBreakpoints("Test-Activity-12", MATCHER));
// breakpoint at 1 to be "AA 2"
assertEquals(IntArray.wrap(1), getListOfBreakpoints("AA2", MATCHER));
// breakpoint at 1 to be "AAA 2"
assertEquals(IntArray.wrap(2), getListOfBreakpoints("AAA2", MATCHER));
// breakpoint at 1 to be "ab 2"
assertEquals(IntArray.wrap(1), getListOfBreakpoints("ab2", MATCHER));
// breakpoint at 1,2 to be "el 3 suhwee"
assertEquals(IntArray.wrap(1,2), getListOfBreakpoints("el3suhwee", MATCHER));
// breakpoint at 0,1 as the breakpoints are at '-'
assertEquals(IntArray.wrap(0,1), getListOfBreakpoints("t-mobile", MATCHER));
assertEquals(IntArray.wrap(0,1), getListOfBreakpoints("t-Mobile", MATCHER));
// breakpoint at 0,1,2 as the breakpoints are at '-'
assertEquals(IntArray.wrap(0,1,2), getListOfBreakpoints("t--Mobile", MATCHER));
// breakpoint at 1,2,3 as the breakpoints are at '-'
assertEquals(IntArray.wrap(1,2,3), getListOfBreakpoints("tr--Mobile", MATCHER));
// breakpoint at 3,4 as the breakpoints are at '.'
assertEquals(IntArray.wrap(3,4), getListOfBreakpoints("Agar.io", MATCHER));
assertEquals(IntArray.wrap(3,4), getListOfBreakpoints("Hole.Io", MATCHER));
// breakpoint at 0 to be "µ Torrent®"
assertEquals(IntArray.wrap(0), getListOfBreakpoints("µTorrent®", MATCHER));
// breakpoint at 4 to be "LEGO® Builder"
assertEquals(IntArray.wrap(4), getListOfBreakpoints("LEGO®Builder", MATCHER));
// breakpoint at 4 to be "LEGO® builder"
assertEquals(IntArray.wrap(4), getListOfBreakpoints("LEGO®builder", MATCHER));
// breakpoint at 4 to be "lego® builder"
assertEquals(IntArray.wrap(4), getListOfBreakpoints("lego®builder", MATCHER));
// test string with spaces - where the breakpoints are right before where the spaces are at
assertEquals(IntArray.wrap(3,8), getListOfBreakpoints("HEAD BALL 2", MATCHER));
assertEquals(IntArray.wrap(2,8),
getListOfBreakpoints("OFL Agent Application", MATCHER));
assertEquals(IntArray.wrap(0,2), getListOfBreakpoints("D D z", MATCHER));
assertEquals(IntArray.wrap(6), getListOfBreakpoints("Battery Stats", MATCHER));
assertEquals(IntArray.wrap(5,9,15),
getListOfBreakpoints("System UWB Field Test", MATCHER));
}
}
@@ -0,0 +1,264 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.ui;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import android.graphics.Typeface;
import android.view.ViewGroup;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Utilities;
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.views.BaseDragLayer;
import org.junit.Before;
import org.junit.Test;
/**
* Unit tests for testing modifyTitleToSupportMultiLine() in BubbleTextView.java
* This class tests a couple of strings and uses the getMaxLines() to determine if the test passes.
* Verifying with getMaxLines() is sufficient since BubbleTextView can only be in one line or
* two lines, and this is enough to ensure whether the string should be specifically wrapped onto
* the second line and to ensure truncation.
*/
public class BubbleTextViewTest {
private static final StringMatcherUtility.StringMatcher
MATCHER = StringMatcherUtility.StringMatcher.getInstance();
private static final int ONE_LINE = 1;
private static final int TWO_LINE = 2;
private static final String TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT = "Battery Stats";
private static final String TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT =
"Battery\nStats";
private static final String TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT =
"flutterappflorafy";
private static final String TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT =
"System UWB Field Test";
private static final String TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT =
"System\nUWB Field Test";
private static final String TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT =
"LEGO®Builder";
private static final String TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT =
"LEGO®\nBuilder";
private static final String EMPTY_STRING = "";
private static final int CHAR_CNT = 7;
private BubbleTextView mBubbleTextView;
private ItemInfoWithIcon mItemInfoWithIcon;
private Context mContext;
private int mLimitedWidth;
@Before
public void setUp() throws Exception {
Utilities.enableRunningInTestHarnessForTests();
mContext = new ActivityContextWrapper(getApplicationContext());
mBubbleTextView = new BubbleTextView(mContext);
mBubbleTextView.reset();
mBubbleTextView.setDisplayAllApps();
assertEquals(ONE_LINE, mBubbleTextView.getMaxLines());
BubbleTextView testView = new BubbleTextView(mContext);
testView.setTypeface(Typeface.MONOSPACE);
testView.setText("B");
// calculate the maxWidth of the textView by calculating the width of one monospace
// character * CHAR_CNT
mLimitedWidth =
(int) (testView.getPaint().measureText(testView.getText().toString()) * CHAR_CNT);
// needed otherwise there is a NPE during setText() on checkForRelayout()
mBubbleTextView.setLayoutParams(
new ViewGroup.LayoutParams(mLimitedWidth,
BaseDragLayer.LayoutParams.WRAP_CONTENT));
mItemInfoWithIcon = new ItemInfoWithIcon() {
@Override
public ItemInfoWithIcon clone() {
return null;
}
};
}
@Test
public void testEmptyString_flagOn() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true);
mItemInfoWithIcon.title = EMPTY_STRING;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getMaxLines());
}
@Test
public void testEmptyString_flagOff() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false);
mItemInfoWithIcon.title = EMPTY_STRING;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testStringWithSpaceLongerThanCharLimit_flagOn() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true);
// test string: "Battery Stats"
mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testStringWithSpaceLongerThanCharLimit_flagOff() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false);
// test string: "Battery Stats"
mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringNoSpaceLongerThanCharLimit_flagOn() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true);
// test string: "flutterappflorafy"
mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringNoSpaceLongerThanCharLimit_flagOff() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false);
// test string: "flutterappflorafy"
mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringWithSpaceLongerThanCharLimit_flagOn() {
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.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringWithSpaceLongerThanCharLimit_flagOff() {
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.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringSymbolLongerThanCharLimit_flagOn() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, 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, 0);
mBubbleTextView.onPreDraw();
assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringSymbolLongerThanCharLimit_flagOff() {
TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false);
// test string: "LEGO®Builder"
mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
mBubbleTextView.applyLabel(mItemInfoWithIcon);
mBubbleTextView.setTypeface(Typeface.MONOSPACE);
mBubbleTextView.measure(mLimitedWidth, 0);
mBubbleTextView.onPreDraw();
assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void modifyTitleToSupportMultiLine_TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT() {
// test string: "Battery Stats"
IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints(
TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER);
CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth,
TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(),
breakPoints);
assertEquals(TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT, newString);
}
@Test
public void modifyTitleToSupportMultiLine_TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT() {
// test string: "flutterappflorafy"
IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints(
TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER);
CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth,
TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(),
breakPoints);
assertEquals(TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, newString);
}
@Test
public void modifyTitleToSupportMultiLine_TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT() {
// test string: "System UWB Field Test"
IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints(
TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER);
CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth,
TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(),
breakPoints);
assertEquals(TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT, newString);
}
@Test
public void modifyTitleToSupportMultiLine_TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT() {
// test string: "LEGO®Builder"
IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints(
TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT, MATCHER);
CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth,
TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(),
breakPoints);
assertEquals(TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT, newString);
}
}