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