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