1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.ui; 18 19 import static androidx.test.core.app.ApplicationProvider.getApplicationContext; 20 21 import static com.android.launcher3.BubbleTextView.DISPLAY_ALL_APPS; 22 import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW; 23 import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertNotEquals; 27 28 import android.content.Context; 29 import android.graphics.Typeface; 30 import android.view.ViewGroup; 31 32 import com.android.launcher3.BubbleTextView; 33 import com.android.launcher3.Utilities; 34 import com.android.launcher3.model.data.ItemInfoWithIcon; 35 import com.android.launcher3.search.StringMatcherUtility; 36 import com.android.launcher3.util.ActivityContextWrapper; 37 import com.android.launcher3.util.IntArray; 38 import com.android.launcher3.util.TestUtil; 39 import com.android.launcher3.views.BaseDragLayer; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 44 /** 45 * Unit tests for testing modifyTitleToSupportMultiLine() in BubbleTextView.java 46 * This class tests a couple of strings and uses the getMaxLines() to determine if the test passes. 47 * Verifying with getMaxLines() is sufficient since BubbleTextView can only be in one line or 48 * two lines, and this is enough to ensure whether the string should be specifically wrapped onto 49 * the second line and to ensure truncation. 50 */ 51 public class BubbleTextViewTest { 52 53 private static final StringMatcherUtility.StringMatcher 54 MATCHER = StringMatcherUtility.StringMatcher.getInstance(); 55 private static final int ONE_LINE = 1; 56 private static final int TWO_LINE = 2; 57 private static final String TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT = "Battery Stats"; 58 private static final String TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT = 59 "Battery\nStats"; 60 private static final String TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT = 61 "flutterappflorafy"; 62 private static final String TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT = 63 "System UWB Field Test"; 64 private static final String TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT = 65 "System\nUWB Field Test"; 66 private static final String TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT = 67 "LEGO®Builder"; 68 private static final String TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT = 69 "LEGO®\nBuilder"; 70 private static final String EMPTY_STRING = ""; 71 private static final int CHAR_CNT = 7; 72 73 private BubbleTextView mBubbleTextView; 74 private ItemInfoWithIcon mItemInfoWithIcon; 75 private Context mContext; 76 private int mLimitedWidth; 77 78 @Before setUp()79 public void setUp() throws Exception { 80 Utilities.enableRunningInTestHarnessForTests(); 81 mContext = new ActivityContextWrapper(getApplicationContext()); 82 mBubbleTextView = new BubbleTextView(mContext); 83 mBubbleTextView.reset(); 84 85 BubbleTextView testView = new BubbleTextView(mContext); 86 testView.setTypeface(Typeface.MONOSPACE); 87 testView.setText("B"); 88 // calculate the maxWidth of the textView by calculating the width of one monospace 89 // character * CHAR_CNT 90 mLimitedWidth = 91 (int) (testView.getPaint().measureText(testView.getText().toString()) * CHAR_CNT); 92 // needed otherwise there is a NPE during setText() on checkForRelayout() 93 mBubbleTextView.setLayoutParams( 94 new ViewGroup.LayoutParams(mLimitedWidth, 95 BaseDragLayer.LayoutParams.WRAP_CONTENT)); 96 mItemInfoWithIcon = new ItemInfoWithIcon() { 97 @Override 98 public ItemInfoWithIcon clone() { 99 return null; 100 } 101 }; 102 } 103 104 @Test testEmptyString_flagOn()105 public void testEmptyString_flagOn() { 106 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { 107 mItemInfoWithIcon.title = EMPTY_STRING; 108 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 109 mBubbleTextView.applyLabel(mItemInfoWithIcon); 110 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 111 mBubbleTextView.measure(mLimitedWidth, 0); 112 mBubbleTextView.onPreDraw(); 113 assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines()); 114 } catch (Exception e) { 115 throw new RuntimeException(e); 116 } 117 } 118 119 @Test testEmptyString_flagOff()120 public void testEmptyString_flagOff() { 121 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { 122 mItemInfoWithIcon.title = EMPTY_STRING; 123 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 124 mBubbleTextView.applyLabel(mItemInfoWithIcon); 125 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 126 mBubbleTextView.measure(mLimitedWidth, 0); 127 mBubbleTextView.onPreDraw(); 128 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 129 } catch (Exception e) { 130 throw new RuntimeException(e); 131 } 132 } 133 134 @Test testStringWithSpaceLongerThanCharLimit_flagOn()135 public void testStringWithSpaceLongerThanCharLimit_flagOn() { 136 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { 137 // test string: "Battery Stats" 138 mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; 139 mBubbleTextView.applyLabel(mItemInfoWithIcon); 140 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 141 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 142 mBubbleTextView.measure(mLimitedWidth, 0); 143 mBubbleTextView.onPreDraw(); 144 assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); 145 } catch (Exception e) { 146 throw new RuntimeException(e); 147 } 148 } 149 150 @Test testStringWithSpaceLongerThanCharLimit_flagOff()151 public void testStringWithSpaceLongerThanCharLimit_flagOff() { 152 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { 153 // test string: "Battery Stats" 154 mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; 155 mBubbleTextView.applyLabel(mItemInfoWithIcon); 156 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 157 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 158 mBubbleTextView.measure(mLimitedWidth, 0); 159 mBubbleTextView.onPreDraw(); 160 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 161 } catch (Exception e) { 162 throw new RuntimeException(e); 163 } 164 } 165 166 @Test testLongStringNoSpaceLongerThanCharLimit_flagOn()167 public void testLongStringNoSpaceLongerThanCharLimit_flagOn() { 168 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { 169 // test string: "flutterappflorafy" 170 mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT; 171 mBubbleTextView.applyLabel(mItemInfoWithIcon); 172 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 173 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 174 mBubbleTextView.measure(mLimitedWidth, 0); 175 mBubbleTextView.onPreDraw(); 176 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 177 } catch (Exception e) { 178 throw new RuntimeException(e); 179 } 180 } 181 182 @Test testLongStringNoSpaceLongerThanCharLimit_flagOff()183 public void testLongStringNoSpaceLongerThanCharLimit_flagOff() { 184 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { 185 // test string: "flutterappflorafy" 186 mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT; 187 mBubbleTextView.applyLabel(mItemInfoWithIcon); 188 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 189 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 190 mBubbleTextView.measure(mLimitedWidth, 0); 191 mBubbleTextView.onPreDraw(); 192 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 193 } catch (Exception e) { 194 throw new RuntimeException(e); 195 } 196 } 197 198 @Test testLongStringWithSpaceLongerThanCharLimit_flagOn()199 public void testLongStringWithSpaceLongerThanCharLimit_flagOn() { 200 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { 201 // test string: "System UWB Field Test" 202 mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; 203 mBubbleTextView.applyLabel(mItemInfoWithIcon); 204 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 205 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 206 mBubbleTextView.measure(mLimitedWidth, 0); 207 mBubbleTextView.onPreDraw(); 208 assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); 209 } catch (Exception e) { 210 throw new RuntimeException(e); 211 } 212 } 213 214 @Test testLongStringWithSpaceLongerThanCharLimit_flagOff()215 public void testLongStringWithSpaceLongerThanCharLimit_flagOff() { 216 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { 217 // test string: "System UWB Field Test" 218 mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; 219 mBubbleTextView.applyLabel(mItemInfoWithIcon); 220 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 221 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 222 mBubbleTextView.measure(mLimitedWidth, 0); 223 mBubbleTextView.onPreDraw(); 224 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 225 } catch (Exception e) { 226 throw new RuntimeException(e); 227 } 228 } 229 230 @Test testLongStringSymbolLongerThanCharLimit_flagOn()231 public void testLongStringSymbolLongerThanCharLimit_flagOn() { 232 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { 233 // test string: "LEGO®Builder" 234 mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; 235 mBubbleTextView.applyLabel(mItemInfoWithIcon); 236 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 237 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 238 mBubbleTextView.measure(mLimitedWidth, 0); 239 mBubbleTextView.onPreDraw(); 240 assertEquals(TWO_LINE, mBubbleTextView.getLineCount()); 241 } catch (Exception e) { 242 throw new RuntimeException(e); 243 } 244 } 245 246 @Test testLongStringSymbolLongerThanCharLimit_flagOff()247 public void testLongStringSymbolLongerThanCharLimit_flagOff() { 248 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) { 249 // test string: "LEGO®Builder" 250 mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT; 251 mBubbleTextView.applyLabel(mItemInfoWithIcon); 252 mBubbleTextView.setDisplay(DISPLAY_ALL_APPS); 253 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 254 mBubbleTextView.measure(mLimitedWidth, 0); 255 mBubbleTextView.onPreDraw(); 256 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 257 } catch (Exception e) { 258 throw new RuntimeException(e); 259 } 260 } 261 262 @Test modifyTitleToSupportMultiLine_TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT()263 public void modifyTitleToSupportMultiLine_TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT() { 264 // test string: "Battery Stats" 265 IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( 266 TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER); 267 CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, 268 TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), 269 breakPoints); 270 assertEquals(TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT, newString); 271 } 272 273 @Test modifyTitleToSupportMultiLine_TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT()274 public void modifyTitleToSupportMultiLine_TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT() { 275 // test string: "flutterappflorafy" 276 IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( 277 TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER); 278 CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, 279 TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), 280 breakPoints); 281 assertEquals(TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT, newString); 282 } 283 284 @Test modifyTitleToSupportMultiLine_TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT()285 public void modifyTitleToSupportMultiLine_TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT() { 286 // test string: "System UWB Field Test" 287 IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( 288 TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, MATCHER); 289 CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, 290 TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), 291 breakPoints); 292 assertEquals(TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT_RESULT, newString); 293 } 294 295 @Test modifyTitleToSupportMultiLine_TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT()296 public void modifyTitleToSupportMultiLine_TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT() { 297 // test string: "LEGO®Builder" 298 IntArray breakPoints = StringMatcherUtility.getListOfBreakpoints( 299 TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT, MATCHER); 300 CharSequence newString = BubbleTextView.modifyTitleToSupportMultiLine(mLimitedWidth, 301 TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT, mBubbleTextView.getPaint(), 302 breakPoints); 303 assertEquals(TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT_RESULT, newString); 304 } 305 306 @Test testEnsurePredictionRowIsOneLine()307 public void testEnsurePredictionRowIsOneLine() { 308 try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) { 309 // test string: "Battery Stats" 310 mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT; 311 mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW); 312 mBubbleTextView.applyLabel(mItemInfoWithIcon); 313 mBubbleTextView.setTypeface(Typeface.MONOSPACE); 314 mBubbleTextView.measure(mLimitedWidth, 0); 315 mBubbleTextView.onPreDraw(); 316 assertEquals(ONE_LINE, mBubbleTextView.getLineCount()); 317 } catch (Exception e) { 318 throw new RuntimeException(e); 319 } 320 } 321 } 322