ChipsTest.java revision 194d427ebcfc2133bda410e0e4c399250d9a6066
1/* 2 * Copyright (C) 2011 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 17package com.android.ex.chips; 18 19import android.content.Context; 20import android.graphics.Bitmap; 21import android.graphics.drawable.BitmapDrawable; 22import android.graphics.drawable.Drawable; 23import android.test.AndroidTestCase; 24import android.test.suitebuilder.annotation.SmallTest; 25import android.text.Editable; 26import android.text.SpannableStringBuilder; 27import android.text.style.ImageSpan; 28import android.text.util.Rfc822Tokenizer; 29import android.widget.TextView; 30 31import com.android.ex.chips.RecipientEditTextView; 32import com.android.ex.chips.RecipientEntry; 33import com.android.ex.chips.recipientchip.DrawableRecipientChip; 34import com.android.ex.chips.recipientchip.VisibleRecipientChip;; 35 36@SmallTest 37public class ChipsTest extends AndroidTestCase { 38 private DrawableRecipientChip[] mMockRecips; 39 40 private RecipientEntry[] mMockEntries; 41 42 private Rfc822Tokenizer mTokenizer; 43 44 private Editable mEditable; 45 46 class BaseMockRecipientEditTextView extends RecipientEditTextView { 47 48 public BaseMockRecipientEditTextView(Context context) { 49 super(context, null); 50 mTokenizer = new Rfc822Tokenizer(); 51 setTokenizer(mTokenizer); 52 } 53 54 @Override 55 public DrawableRecipientChip[] getSortedRecipients() { 56 return mMockRecips; 57 } 58 59 @Override 60 public int getLineHeight() { 61 return 48; 62 } 63 64 @Override 65 Drawable getChipBackground(RecipientEntry contact) { 66 return createChipBackground(); 67 } 68 69 @Override 70 public int getViewWidth() { 71 return 100; 72 } 73 } 74 75 class MockRecipientEditTextView extends BaseMockRecipientEditTextView { 76 77 public MockRecipientEditTextView(Context context) { 78 super(context); 79 mTokenizer = new Rfc822Tokenizer(); 80 setTokenizer(mTokenizer); 81 } 82 83 @Override 84 public DrawableRecipientChip[] getSortedRecipients() { 85 return mMockRecips; 86 } 87 88 @Override 89 public Editable getText() { 90 return mEditable; 91 } 92 93 @Override 94 public Editable getSpannable() { 95 return mEditable; 96 } 97 98 @Override 99 public int getLineHeight() { 100 return 48; 101 } 102 103 @Override 104 Drawable getChipBackground(RecipientEntry contact) { 105 return createChipBackground(); 106 } 107 108 @Override 109 public int length() { 110 return mEditable != null ? mEditable.length() : 0; 111 } 112 113 @Override 114 public String toString() { 115 return mEditable != null ? mEditable.toString() : ""; 116 } 117 118 @Override 119 public int getViewWidth() { 120 return 100; 121 } 122 } 123 124 private class TestBaseRecipientAdapter extends BaseRecipientAdapter { 125 public TestBaseRecipientAdapter(Context context) { 126 super(context); 127 } 128 } 129 130 private MockRecipientEditTextView createViewForTesting() { 131 mEditable = new SpannableStringBuilder(); 132 MockRecipientEditTextView view = new MockRecipientEditTextView(getContext()); 133 view.setAdapter(new TestBaseRecipientAdapter(getContext())); 134 return view; 135 } 136 137 public void testCreateDisplayText() { 138 RecipientEditTextView view = createViewForTesting(); 139 RecipientEntry entry = RecipientEntry.constructGeneratedEntry("User Name, Jr", 140 "user@username.com", true); 141 String testAddress = view.createAddressText(entry); 142 String testDisplay = view.createChipDisplayText(entry); 143 assertEquals("Expected a properly formatted RFC email address", 144 "\"User Name, Jr\" <user@username.com>, ", testAddress); 145 assertEquals("Expected a displayable name", "User Name, Jr", testDisplay); 146 147 RecipientEntry alreadyFormatted = 148 RecipientEntry.constructFakeEntry("user@username.com, ", true); 149 testAddress = view.createAddressText(alreadyFormatted); 150 testDisplay = view.createChipDisplayText(alreadyFormatted); 151 assertEquals("Expected a properly formatted RFC email address", "<user@username.com>, ", 152 testAddress); 153 assertEquals("Expected a displayable name", "user@username.com", testDisplay); 154 155 RecipientEntry alreadyFormattedNoSpace = RecipientEntry 156 .constructFakeEntry("user@username.com,", true); 157 testAddress = view.createAddressText(alreadyFormattedNoSpace); 158 assertEquals("Expected a properly formatted RFC email address", "<user@username.com>, ", 159 testAddress); 160 161 RecipientEntry alreadyNamed = RecipientEntry.constructGeneratedEntry("User Name", 162 "\"User Name, Jr\" <user@username.com>", true); 163 testAddress = view.createAddressText(alreadyNamed); 164 testDisplay = view.createChipDisplayText(alreadyNamed); 165 assertEquals( 166 "Expected address that used the name not the excess address name", 167 "User Name <user@username.com>, ", testAddress); 168 assertEquals("Expected a displayable name", "User Name", testDisplay); 169 } 170 171 public void testSanitizeBetween() { 172 // First, add 2 chips and then make sure we remove 173 // the extra content between them correctly. 174 populateMocks(2); 175 MockRecipientEditTextView view = createViewForTesting(); 176 String first = (String) mTokenizer.terminateToken("FIRST"); 177 String second = (String) mTokenizer.terminateToken("SECOND"); 178 String extra = "EXTRA"; 179 mEditable = new SpannableStringBuilder(); 180 mEditable.append(first + extra + second); 181 int firstStart = mEditable.toString().indexOf(first); 182 int firstEnd = firstStart + first.trim().length(); 183 int secondStart = mEditable.toString().indexOf(second); 184 int secondEnd = secondStart + second.trim().length(); 185 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], firstStart, firstEnd, 0); 186 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], secondStart, secondEnd, 0); 187 view.sanitizeBetween(); 188 String editableString = mEditable.toString(); 189 assertEquals(editableString.indexOf(extra), -1); 190 assertEquals(editableString.indexOf(first), firstStart); 191 assertEquals(editableString.indexOf(second), secondStart - extra.length()); 192 assertEquals(editableString, (first + second)); 193 194 // Add 1 chip and make sure that we remove the extra stuff before it correctly. 195 mEditable = new SpannableStringBuilder(); 196 populateMocks(1); 197 mEditable.append(extra); 198 mEditable.append(first); 199 firstStart = mEditable.toString().indexOf(first); 200 firstEnd = firstStart + first.length(); 201 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], firstStart, firstEnd, 0); 202 view.sanitizeBetween(); 203 assertEquals(mEditable.toString(), first); 204 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), firstStart 205 - extra.length()); 206 } 207 208 public void testSanitizeEnd() { 209 // First, add 2 chips and then make sure we remove 210 // the extra content between them correctly. 211 populateMocks(2); 212 MockRecipientEditTextView view = createViewForTesting(); 213 String first = (String) mTokenizer.terminateToken("FIRST"); 214 String second = (String) mTokenizer.terminateToken("SECOND"); 215 String extra = "EXTRA"; 216 mEditable = new SpannableStringBuilder(); 217 mEditable.append(first + second); 218 int firstStart = mEditable.toString().indexOf(first); 219 int firstEnd = firstStart + first.trim().length(); 220 int secondStart = mEditable.toString().indexOf(second); 221 int secondEnd = secondStart + second.trim().length(); 222 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], firstStart, firstEnd, 0); 223 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], secondStart, secondEnd, 0); 224 view.sanitizeEnd(); 225 String editableString = mEditable.toString(); 226 assertEquals(editableString.indexOf(extra), -1); 227 assertEquals(editableString.indexOf(first), firstStart); 228 assertEquals(editableString.indexOf(second), secondStart); 229 assertEquals(editableString, (first + second)); 230 mEditable.append(extra); 231 editableString = mEditable.toString(); 232 assertEquals(mEditable.toString(), (first + second + extra)); 233 view.sanitizeEnd(); 234 assertEquals(mEditable.toString(), (first + second)); 235 } 236 237 public void testMoreChipPlainText() { 238 MockRecipientEditTextView view = createViewForTesting(); 239 view.setMoreItem(createTestMoreItem()); 240 String first = (String) mTokenizer.terminateToken("FIRST"); 241 String second = (String) mTokenizer.terminateToken("SECOND"); 242 String third = (String) mTokenizer.terminateToken("THIRD"); 243 mEditable = new SpannableStringBuilder(); 244 mEditable.append(first+second+third); 245 int thirdStart = mEditable.toString().indexOf(third); 246 int thirdEnd = thirdStart + third.trim().length(); 247 view.createMoreChipPlainText(); 248 ImageSpan moreChip = view.getMoreChip(); 249 assertEquals(mEditable.getSpanStart(moreChip), thirdStart); 250 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1); 251 } 252 253 public void testCountTokens() { 254 MockRecipientEditTextView view = createViewForTesting(); 255 view.setMoreItem(createTestMoreItem()); 256 String first = (String) mTokenizer.terminateToken("FIRST"); 257 String second = (String) mTokenizer.terminateToken("SECOND"); 258 String third = (String) mTokenizer.terminateToken("THIRD"); 259 String fourth = "FOURTH,"; 260 String fifth = "FIFTH,"; 261 mEditable = new SpannableStringBuilder(); 262 mEditable.append(first+second+third+fourth+fifth); 263 assertEquals(view.countTokens(mEditable), 5); 264 } 265 266 public void testTooManyRecips() { 267 BaseMockRecipientEditTextView view = new BaseMockRecipientEditTextView(getContext()); 268 view.setMoreItem(createTestMoreItem()); 269 for (int i = 0; i < 100; i++) { 270 view.append(mTokenizer.terminateToken(i + "")); 271 } 272 assertEquals(view.countTokens(view.getText()), 100); 273 view.handlePendingChips(); 274 view.createMoreChip(); 275 ImageSpan moreChip = view.getMoreChip(); 276 // We show 2 chips then place a more chip. 277 int secondStart = view.getText().toString().indexOf( 278 (String) mTokenizer.terminateToken(RecipientEditTextView.CHIP_LIMIT + "")); 279 assertEquals(view.getText().getSpanStart(moreChip), secondStart); 280 assertEquals(view.getText().getSpanEnd(moreChip), view.length()); 281 assertEquals(view.getSortedRecipients(), null); 282 } 283 284 public void testMoreChip() { 285 // Add 3 chips: this is the trigger point at which the more chip will be created. 286 // Test that adding the chips and then creating and removing the more chip, as if 287 // the user were focusing/ removing focus from the chips field. 288 populateMocks(3); 289 MockRecipientEditTextView view = createViewForTesting(); 290 view.setMoreItem(createTestMoreItem()); 291 String first = (String) mTokenizer.terminateToken("FIRST"); 292 String second = (String) mTokenizer.terminateToken("SECOND"); 293 String third = (String) mTokenizer.terminateToken("THIRD"); 294 mEditable = new SpannableStringBuilder(); 295 mEditable.append(first+second+third); 296 297 int firstStart = mEditable.toString().indexOf(first); 298 int firstEnd = firstStart + first.trim().length(); 299 int secondStart = mEditable.toString().indexOf(second); 300 int secondEnd = secondStart + second.trim().length(); 301 int thirdStart = mEditable.toString().indexOf(third); 302 int thirdEnd = thirdStart + third.trim().length(); 303 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 304 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 305 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 306 307 view.createMoreChip(); 308 assertEquals(mEditable.toString(), first+second+third); 309 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 310 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 311 // Find the more chip. 312 ImageSpan moreChip = view.getMoreChip(); 313 assertEquals(mEditable.getSpanStart(moreChip), thirdStart); 314 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1); 315 316 view.removeMoreChip(); 317 assertEquals(mEditable.toString(), first+second+third); 318 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 319 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 320 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 321 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdStart); 322 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdEnd); 323 moreChip = view.getMoreChip(); 324 assertEquals(mEditable.getSpanStart(moreChip), -1); 325 326 // Rinse and repeat, just in case! 327 view.createMoreChip(); 328 assertEquals(mEditable.toString(), first+second+third); 329 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 330 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 331 // Find the more chip. 332 moreChip = view.getMoreChip(); 333 assertEquals(mEditable.getSpanStart(moreChip), thirdStart); 334 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1); 335 336 view.removeMoreChip(); 337 assertEquals(mEditable.toString(), first+second+third); 338 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 339 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 340 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 341 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdStart); 342 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdEnd); 343 moreChip = view.getMoreChip(); 344 assertEquals(mEditable.getSpanStart(moreChip), -1); 345 } 346 347 public void testMoreChipLotsOfUsers() { 348 // Test adding and removing the more chip in the case where we have a lot of users. 349 populateMocks(10); 350 MockRecipientEditTextView view = createViewForTesting(); 351 view.setMoreItem(createTestMoreItem()); 352 String first = (String) mTokenizer.terminateToken("FIRST"); 353 String second = (String) mTokenizer.terminateToken("SECOND"); 354 String third = (String) mTokenizer.terminateToken("THIRD"); 355 String fourth = (String) mTokenizer.terminateToken("FOURTH"); 356 String fifth = (String) mTokenizer.terminateToken("FIFTH"); 357 String sixth = (String) mTokenizer.terminateToken("SIXTH"); 358 String seventh = (String) mTokenizer.terminateToken("SEVENTH"); 359 String eigth = (String) mTokenizer.terminateToken("EIGHTH"); 360 String ninth = (String) mTokenizer.terminateToken("NINTH"); 361 String tenth = (String) mTokenizer.terminateToken("TENTH"); 362 mEditable = new SpannableStringBuilder(); 363 mEditable.append(first+second+third+fourth+fifth+sixth+seventh+eigth+ninth+tenth); 364 365 int firstStart = mEditable.toString().indexOf(first); 366 int firstEnd = firstStart + first.trim().length(); 367 int secondStart = mEditable.toString().indexOf(second); 368 int secondEnd = secondStart + second.trim().length(); 369 int thirdStart = mEditable.toString().indexOf(third); 370 int thirdEnd = thirdStart + third.trim().length(); 371 int fourthStart = mEditable.toString().indexOf(fourth); 372 int fourthEnd = fourthStart + fourth.trim().length(); 373 int fifthStart = mEditable.toString().indexOf(fifth); 374 int fifthEnd = fifthStart + fifth.trim().length(); 375 int sixthStart = mEditable.toString().indexOf(sixth); 376 int sixthEnd = sixthStart + sixth.trim().length(); 377 int seventhStart = mEditable.toString().indexOf(seventh); 378 int seventhEnd = seventhStart + seventh.trim().length(); 379 int eighthStart = mEditable.toString().indexOf(eigth); 380 int eighthEnd = eighthStart + eigth.trim().length(); 381 int ninthStart = mEditable.toString().indexOf(ninth); 382 int ninthEnd = ninthStart + ninth.trim().length(); 383 int tenthStart = mEditable.toString().indexOf(tenth); 384 int tenthEnd = tenthStart + tenth.trim().length(); 385 mEditable.setSpan(mMockRecips[mMockRecips.length - 10], firstStart, firstEnd, 0); 386 mEditable.setSpan(mMockRecips[mMockRecips.length - 9], secondStart, secondEnd, 0); 387 mEditable.setSpan(mMockRecips[mMockRecips.length - 8], thirdStart, thirdEnd, 0); 388 mEditable.setSpan(mMockRecips[mMockRecips.length - 7], fourthStart, fourthEnd, 0); 389 mEditable.setSpan(mMockRecips[mMockRecips.length - 6], fifthStart, fifthEnd, 0); 390 mEditable.setSpan(mMockRecips[mMockRecips.length - 5], sixthStart, sixthEnd, 0); 391 mEditable.setSpan(mMockRecips[mMockRecips.length - 4], seventhStart, seventhEnd, 0); 392 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], eighthStart, eighthEnd, 0); 393 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], ninthStart, ninthEnd, 0); 394 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], tenthStart, tenthEnd, 0); 395 396 view.createMoreChip(); 397 assertEquals(mEditable.toString(), first + second + third + fourth + fifth + sixth 398 + seventh + eigth + ninth + tenth); 399 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 10]), firstStart); 400 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 9]), secondStart); 401 // Find the more chip. 402 ImageSpan moreChip = view.getMoreChip(); 403 assertEquals(mEditable.getSpanStart(moreChip), thirdStart); 404 assertEquals(mEditable.getSpanEnd(moreChip), tenthEnd + 1); 405 406 view.removeMoreChip(); 407 assertEquals(mEditable.toString(), first + second + third + fourth + fifth + sixth 408 + seventh + eigth + ninth + tenth); 409 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 10]), firstStart); 410 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 9]), secondStart); 411 412 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 8]), thirdStart); 413 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 7]), fourthStart); 414 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 6]), fifthStart); 415 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 5]), sixthStart); 416 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 4]), seventhStart); 417 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), eighthStart); 418 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), ninthStart); 419 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), tenthStart); 420 moreChip = view.getMoreChip(); 421 assertEquals(mEditable.getSpanStart(moreChip), -1); 422 423 } 424 425 public void testMoreChipSpecialChars() { 426 // Make sure the more chip correctly handles extra tokenizer characters in the middle 427 // of chip text. 428 populateMocks(3); 429 MockRecipientEditTextView view = createViewForTesting(); 430 view.setMoreItem(createTestMoreItem()); 431 String first = (String) mTokenizer.terminateToken("FI,RST"); 432 String second = (String) mTokenizer.terminateToken("SE,COND"); 433 String third = (String) mTokenizer.terminateToken("THI,RD"); 434 mEditable = new SpannableStringBuilder(); 435 mEditable.append(first+second+third); 436 437 int firstStart = mEditable.toString().indexOf(first); 438 int firstEnd = firstStart + first.trim().length(); 439 int secondStart = mEditable.toString().indexOf(second); 440 int secondEnd = secondStart + second.trim().length(); 441 int thirdStart = mEditable.toString().indexOf(third); 442 int thirdEnd = thirdStart + third.trim().length(); 443 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 444 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 445 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 446 447 view.createMoreChip(); 448 assertEquals(mEditable.toString(), first+second+third); 449 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 450 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 451 // Find the more chip. 452 ImageSpan moreChip = view.getMoreChip(); 453 assertEquals(mEditable.getSpanStart(moreChip), thirdStart); 454 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1); 455 456 view.removeMoreChip(); 457 assertEquals(mEditable.toString(), first+second+third); 458 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 459 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 460 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 461 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdStart); 462 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdEnd); 463 moreChip = view.getMoreChip(); 464 assertEquals(mEditable.getSpanStart(moreChip), -1); 465 } 466 467 public void testMoreChipDupes() { 468 // Make sure the more chip is correctly added and removed when we have duplicate chips. 469 populateMocks(4); 470 MockRecipientEditTextView view = createViewForTesting(); 471 view.setMoreItem(createTestMoreItem()); 472 String first = (String) mTokenizer.terminateToken("FIRST"); 473 String second = (String) mTokenizer.terminateToken("SECOND"); 474 String third = (String) mTokenizer.terminateToken("THIRD"); 475 mEditable = new SpannableStringBuilder(); 476 mEditable.append(first+second+third+third); 477 478 int firstStart = mEditable.toString().indexOf(first); 479 int firstEnd = firstStart + first.trim().length(); 480 int secondStart = mEditable.toString().indexOf(second); 481 int secondEnd = secondStart + second.trim().length(); 482 int thirdStart = mEditable.toString().indexOf(third); 483 int thirdEnd = thirdStart + third.trim().length(); 484 int thirdNextStart = mEditable.toString().indexOf(third, thirdEnd); 485 int thirdNextEnd = thirdNextStart + third.trim().length(); 486 mEditable.setSpan(mMockRecips[mMockRecips.length - 4], firstStart, firstEnd, 0); 487 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], secondStart, secondEnd, 0); 488 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], thirdStart, thirdEnd, 0); 489 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdNextStart, thirdNextEnd, 0); 490 491 view.createMoreChip(); 492 assertEquals(mEditable.toString(), first+second+third+third); 493 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 4]), firstStart); 494 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), secondStart); 495 // Find the more chip. 496 ImageSpan moreChip = view.getMoreChip(); 497 assertEquals(mEditable.getSpanStart(moreChip), thirdStart); 498 assertEquals(mEditable.getSpanEnd(moreChip), thirdNextEnd + 1); 499 500 view.removeMoreChip(); 501 assertEquals(mEditable.toString(), first+second+third+third); 502 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 4]), firstStart); 503 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 4]), firstEnd); 504 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), secondStart); 505 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), thirdStart); 506 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), thirdEnd); 507 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdNextStart); 508 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdNextEnd); 509 moreChip = view.getMoreChip(); 510 assertEquals(mEditable.getSpanStart(moreChip), -1); 511 } 512 513 public void testRemoveChip() { 514 // Create 3 chips to start and test removing chips in various postions. 515 populateMocks(3); 516 MockRecipientEditTextView view = createViewForTesting(); 517 view.setMoreItem(createTestMoreItem()); 518 String first = (String) mTokenizer.terminateToken("FIRST"); 519 String second = (String) mTokenizer.terminateToken("SECOND"); 520 String third = (String) mTokenizer.terminateToken("THIRD"); 521 mEditable = new SpannableStringBuilder(); 522 mEditable.append(first + second + third); 523 524 int firstStart = mEditable.toString().indexOf(first); 525 int firstEnd = firstStart + first.length(); 526 int secondStart = mEditable.toString().indexOf(second); 527 int secondEnd = secondStart + second.length(); 528 int thirdStart = mEditable.toString().indexOf(third); 529 int thirdEnd = thirdStart + third.length(); 530 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 531 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 532 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 533 assertEquals(mEditable.toString(), first + second + third); 534 // Test removing the middle chip. 535 view.removeChip(mMockRecips[mMockRecips.length - 2]); 536 assertEquals(mEditable.toString(), first + third); 537 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 538 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 539 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), -1); 540 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), -1); 541 int newThirdStart = mEditable.toString().indexOf(third); 542 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), newThirdStart); 543 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), newThirdStart 544 + third.length()); 545 546 // Test removing the first chip. 547 populateMocks(3); 548 view = createViewForTesting(); 549 view.setMoreItem(createTestMoreItem()); 550 mEditable = new SpannableStringBuilder(); 551 mEditable.append(first + second + third); 552 553 firstStart = mEditable.toString().indexOf(first); 554 firstEnd = firstStart + first.length(); 555 secondStart = mEditable.toString().indexOf(second); 556 secondEnd = secondStart + second.length(); 557 thirdStart = mEditable.toString().indexOf(third); 558 thirdEnd = thirdStart + third.length(); 559 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 560 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 561 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 562 assertEquals(mEditable.toString(), first + second + third); 563 view.removeChip(mMockRecips[mMockRecips.length - 3]); 564 assertEquals(mEditable.toString(), second + third); 565 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), -1); 566 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), -1); 567 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), 0); 568 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), second.length()); 569 newThirdStart = mEditable.toString().indexOf(third); 570 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), newThirdStart); 571 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), newThirdStart 572 + third.length()); 573 574 // Test removing the last chip. 575 populateMocks(3); 576 view = createViewForTesting(); 577 view.setMoreItem(createTestMoreItem()); 578 mEditable = new SpannableStringBuilder(); 579 mEditable.append(first + second + third); 580 581 firstStart = mEditable.toString().indexOf(first); 582 firstEnd = firstStart + first.length(); 583 secondStart = mEditable.toString().indexOf(second); 584 secondEnd = secondStart + second.length(); 585 thirdStart = mEditable.toString().indexOf(third); 586 thirdEnd = thirdStart + third.length(); 587 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 588 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 589 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 590 assertEquals(mEditable.toString(), first + second + third); 591 view.removeChip(mMockRecips[mMockRecips.length - 1]); 592 assertEquals(mEditable.toString(), first + second); 593 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 594 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 595 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 596 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), secondEnd); 597 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), -1); 598 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), -1); 599 } 600 601 public void testReplaceChip() { 602 populateMocks(3); 603 MockRecipientEditTextView view = createViewForTesting(); 604 view.setMoreItem(createTestMoreItem()); 605 view.setChipBackground(createChipBackground()); 606 view.setChipHeight(48); 607 String first = (String) mTokenizer.terminateToken("FIRST"); 608 String second = (String) mTokenizer.terminateToken("SECOND"); 609 String third = (String) mTokenizer.terminateToken("THIRD"); 610 mEditable = new SpannableStringBuilder(); 611 mEditable.append(first + second + third); 612 613 // Test replacing the first chip with a new chip. 614 int firstStart = mEditable.toString().indexOf(first); 615 int firstEnd = firstStart + first.trim().length(); 616 int secondStart = mEditable.toString().indexOf(second); 617 int secondEnd = secondStart + second.trim().length(); 618 int thirdStart = mEditable.toString().indexOf(third); 619 int thirdEnd = thirdStart + third.trim().length(); 620 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 621 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 622 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 623 assertEquals(mEditable.toString(), first + second + third); 624 view.replaceChip(mMockRecips[mMockRecips.length - 3], RecipientEntry 625 .constructGeneratedEntry("replacement", "replacement@replacement.com", true)); 626 assertEquals(mEditable.toString(), mTokenizer 627 .terminateToken("replacement <replacement@replacement.com>") 628 + second + third); 629 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), -1); 630 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), -1); 631 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), mEditable 632 .toString().indexOf(second)); 633 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), mEditable 634 .toString().indexOf(second) 635 + second.trim().length()); 636 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), mEditable 637 .toString().indexOf(third)); 638 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), mEditable 639 .toString().indexOf(third) 640 + third.trim().length()); 641 DrawableRecipientChip[] spans = 642 mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class); 643 assertEquals(spans.length, 3); 644 spans = mEditable 645 .getSpans(0, mEditable.toString().indexOf(second) - 1, DrawableRecipientChip.class); 646 assertEquals((String) spans[0].getDisplay(), "replacement"); 647 648 649 // Test replacing the middle chip with a new chip. 650 mEditable = new SpannableStringBuilder(); 651 mEditable.append(first + second + third); 652 firstStart = mEditable.toString().indexOf(first); 653 firstEnd = firstStart + first.trim().length(); 654 secondStart = mEditable.toString().indexOf(second); 655 secondEnd = secondStart + second.trim().length(); 656 thirdStart = mEditable.toString().indexOf(third); 657 thirdEnd = thirdStart + third.trim().length(); 658 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 659 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 660 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 661 assertEquals(mEditable.toString(), first + second + third); 662 view.replaceChip(mMockRecips[mMockRecips.length - 2], RecipientEntry 663 .constructGeneratedEntry("replacement", "replacement@replacement.com", true)); 664 assertEquals(mEditable.toString(), first + mTokenizer 665 .terminateToken("replacement <replacement@replacement.com>") + third); 666 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 667 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 668 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), -1); 669 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), -1); 670 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), mEditable 671 .toString().indexOf(third)); 672 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), mEditable 673 .toString().indexOf(third) 674 + third.trim().length()); 675 spans = mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class); 676 assertEquals(spans.length, 3); 677 spans = mEditable.getSpans(firstEnd, mEditable.toString().indexOf(third) - 1, 678 DrawableRecipientChip.class); 679 assertEquals((String) spans[0].getDisplay(), "replacement"); 680 681 682 // Test replacing the last chip with a new chip. 683 mEditable = new SpannableStringBuilder(); 684 mEditable.append(first + second + third); 685 firstStart = mEditable.toString().indexOf(first); 686 firstEnd = firstStart + first.trim().length(); 687 secondStart = mEditable.toString().indexOf(second); 688 secondEnd = secondStart + second.trim().length(); 689 thirdStart = mEditable.toString().indexOf(third); 690 thirdEnd = thirdStart + third.trim().length(); 691 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 692 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 693 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 694 assertEquals(mEditable.toString(), first + second + third); 695 view.replaceChip(mMockRecips[mMockRecips.length - 1], RecipientEntry 696 .constructGeneratedEntry("replacement", "replacement@replacement.com", true)); 697 assertEquals(mEditable.toString(), first + second + mTokenizer 698 .terminateToken("replacement <replacement@replacement.com>")); 699 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart); 700 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd); 701 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart); 702 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), secondEnd); 703 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), -1); 704 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), -1); 705 spans = mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class); 706 assertEquals(spans.length, 3); 707 spans = mEditable 708 .getSpans(secondEnd, mEditable.length(), DrawableRecipientChip.class); 709 assertEquals((String) spans[0].getDisplay(), "replacement"); 710 } 711 712 public void testHandlePaste() { 713 // Start with an empty edit field. 714 // Add an address; the text should be left as is. 715 MockRecipientEditTextView view = createViewForTesting(); 716 view.setMoreItem(createTestMoreItem()); 717 view.setChipBackground(createChipBackground()); 718 view.setChipHeight(48); 719 mEditable = new SpannableStringBuilder(); 720 mEditable.append("user@user.com"); 721 view.setSelection(mEditable.length()); 722 view.handlePaste(); 723 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 0); 724 assertEquals(mEditable.toString(), "user@user.com"); 725 726 // Test adding a single address to an empty chips field with a space at 727 // the end of it. The address should stay as text. 728 mEditable = new SpannableStringBuilder(); 729 String tokenizedUser = "user@user.com" + " "; 730 mEditable.append(tokenizedUser); 731 view.setSelection(mEditable.length()); 732 view.handlePaste(); 733 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 0); 734 assertEquals(mEditable.toString(), tokenizedUser); 735 736 // Test adding a single address to an empty chips field with a semicolon at 737 // the end of it. The address should become a chip 738 mEditable = new SpannableStringBuilder(); 739 tokenizedUser = "user@user.com;"; 740 mEditable.append(tokenizedUser); 741 view.setSelection(mEditable.length()); 742 view.handlePaste(); 743 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 1); 744 745 // Test adding 2 address to an empty chips field. The second to last 746 // address should become a chip and the last address should stay as 747 // text. 748 mEditable = new SpannableStringBuilder(); 749 mEditable.append("user1,user2@user.com"); 750 view.setSelection(mEditable.length()); 751 view.handlePaste(); 752 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 1); 753 assertEquals(mEditable.getSpans(0, mEditable.toString().indexOf("user2@user.com"), 754 DrawableRecipientChip.class).length, 1); 755 assertEquals(mEditable.toString(), "<user1>, user2@user.com"); 756 757 // Test adding a single address to the end of existing chips. The existing 758 // chips should remain, and the last address should stay as text. 759 populateMocks(3); 760 String first = (String) mTokenizer.terminateToken("FIRST"); 761 String second = (String) mTokenizer.terminateToken("SECOND"); 762 String third = (String) mTokenizer.terminateToken("THIRD"); 763 mEditable = new SpannableStringBuilder(); 764 mEditable.append(first + second + third); 765 view.setSelection(mEditable.length()); 766 int firstStart = mEditable.toString().indexOf(first); 767 int firstEnd = firstStart + first.trim().length(); 768 int secondStart = mEditable.toString().indexOf(second); 769 int secondEnd = secondStart + second.trim().length(); 770 int thirdStart = mEditable.toString().indexOf(third); 771 int thirdEnd = thirdStart + third.trim().length(); 772 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 773 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 774 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 775 776 mEditable.append("user@user.com"); 777 view.setSelection(mEditable.length()); 778 view.handlePaste(); 779 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 780 mMockRecips.length); 781 assertEquals(mEditable.toString(), first + second + third + "user@user.com"); 782 783 // Paste 2 addresses after existing chips. We expect the first address to be turned into 784 // a chip and the second to be left as text. 785 populateMocks(3); 786 mEditable = new SpannableStringBuilder(); 787 mEditable.append(first + second + third); 788 789 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 790 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 791 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 792 793 mEditable.append("user1, user2@user.com"); 794 view.setSelection(mEditable.length()); 795 view.handlePaste(); 796 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 797 mMockRecips.length + 1); 798 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable 799 .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1); 800 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable 801 .length(), DrawableRecipientChip.class).length, 0); 802 assertEquals(mEditable.toString(), first + second + third + "<user1>, user2@user.com"); 803 804 // Paste 2 addresses after existing chips. We expect the first address to be turned into 805 // a chip and the second to be left as text. This removes the space seperator char between 806 // addresses. 807 populateMocks(3); 808 mEditable = new SpannableStringBuilder(); 809 mEditable.append(first + second + third); 810 811 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 812 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 813 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 814 815 mEditable.append("user1,user2@user.com"); 816 view.setSelection(mEditable.length()); 817 view.handlePaste(); 818 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 819 mMockRecips.length + 1); 820 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable 821 .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1); 822 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable 823 .length(), DrawableRecipientChip.class).length, 0); 824 assertEquals(mEditable.toString(), first + second + third + "<user1>, user2@user.com"); 825 826 // Test a complete token pasted in at the end. It should be turned into a chip. 827 mEditable = new SpannableStringBuilder(); 828 mEditable.append("user1, user2@user.com,"); 829 view.setSelection(mEditable.length()); 830 view.handlePaste(); 831 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 2); 832 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable 833 .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1); 834 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable 835 .length(), DrawableRecipientChip.class).length, 1); 836 assertEquals(mEditable.toString(), "<user1>, <user2@user.com>, "); 837 } 838 839 public void testGetPastTerminators() { 840 MockRecipientEditTextView view = createViewForTesting(); 841 view.setMoreItem(createTestMoreItem()); 842 view.setChipBackground(createChipBackground()); 843 view.setChipHeight(48); 844 String test = "test"; 845 mEditable = new SpannableStringBuilder(); 846 mEditable.append(test); 847 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)), 848 test.length()); 849 850 test = "test,"; 851 mEditable = new SpannableStringBuilder(); 852 mEditable.append(test); 853 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)), 854 test.length()); 855 856 test = "test, "; 857 mEditable = new SpannableStringBuilder(); 858 mEditable.append(test); 859 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)), 860 test.length()); 861 862 test = "test;"; 863 mEditable = new SpannableStringBuilder(); 864 mEditable.append(test); 865 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)), 866 test.length()); 867 868 test = "test; "; 869 mEditable = new SpannableStringBuilder(); 870 mEditable.append(test); 871 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)), 872 test.length()); 873 } 874 875 public void testIsCompletedToken() { 876 MockRecipientEditTextView view = createViewForTesting(); 877 view.setMoreItem(createTestMoreItem()); 878 view.setChipBackground(createChipBackground()); 879 view.setChipHeight(48); 880 assertTrue(view.isCompletedToken("test;")); 881 assertTrue(view.isCompletedToken("test,")); 882 assertFalse(view.isCompletedToken("test")); 883 assertFalse(view.isCompletedToken("test ")); 884 } 885 886 public void testGetLastChip() { 887 populateMocks(3); 888 MockRecipientEditTextView view = createViewForTesting(); 889 view.setMoreItem(createTestMoreItem()); 890 view.setChipBackground(createChipBackground()); 891 view.setChipHeight(48); 892 String first = (String) mTokenizer.terminateToken("FIRST"); 893 String second = (String) mTokenizer.terminateToken("SECOND"); 894 String third = (String) mTokenizer.terminateToken("THIRD"); 895 mEditable = new SpannableStringBuilder(); 896 mEditable.append(first + second + third); 897 898 // Test replacing the first chip with a new chip. 899 int firstStart = mEditable.toString().indexOf(first); 900 int firstEnd = firstStart + first.trim().length(); 901 int secondStart = mEditable.toString().indexOf(second); 902 int secondEnd = secondStart + second.trim().length(); 903 int thirdStart = mEditable.toString().indexOf(third); 904 int thirdEnd = thirdStart + third.trim().length(); 905 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0); 906 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0); 907 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0); 908 assertEquals(view.getLastChip(), mMockRecips[mMockRecips.length - 1]); 909 mEditable.append("extra"); 910 assertEquals(view.getLastChip(), mMockRecips[mMockRecips.length - 1]); 911 } 912 913 private Drawable createChipBackground() { 914 Bitmap drawable = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); 915 return new BitmapDrawable(getContext().getResources(), drawable); 916 } 917 918 private TextView createTestMoreItem() { 919 TextView view = new TextView(getContext()); 920 view.setText("<xliff:g id='count'>%1$s</xliff:g> more..."); 921 return view; 922 } 923 924 private void populateMocks(int size) { 925 mMockEntries = new RecipientEntry[size]; 926 for (int i = 0; i < size; i++) { 927 mMockEntries[i] = RecipientEntry.constructGeneratedEntry("user", 928 "user@username.com", true); 929 } 930 mMockRecips = new DrawableRecipientChip[size]; 931 for (int i = 0; i < size; i++) { 932 mMockRecips[i] = new VisibleRecipientChip(null, mMockEntries[i]); 933 } 934 } 935 936 /** 937 * <p> 938 * Ensure the original text is always accurate, regardless of the type of email. The original 939 * text is used to determine where to display the chip span. If this test fails, it means some 940 * text that should be turned into one whole chip may behave unexpectedly. 941 * </p> 942 * <p> 943 * For example, a bug was seen where 944 * 945 * <pre> 946 * "Android User" <android@example.com> 947 * </pre> 948 * 949 * was converted to 950 * 951 * <pre> 952 * Android User [android@example.com] 953 * </pre> 954 * 955 * where text inside [] is a chip. 956 * </p> 957 */ 958 public void testCreateReplacementChipOriginalText() { 959 // Name in quotes + email address 960 testCreateReplacementChipOriginalText("\"Android User\" <android@example.com>,"); 961 // Name in quotes + email address without brackets 962 testCreateReplacementChipOriginalText("\"Android User\" android@example.com,"); 963 // Name in quotes 964 testCreateReplacementChipOriginalText("\"Android User\","); 965 // Name without quotes + email address 966 testCreateReplacementChipOriginalText("Android User <android@example.com>,"); 967 // Name without quotes 968 testCreateReplacementChipOriginalText("Android User,"); 969 // Email address 970 testCreateReplacementChipOriginalText("<android@example.com>,"); 971 // Email address without brackets 972 testCreateReplacementChipOriginalText("android@example.com,"); 973 } 974 975 private void testCreateReplacementChipOriginalText(final String email) { 976 // No trailing space 977 attemptCreateReplacementChipOriginalText(email.trim()); 978 // Trailing space 979 attemptCreateReplacementChipOriginalText(email.trim() + " "); 980 } 981 982 private void attemptCreateReplacementChipOriginalText(final String email) { 983 final RecipientEditTextView view = new RecipientEditTextView(getContext(), null); 984 985 view.setText(email); 986 view.mPendingChips.add(email); 987 988 view.createReplacementChip(0, email.length(), view.getText(), true); 989 // The "original text" should be the email without the comma or space(s) 990 assertEquals(email.replaceAll(",\\s*$", ""), 991 view.mTemporaryRecipients.get(0).getOriginalText().toString().trim()); 992 } 993} 994