blob: 6e486778482efea421c7b3a01bf2a7482c727429 [file] [log] [blame]
Mindy Pereira7cb970b2011-09-19 13:33:10 -07001/*
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
Régis Décamps219cbfb2014-06-04 14:29:54 +020019import android.annotation.TargetApi;
20import android.content.ClipData;
Mindy Pereira01162ce2011-09-20 12:21:55 -070021import android.content.Context;
Mindy Pereira97cb2592011-09-26 16:11:41 -070022import android.graphics.Bitmap;
23import android.graphics.drawable.BitmapDrawable;
24import android.graphics.drawable.Drawable;
Régis Décamps219cbfb2014-06-04 14:29:54 +020025import android.net.Uri;
Mindy Pereira7cb970b2011-09-19 13:33:10 -070026import android.test.AndroidTestCase;
Mindy Pereirafecc6f82011-09-27 10:05:05 -070027import android.test.suitebuilder.annotation.SmallTest;
Mindy Pereira01162ce2011-09-20 12:21:55 -070028import android.text.Editable;
29import android.text.SpannableStringBuilder;
30import android.text.util.Rfc822Tokenizer;
Mindy Pereirad7192502011-09-22 08:04:45 -070031import android.widget.TextView;
Mindy Pereira01162ce2011-09-20 12:21:55 -070032
Scott Kennedy194d4272013-03-06 22:06:45 -080033import com.android.ex.chips.recipientchip.DrawableRecipientChip;
Jin Cao6c2a0162014-08-17 15:00:50 -070034import com.android.ex.chips.recipientchip.ReplacementDrawableSpan;
Scott Kennedy858e0942013-10-10 11:50:01 -070035import com.android.ex.chips.recipientchip.VisibleRecipientChip;
Mindy Pereira01162ce2011-09-20 12:21:55 -070036
Scott Kennedy983c99b2013-03-22 09:42:03 -070037import java.util.regex.Pattern;
38
Mindy Pereirafecc6f82011-09-27 10:05:05 -070039@SmallTest
Mindy Pereira7cb970b2011-09-19 13:33:10 -070040public class ChipsTest extends AndroidTestCase {
Scott Kennedy194d4272013-03-06 22:06:45 -080041 private DrawableRecipientChip[] mMockRecips;
Mindy Pereira7cb970b2011-09-19 13:33:10 -070042
Mindy Pereira8eb031e2011-09-20 15:42:32 -070043 private RecipientEntry[] mMockEntries;
Mindy Pereira399bda82011-09-20 11:18:26 -070044
Mindy Pereira01162ce2011-09-20 12:21:55 -070045 private Rfc822Tokenizer mTokenizer;
46
47 private Editable mEditable;
48
Mindy Pereiraf6519d22011-11-02 13:33:18 -070049 class BaseMockRecipientEditTextView extends RecipientEditTextView {
50
51 public BaseMockRecipientEditTextView(Context context) {
52 super(context, null);
53 mTokenizer = new Rfc822Tokenizer();
54 setTokenizer(mTokenizer);
55 }
56
57 @Override
Scott Kennedy194d4272013-03-06 22:06:45 -080058 public DrawableRecipientChip[] getSortedRecipients() {
Mindy Pereiraf6519d22011-11-02 13:33:18 -070059 return mMockRecips;
60 }
61
62 @Override
63 public int getLineHeight() {
64 return 48;
65 }
66
67 @Override
68 Drawable getChipBackground(RecipientEntry contact) {
69 return createChipBackground();
70 }
71
72 @Override
73 public int getViewWidth() {
74 return 100;
75 }
76 }
77
78 class MockRecipientEditTextView extends BaseMockRecipientEditTextView {
Mindy Pereira01162ce2011-09-20 12:21:55 -070079
80 public MockRecipientEditTextView(Context context) {
Mindy Pereiraf6519d22011-11-02 13:33:18 -070081 super(context);
Mindy Pereira01162ce2011-09-20 12:21:55 -070082 mTokenizer = new Rfc822Tokenizer();
83 setTokenizer(mTokenizer);
Mindy Pereira01162ce2011-09-20 12:21:55 -070084 }
85
86 @Override
Scott Kennedy194d4272013-03-06 22:06:45 -080087 public DrawableRecipientChip[] getSortedRecipients() {
Mindy Pereira01162ce2011-09-20 12:21:55 -070088 return mMockRecips;
89 }
90
91 @Override
92 public Editable getText() {
93 return mEditable;
94 }
95
96 @Override
97 public Editable getSpannable() {
98 return mEditable;
99 }
Mindy Pereirad7192502011-09-22 08:04:45 -0700100
101 @Override
102 public int getLineHeight() {
103 return 48;
104 }
Mindy Pereira97cb2592011-09-26 16:11:41 -0700105
Mindy Pereira20c9d622011-10-12 13:18:04 -0700106 @Override
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700107 Drawable getChipBackground(RecipientEntry contact) {
Mindy Pereira97cb2592011-09-26 16:11:41 -0700108 return createChipBackground();
109 }
Mindy Pereira20c9d622011-10-12 13:18:04 -0700110
111 @Override
112 public int length() {
113 return mEditable != null ? mEditable.length() : 0;
114 }
115
116 @Override
117 public String toString() {
118 return mEditable != null ? mEditable.toString() : "";
119 }
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700120
121 @Override
122 public int getViewWidth() {
123 return 100;
124 }
Mindy Pereira01162ce2011-09-20 12:21:55 -0700125 }
126
Mindy Pereirabdf58b62012-05-02 14:16:50 -0700127 private class TestBaseRecipientAdapter extends BaseRecipientAdapter {
Scott Kennedy983c99b2013-03-22 09:42:03 -0700128 public TestBaseRecipientAdapter(final Context context) {
Mindy Pereirabdf58b62012-05-02 14:16:50 -0700129 super(context);
130 }
Scott Kennedy983c99b2013-03-22 09:42:03 -0700131
132 public TestBaseRecipientAdapter(final Context context, final int preferredMaxResultCount,
133 final int queryMode) {
134 super(context, preferredMaxResultCount, queryMode);
135 }
Mindy Pereirabdf58b62012-05-02 14:16:50 -0700136 }
137
Mindy Pereira01162ce2011-09-20 12:21:55 -0700138 private MockRecipientEditTextView createViewForTesting() {
139 mEditable = new SpannableStringBuilder();
140 MockRecipientEditTextView view = new MockRecipientEditTextView(getContext());
Mindy Pereirabdf58b62012-05-02 14:16:50 -0700141 view.setAdapter(new TestBaseRecipientAdapter(getContext()));
Mindy Pereira01162ce2011-09-20 12:21:55 -0700142 return view;
143 }
144
145 public void testCreateDisplayText() {
146 RecipientEditTextView view = createViewForTesting();
147 RecipientEntry entry = RecipientEntry.constructGeneratedEntry("User Name, Jr",
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800148 "user@username.com", true);
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700149 String testAddress = view.createAddressText(entry);
150 String testDisplay = view.createChipDisplayText(entry);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700151 assertEquals("Expected a properly formatted RFC email address",
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700152 "\"User Name, Jr\" <user@username.com>, ", testAddress);
153 assertEquals("Expected a displayable name", "User Name, Jr", testDisplay);
154
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800155 RecipientEntry alreadyFormatted =
156 RecipientEntry.constructFakeEntry("user@username.com, ", true);
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700157 testAddress = view.createAddressText(alreadyFormatted);
158 testDisplay = view.createChipDisplayText(alreadyFormatted);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700159 assertEquals("Expected a properly formatted RFC email address", "<user@username.com>, ",
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700160 testAddress);
161 assertEquals("Expected a displayable name", "user@username.com", testDisplay);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700162
163 RecipientEntry alreadyFormattedNoSpace = RecipientEntry
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800164 .constructFakeEntry("user@username.com,", true);
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700165 testAddress = view.createAddressText(alreadyFormattedNoSpace);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700166 assertEquals("Expected a properly formatted RFC email address", "<user@username.com>, ",
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700167 testAddress);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700168
169 RecipientEntry alreadyNamed = RecipientEntry.constructGeneratedEntry("User Name",
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800170 "\"User Name, Jr\" <user@username.com>", true);
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700171 testAddress = view.createAddressText(alreadyNamed);
172 testDisplay = view.createChipDisplayText(alreadyNamed);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700173 assertEquals(
174 "Expected address that used the name not the excess address name",
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700175 "User Name <user@username.com>, ", testAddress);
176 assertEquals("Expected a displayable name", "User Name", testDisplay);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700177 }
178
179 public void testSanitizeBetween() {
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700180 // First, add 2 chips and then make sure we remove
181 // the extra content between them correctly.
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700182 populateMocks(2);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700183 MockRecipientEditTextView view = createViewForTesting();
184 String first = (String) mTokenizer.terminateToken("FIRST");
185 String second = (String) mTokenizer.terminateToken("SECOND");
186 String extra = "EXTRA";
Mindy Pereirad7192502011-09-22 08:04:45 -0700187 mEditable = new SpannableStringBuilder();
Mindy Pereira01162ce2011-09-20 12:21:55 -0700188 mEditable.append(first + extra + second);
189 int firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700190 int firstEnd = firstStart + first.trim().length();
Mindy Pereira01162ce2011-09-20 12:21:55 -0700191 int secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700192 int secondEnd = secondStart + second.trim().length();
Mindy Pereira01162ce2011-09-20 12:21:55 -0700193 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], firstStart, firstEnd, 0);
194 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], secondStart, secondEnd, 0);
195 view.sanitizeBetween();
196 String editableString = mEditable.toString();
197 assertEquals(editableString.indexOf(extra), -1);
198 assertEquals(editableString.indexOf(first), firstStart);
199 assertEquals(editableString.indexOf(second), secondStart - extra.length());
200 assertEquals(editableString, (first + second));
201
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700202 // Add 1 chip and make sure that we remove the extra stuff before it correctly.
Mindy Pereira01162ce2011-09-20 12:21:55 -0700203 mEditable = new SpannableStringBuilder();
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700204 populateMocks(1);
205 mEditable.append(extra);
Mindy Pereira01162ce2011-09-20 12:21:55 -0700206 mEditable.append(first);
207 firstStart = mEditable.toString().indexOf(first);
208 firstEnd = firstStart + first.length();
209 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], firstStart, firstEnd, 0);
210 view.sanitizeBetween();
211 assertEquals(mEditable.toString(), first);
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700212 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), firstStart
213 - extra.length());
214 }
215
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700216 public void testSanitizeEnd() {
217 // First, add 2 chips and then make sure we remove
218 // the extra content between them correctly.
219 populateMocks(2);
220 MockRecipientEditTextView view = createViewForTesting();
221 String first = (String) mTokenizer.terminateToken("FIRST");
222 String second = (String) mTokenizer.terminateToken("SECOND");
223 String extra = "EXTRA";
224 mEditable = new SpannableStringBuilder();
225 mEditable.append(first + second);
226 int firstStart = mEditable.toString().indexOf(first);
227 int firstEnd = firstStart + first.trim().length();
228 int secondStart = mEditable.toString().indexOf(second);
229 int secondEnd = secondStart + second.trim().length();
230 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], firstStart, firstEnd, 0);
231 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], secondStart, secondEnd, 0);
232 view.sanitizeEnd();
233 String editableString = mEditable.toString();
234 assertEquals(editableString.indexOf(extra), -1);
235 assertEquals(editableString.indexOf(first), firstStart);
236 assertEquals(editableString.indexOf(second), secondStart);
237 assertEquals(editableString, (first + second));
238 mEditable.append(extra);
239 editableString = mEditable.toString();
240 assertEquals(mEditable.toString(), (first + second + extra));
241 view.sanitizeEnd();
242 assertEquals(mEditable.toString(), (first + second));
243 }
244
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700245 public void testMoreChipPlainText() {
246 MockRecipientEditTextView view = createViewForTesting();
247 view.setMoreItem(createTestMoreItem());
248 String first = (String) mTokenizer.terminateToken("FIRST");
249 String second = (String) mTokenizer.terminateToken("SECOND");
250 String third = (String) mTokenizer.terminateToken("THIRD");
251 mEditable = new SpannableStringBuilder();
252 mEditable.append(first+second+third);
253 int thirdStart = mEditable.toString().indexOf(third);
254 int thirdEnd = thirdStart + third.trim().length();
255 view.createMoreChipPlainText();
Jin Cao6c2a0162014-08-17 15:00:50 -0700256 ReplacementDrawableSpan moreChip = view.getMoreChip();
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700257 assertEquals(mEditable.getSpanStart(moreChip), thirdStart);
258 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1);
259 }
260
261 public void testCountTokens() {
262 MockRecipientEditTextView view = createViewForTesting();
263 view.setMoreItem(createTestMoreItem());
264 String first = (String) mTokenizer.terminateToken("FIRST");
265 String second = (String) mTokenizer.terminateToken("SECOND");
266 String third = (String) mTokenizer.terminateToken("THIRD");
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800267 String fourth = "FOURTH,";
268 String fifth = "FIFTH,";
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700269 mEditable = new SpannableStringBuilder();
270 mEditable.append(first+second+third+fourth+fifth);
271 assertEquals(view.countTokens(mEditable), 5);
272 }
273
274 public void testTooManyRecips() {
275 BaseMockRecipientEditTextView view = new BaseMockRecipientEditTextView(getContext());
276 view.setMoreItem(createTestMoreItem());
277 for (int i = 0; i < 100; i++) {
278 view.append(mTokenizer.terminateToken(i + ""));
279 }
280 assertEquals(view.countTokens(view.getText()), 100);
281 view.handlePendingChips();
282 view.createMoreChip();
Jin Cao6c2a0162014-08-17 15:00:50 -0700283 ReplacementDrawableSpan moreChip = view.getMoreChip();
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700284 // We show 2 chips then place a more chip.
285 int secondStart = view.getText().toString().indexOf(
286 (String) mTokenizer.terminateToken(RecipientEditTextView.CHIP_LIMIT + ""));
287 assertEquals(view.getText().getSpanStart(moreChip), secondStart);
288 assertEquals(view.getText().getSpanEnd(moreChip), view.length());
289 assertEquals(view.getSortedRecipients(), null);
290 }
291
Mindy Pereirad7192502011-09-22 08:04:45 -0700292 public void testMoreChip() {
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700293 // Add 3 chips: this is the trigger point at which the more chip will be created.
294 // Test that adding the chips and then creating and removing the more chip, as if
295 // the user were focusing/ removing focus from the chips field.
Mindy Pereirad7192502011-09-22 08:04:45 -0700296 populateMocks(3);
297 MockRecipientEditTextView view = createViewForTesting();
298 view.setMoreItem(createTestMoreItem());
299 String first = (String) mTokenizer.terminateToken("FIRST");
300 String second = (String) mTokenizer.terminateToken("SECOND");
301 String third = (String) mTokenizer.terminateToken("THIRD");
302 mEditable = new SpannableStringBuilder();
303 mEditable.append(first+second+third);
304
305 int firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700306 int firstEnd = firstStart + first.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700307 int secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700308 int secondEnd = secondStart + second.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700309 int thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700310 int thirdEnd = thirdStart + third.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700311 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
312 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
313 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
314
315 view.createMoreChip();
316 assertEquals(mEditable.toString(), first+second+third);
317 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
318 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
319 // Find the more chip.
Jin Cao6c2a0162014-08-17 15:00:50 -0700320 ReplacementDrawableSpan moreChip = view.getMoreChip();
Mindy Pereirad7192502011-09-22 08:04:45 -0700321 assertEquals(mEditable.getSpanStart(moreChip), thirdStart);
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700322 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1);
Mindy Pereirad7192502011-09-22 08:04:45 -0700323
324 view.removeMoreChip();
325 assertEquals(mEditable.toString(), first+second+third);
326 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
327 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
328 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
329 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdStart);
330 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdEnd);
331 moreChip = view.getMoreChip();
332 assertEquals(mEditable.getSpanStart(moreChip), -1);
333
334 // Rinse and repeat, just in case!
335 view.createMoreChip();
336 assertEquals(mEditable.toString(), first+second+third);
337 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
338 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
339 // Find the more chip.
340 moreChip = view.getMoreChip();
341 assertEquals(mEditable.getSpanStart(moreChip), thirdStart);
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700342 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1);
Mindy Pereirad7192502011-09-22 08:04:45 -0700343
344 view.removeMoreChip();
345 assertEquals(mEditable.toString(), first+second+third);
346 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
347 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
348 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
349 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdStart);
350 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdEnd);
351 moreChip = view.getMoreChip();
352 assertEquals(mEditable.getSpanStart(moreChip), -1);
353 }
354
355 public void testMoreChipLotsOfUsers() {
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700356 // Test adding and removing the more chip in the case where we have a lot of users.
Mindy Pereirad7192502011-09-22 08:04:45 -0700357 populateMocks(10);
358 MockRecipientEditTextView view = createViewForTesting();
359 view.setMoreItem(createTestMoreItem());
360 String first = (String) mTokenizer.terminateToken("FIRST");
361 String second = (String) mTokenizer.terminateToken("SECOND");
362 String third = (String) mTokenizer.terminateToken("THIRD");
363 String fourth = (String) mTokenizer.terminateToken("FOURTH");
364 String fifth = (String) mTokenizer.terminateToken("FIFTH");
365 String sixth = (String) mTokenizer.terminateToken("SIXTH");
366 String seventh = (String) mTokenizer.terminateToken("SEVENTH");
367 String eigth = (String) mTokenizer.terminateToken("EIGHTH");
368 String ninth = (String) mTokenizer.terminateToken("NINTH");
369 String tenth = (String) mTokenizer.terminateToken("TENTH");
370 mEditable = new SpannableStringBuilder();
371 mEditable.append(first+second+third+fourth+fifth+sixth+seventh+eigth+ninth+tenth);
372
373 int firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700374 int firstEnd = firstStart + first.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700375 int secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700376 int secondEnd = secondStart + second.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700377 int thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700378 int thirdEnd = thirdStart + third.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700379 int fourthStart = mEditable.toString().indexOf(fourth);
Mindy Pereira62397a52011-10-03 13:46:43 -0700380 int fourthEnd = fourthStart + fourth.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700381 int fifthStart = mEditable.toString().indexOf(fifth);
Mindy Pereira62397a52011-10-03 13:46:43 -0700382 int fifthEnd = fifthStart + fifth.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700383 int sixthStart = mEditable.toString().indexOf(sixth);
Mindy Pereira62397a52011-10-03 13:46:43 -0700384 int sixthEnd = sixthStart + sixth.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700385 int seventhStart = mEditable.toString().indexOf(seventh);
Mindy Pereira62397a52011-10-03 13:46:43 -0700386 int seventhEnd = seventhStart + seventh.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700387 int eighthStart = mEditable.toString().indexOf(eigth);
Mindy Pereira62397a52011-10-03 13:46:43 -0700388 int eighthEnd = eighthStart + eigth.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700389 int ninthStart = mEditable.toString().indexOf(ninth);
Mindy Pereira62397a52011-10-03 13:46:43 -0700390 int ninthEnd = ninthStart + ninth.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700391 int tenthStart = mEditable.toString().indexOf(tenth);
Mindy Pereira62397a52011-10-03 13:46:43 -0700392 int tenthEnd = tenthStart + tenth.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700393 mEditable.setSpan(mMockRecips[mMockRecips.length - 10], firstStart, firstEnd, 0);
394 mEditable.setSpan(mMockRecips[mMockRecips.length - 9], secondStart, secondEnd, 0);
395 mEditable.setSpan(mMockRecips[mMockRecips.length - 8], thirdStart, thirdEnd, 0);
396 mEditable.setSpan(mMockRecips[mMockRecips.length - 7], fourthStart, fourthEnd, 0);
397 mEditable.setSpan(mMockRecips[mMockRecips.length - 6], fifthStart, fifthEnd, 0);
398 mEditable.setSpan(mMockRecips[mMockRecips.length - 5], sixthStart, sixthEnd, 0);
399 mEditable.setSpan(mMockRecips[mMockRecips.length - 4], seventhStart, seventhEnd, 0);
400 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], eighthStart, eighthEnd, 0);
401 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], ninthStart, ninthEnd, 0);
402 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], tenthStart, tenthEnd, 0);
403
404 view.createMoreChip();
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 // Find the more chip.
Jin Cao6c2a0162014-08-17 15:00:50 -0700410 ReplacementDrawableSpan moreChip = view.getMoreChip();
Mindy Pereirad7192502011-09-22 08:04:45 -0700411 assertEquals(mEditable.getSpanStart(moreChip), thirdStart);
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700412 assertEquals(mEditable.getSpanEnd(moreChip), tenthEnd + 1);
Mindy Pereirad7192502011-09-22 08:04:45 -0700413
414 view.removeMoreChip();
415 assertEquals(mEditable.toString(), first + second + third + fourth + fifth + sixth
416 + seventh + eigth + ninth + tenth);
417 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 10]), firstStart);
418 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 9]), secondStart);
419
420 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 8]), thirdStart);
421 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 7]), fourthStart);
422 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 6]), fifthStart);
423 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 5]), sixthStart);
424 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 4]), seventhStart);
425 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), eighthStart);
426 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), ninthStart);
427 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), tenthStart);
428 moreChip = view.getMoreChip();
429 assertEquals(mEditable.getSpanStart(moreChip), -1);
430
431 }
432
433 public void testMoreChipSpecialChars() {
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700434 // Make sure the more chip correctly handles extra tokenizer characters in the middle
435 // of chip text.
Mindy Pereirad7192502011-09-22 08:04:45 -0700436 populateMocks(3);
437 MockRecipientEditTextView view = createViewForTesting();
438 view.setMoreItem(createTestMoreItem());
439 String first = (String) mTokenizer.terminateToken("FI,RST");
440 String second = (String) mTokenizer.terminateToken("SE,COND");
441 String third = (String) mTokenizer.terminateToken("THI,RD");
442 mEditable = new SpannableStringBuilder();
443 mEditable.append(first+second+third);
444
445 int firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700446 int firstEnd = firstStart + first.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700447 int secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700448 int secondEnd = secondStart + second.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700449 int thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700450 int thirdEnd = thirdStart + third.trim().length();
Mindy Pereirad7192502011-09-22 08:04:45 -0700451 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
452 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
453 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
454
455 view.createMoreChip();
456 assertEquals(mEditable.toString(), first+second+third);
457 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
458 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
459 // Find the more chip.
Jin Cao6c2a0162014-08-17 15:00:50 -0700460 ReplacementDrawableSpan moreChip = view.getMoreChip();
Mindy Pereirad7192502011-09-22 08:04:45 -0700461 assertEquals(mEditable.getSpanStart(moreChip), thirdStart);
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700462 assertEquals(mEditable.getSpanEnd(moreChip), thirdEnd + 1);
Mindy Pereirad7192502011-09-22 08:04:45 -0700463
464 view.removeMoreChip();
465 assertEquals(mEditable.toString(), first+second+third);
466 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
467 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
468 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
469 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdStart);
470 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdEnd);
471 moreChip = view.getMoreChip();
472 assertEquals(mEditable.getSpanStart(moreChip), -1);
473 }
474
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700475 public void testMoreChipDupes() {
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700476 // Make sure the more chip is correctly added and removed when we have duplicate chips.
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700477 populateMocks(4);
478 MockRecipientEditTextView view = createViewForTesting();
479 view.setMoreItem(createTestMoreItem());
480 String first = (String) mTokenizer.terminateToken("FIRST");
481 String second = (String) mTokenizer.terminateToken("SECOND");
482 String third = (String) mTokenizer.terminateToken("THIRD");
483 mEditable = new SpannableStringBuilder();
484 mEditable.append(first+second+third+third);
485
486 int firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700487 int firstEnd = firstStart + first.trim().length();
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700488 int secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700489 int secondEnd = secondStart + second.trim().length();
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700490 int thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700491 int thirdEnd = thirdStart + third.trim().length();
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700492 int thirdNextStart = mEditable.toString().indexOf(third, thirdEnd);
Mindy Pereira62397a52011-10-03 13:46:43 -0700493 int thirdNextEnd = thirdNextStart + third.trim().length();
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700494 mEditable.setSpan(mMockRecips[mMockRecips.length - 4], firstStart, firstEnd, 0);
495 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], secondStart, secondEnd, 0);
496 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], thirdStart, thirdEnd, 0);
497 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdNextStart, thirdNextEnd, 0);
498
499 view.createMoreChip();
500 assertEquals(mEditable.toString(), first+second+third+third);
501 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 4]), firstStart);
502 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), secondStart);
503 // Find the more chip.
Jin Cao6c2a0162014-08-17 15:00:50 -0700504 ReplacementDrawableSpan moreChip = view.getMoreChip();
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700505 assertEquals(mEditable.getSpanStart(moreChip), thirdStart);
Mindy Pereiraf6519d22011-11-02 13:33:18 -0700506 assertEquals(mEditable.getSpanEnd(moreChip), thirdNextEnd + 1);
Mindy Pereiradfeb97f2011-09-23 10:50:47 -0700507
508 view.removeMoreChip();
509 assertEquals(mEditable.toString(), first+second+third+third);
510 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 4]), firstStart);
511 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 4]), firstEnd);
512 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), secondStart);
513 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), thirdStart);
514 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), thirdEnd);
515 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), thirdNextStart);
516 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), thirdNextEnd);
517 moreChip = view.getMoreChip();
518 assertEquals(mEditable.getSpanStart(moreChip), -1);
519 }
520
Mindy Pereira97cb2592011-09-26 16:11:41 -0700521 public void testRemoveChip() {
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700522 // Create 3 chips to start and test removing chips in various postions.
Mindy Pereira97cb2592011-09-26 16:11:41 -0700523 populateMocks(3);
524 MockRecipientEditTextView view = createViewForTesting();
525 view.setMoreItem(createTestMoreItem());
526 String first = (String) mTokenizer.terminateToken("FIRST");
527 String second = (String) mTokenizer.terminateToken("SECOND");
528 String third = (String) mTokenizer.terminateToken("THIRD");
529 mEditable = new SpannableStringBuilder();
530 mEditable.append(first + second + third);
531
532 int firstStart = mEditable.toString().indexOf(first);
533 int firstEnd = firstStart + first.length();
534 int secondStart = mEditable.toString().indexOf(second);
535 int secondEnd = secondStart + second.length();
536 int thirdStart = mEditable.toString().indexOf(third);
537 int thirdEnd = thirdStart + third.length();
538 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
539 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
540 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
541 assertEquals(mEditable.toString(), first + second + third);
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700542 // Test removing the middle chip.
Mindy Pereira97cb2592011-09-26 16:11:41 -0700543 view.removeChip(mMockRecips[mMockRecips.length - 2]);
544 assertEquals(mEditable.toString(), first + third);
545 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
546 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
547 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), -1);
548 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), -1);
549 int newThirdStart = mEditable.toString().indexOf(third);
550 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), newThirdStart);
551 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), newThirdStart
552 + third.length());
553
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700554 // Test removing the first chip.
Mindy Pereira97cb2592011-09-26 16:11:41 -0700555 populateMocks(3);
556 view = createViewForTesting();
557 view.setMoreItem(createTestMoreItem());
558 mEditable = new SpannableStringBuilder();
559 mEditable.append(first + second + third);
560
561 firstStart = mEditable.toString().indexOf(first);
562 firstEnd = firstStart + first.length();
563 secondStart = mEditable.toString().indexOf(second);
564 secondEnd = secondStart + second.length();
565 thirdStart = mEditable.toString().indexOf(third);
566 thirdEnd = thirdStart + third.length();
567 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
568 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
569 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
570 assertEquals(mEditable.toString(), first + second + third);
571 view.removeChip(mMockRecips[mMockRecips.length - 3]);
572 assertEquals(mEditable.toString(), second + third);
573 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), -1);
574 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), -1);
575 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), 0);
576 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), second.length());
577 newThirdStart = mEditable.toString().indexOf(third);
578 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), newThirdStart);
579 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), newThirdStart
580 + third.length());
581
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700582 // Test removing the last chip.
Mindy Pereira97cb2592011-09-26 16:11:41 -0700583 populateMocks(3);
584 view = createViewForTesting();
585 view.setMoreItem(createTestMoreItem());
586 mEditable = new SpannableStringBuilder();
587 mEditable.append(first + second + third);
588
589 firstStart = mEditable.toString().indexOf(first);
590 firstEnd = firstStart + first.length();
591 secondStart = mEditable.toString().indexOf(second);
592 secondEnd = secondStart + second.length();
593 thirdStart = mEditable.toString().indexOf(third);
594 thirdEnd = thirdStart + third.length();
595 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
596 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
597 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
598 assertEquals(mEditable.toString(), first + second + third);
599 view.removeChip(mMockRecips[mMockRecips.length - 1]);
600 assertEquals(mEditable.toString(), first + second);
601 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
602 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
603 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
604 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), secondEnd);
605 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), -1);
606 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), -1);
607 }
608
609 public void testReplaceChip() {
610 populateMocks(3);
611 MockRecipientEditTextView view = createViewForTesting();
612 view.setMoreItem(createTestMoreItem());
613 view.setChipBackground(createChipBackground());
614 view.setChipHeight(48);
615 String first = (String) mTokenizer.terminateToken("FIRST");
616 String second = (String) mTokenizer.terminateToken("SECOND");
617 String third = (String) mTokenizer.terminateToken("THIRD");
618 mEditable = new SpannableStringBuilder();
619 mEditable.append(first + second + third);
620
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700621 // Test replacing the first chip with a new chip.
Mindy Pereira97cb2592011-09-26 16:11:41 -0700622 int firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700623 int firstEnd = firstStart + first.trim().length();
Mindy Pereira97cb2592011-09-26 16:11:41 -0700624 int secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700625 int secondEnd = secondStart + second.trim().length();
Mindy Pereira97cb2592011-09-26 16:11:41 -0700626 int thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700627 int thirdEnd = thirdStart + third.trim().length();
Mindy Pereira97cb2592011-09-26 16:11:41 -0700628 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
629 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
630 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
631 assertEquals(mEditable.toString(), first + second + third);
632 view.replaceChip(mMockRecips[mMockRecips.length - 3], RecipientEntry
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800633 .constructGeneratedEntry("replacement", "replacement@replacement.com", true));
Mindy Pereira97cb2592011-09-26 16:11:41 -0700634 assertEquals(mEditable.toString(), mTokenizer
635 .terminateToken("replacement <replacement@replacement.com>")
636 + second + third);
637 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), -1);
638 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), -1);
639 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), mEditable
640 .toString().indexOf(second));
641 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), mEditable
642 .toString().indexOf(second)
Mindy Pereira62397a52011-10-03 13:46:43 -0700643 + second.trim().length());
Mindy Pereira97cb2592011-09-26 16:11:41 -0700644 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), mEditable
645 .toString().indexOf(third));
646 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), mEditable
647 .toString().indexOf(third)
Mindy Pereira62397a52011-10-03 13:46:43 -0700648 + third.trim().length());
Scott Kennedy194d4272013-03-06 22:06:45 -0800649 DrawableRecipientChip[] spans =
650 mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class);
Mindy Pereira97cb2592011-09-26 16:11:41 -0700651 assertEquals(spans.length, 3);
652 spans = mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800653 .getSpans(0, mEditable.toString().indexOf(second) - 1, DrawableRecipientChip.class);
Mindy Pereira97cb2592011-09-26 16:11:41 -0700654 assertEquals((String) spans[0].getDisplay(), "replacement");
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700655
656
657 // Test replacing the middle chip with a new chip.
658 mEditable = new SpannableStringBuilder();
659 mEditable.append(first + second + third);
660 firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700661 firstEnd = firstStart + first.trim().length();
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700662 secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700663 secondEnd = secondStart + second.trim().length();
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700664 thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700665 thirdEnd = thirdStart + third.trim().length();
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700666 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
667 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
668 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
669 assertEquals(mEditable.toString(), first + second + third);
670 view.replaceChip(mMockRecips[mMockRecips.length - 2], RecipientEntry
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800671 .constructGeneratedEntry("replacement", "replacement@replacement.com", true));
Mindy Pereira62397a52011-10-03 13:46:43 -0700672 assertEquals(mEditable.toString(), first + mTokenizer
673 .terminateToken("replacement <replacement@replacement.com>") + third);
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700674 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
675 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
676 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), -1);
677 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), -1);
678 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), mEditable
679 .toString().indexOf(third));
680 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), mEditable
681 .toString().indexOf(third)
Mindy Pereira62397a52011-10-03 13:46:43 -0700682 + third.trim().length());
Scott Kennedy194d4272013-03-06 22:06:45 -0800683 spans = mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class);
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700684 assertEquals(spans.length, 3);
Scott Kennedy194d4272013-03-06 22:06:45 -0800685 spans = mEditable.getSpans(firstEnd, mEditable.toString().indexOf(third) - 1,
686 DrawableRecipientChip.class);
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700687 assertEquals((String) spans[0].getDisplay(), "replacement");
688
689
690 // Test replacing the last chip with a new chip.
691 mEditable = new SpannableStringBuilder();
692 mEditable.append(first + second + third);
693 firstStart = mEditable.toString().indexOf(first);
Mindy Pereira62397a52011-10-03 13:46:43 -0700694 firstEnd = firstStart + first.trim().length();
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700695 secondStart = mEditable.toString().indexOf(second);
Mindy Pereira62397a52011-10-03 13:46:43 -0700696 secondEnd = secondStart + second.trim().length();
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700697 thirdStart = mEditable.toString().indexOf(third);
Mindy Pereira62397a52011-10-03 13:46:43 -0700698 thirdEnd = thirdStart + third.trim().length();
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700699 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
700 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
701 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
702 assertEquals(mEditable.toString(), first + second + third);
703 view.replaceChip(mMockRecips[mMockRecips.length - 1], RecipientEntry
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800704 .constructGeneratedEntry("replacement", "replacement@replacement.com", true));
Mindy Pereira62397a52011-10-03 13:46:43 -0700705 assertEquals(mEditable.toString(), first + second + mTokenizer
706 .terminateToken("replacement <replacement@replacement.com>"));
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700707 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 3]), firstStart);
708 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 3]), firstEnd);
709 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 2]), secondStart);
710 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 2]), secondEnd);
711 assertEquals(mEditable.getSpanStart(mMockRecips[mMockRecips.length - 1]), -1);
712 assertEquals(mEditable.getSpanEnd(mMockRecips[mMockRecips.length - 1]), -1);
Scott Kennedy194d4272013-03-06 22:06:45 -0800713 spans = mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class);
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700714 assertEquals(spans.length, 3);
715 spans = mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800716 .getSpans(secondEnd, mEditable.length(), DrawableRecipientChip.class);
Mindy Pereirafecc6f82011-09-27 10:05:05 -0700717 assertEquals((String) spans[0].getDisplay(), "replacement");
Mindy Pereira97cb2592011-09-26 16:11:41 -0700718 }
719
Mindy Pereira20c9d622011-10-12 13:18:04 -0700720 public void testHandlePaste() {
721 // Start with an empty edit field.
722 // Add an address; the text should be left as is.
723 MockRecipientEditTextView view = createViewForTesting();
724 view.setMoreItem(createTestMoreItem());
725 view.setChipBackground(createChipBackground());
726 view.setChipHeight(48);
727 mEditable = new SpannableStringBuilder();
728 mEditable.append("user@user.com");
729 view.setSelection(mEditable.length());
730 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800731 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 0);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700732 assertEquals(mEditable.toString(), "user@user.com");
733
734 // Test adding a single address to an empty chips field with a space at
735 // the end of it. The address should stay as text.
736 mEditable = new SpannableStringBuilder();
737 String tokenizedUser = "user@user.com" + " ";
738 mEditable.append(tokenizedUser);
739 view.setSelection(mEditable.length());
740 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800741 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 0);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700742 assertEquals(mEditable.toString(), tokenizedUser);
743
744 // Test adding a single address to an empty chips field with a semicolon at
745 // the end of it. The address should become a chip
746 mEditable = new SpannableStringBuilder();
747 tokenizedUser = "user@user.com;";
748 mEditable.append(tokenizedUser);
749 view.setSelection(mEditable.length());
750 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800751 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700752
753 // Test adding 2 address to an empty chips field. The second to last
754 // address should become a chip and the last address should stay as
755 // text.
756 mEditable = new SpannableStringBuilder();
757 mEditable.append("user1,user2@user.com");
758 view.setSelection(mEditable.length());
759 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800760 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700761 assertEquals(mEditable.getSpans(0, mEditable.toString().indexOf("user2@user.com"),
Scott Kennedy194d4272013-03-06 22:06:45 -0800762 DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700763 assertEquals(mEditable.toString(), "<user1>, user2@user.com");
764
765 // Test adding a single address to the end of existing chips. The existing
766 // chips should remain, and the last address should stay as text.
767 populateMocks(3);
768 String first = (String) mTokenizer.terminateToken("FIRST");
769 String second = (String) mTokenizer.terminateToken("SECOND");
770 String third = (String) mTokenizer.terminateToken("THIRD");
771 mEditable = new SpannableStringBuilder();
772 mEditable.append(first + second + third);
773 view.setSelection(mEditable.length());
774 int firstStart = mEditable.toString().indexOf(first);
775 int firstEnd = firstStart + first.trim().length();
776 int secondStart = mEditable.toString().indexOf(second);
777 int secondEnd = secondStart + second.trim().length();
778 int thirdStart = mEditable.toString().indexOf(third);
779 int thirdEnd = thirdStart + third.trim().length();
780 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
781 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
782 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
783
784 mEditable.append("user@user.com");
785 view.setSelection(mEditable.length());
786 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800787 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length,
Mindy Pereira20c9d622011-10-12 13:18:04 -0700788 mMockRecips.length);
789 assertEquals(mEditable.toString(), first + second + third + "user@user.com");
790
791 // Paste 2 addresses after existing chips. We expect the first address to be turned into
792 // a chip and the second to be left as text.
793 populateMocks(3);
794 mEditable = new SpannableStringBuilder();
795 mEditable.append(first + second + third);
796
797 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
798 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
799 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
800
801 mEditable.append("user1, user2@user.com");
802 view.setSelection(mEditable.length());
803 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800804 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length,
Mindy Pereira20c9d622011-10-12 13:18:04 -0700805 mMockRecips.length + 1);
806 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800807 .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700808 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800809 .length(), DrawableRecipientChip.class).length, 0);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700810 assertEquals(mEditable.toString(), first + second + third + "<user1>, user2@user.com");
811
812 // Paste 2 addresses after existing chips. We expect the first address to be turned into
813 // a chip and the second to be left as text. This removes the space seperator char between
814 // addresses.
815 populateMocks(3);
816 mEditable = new SpannableStringBuilder();
817 mEditable.append(first + second + third);
818
819 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
820 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
821 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
822
823 mEditable.append("user1,user2@user.com");
824 view.setSelection(mEditable.length());
825 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800826 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length,
Mindy Pereira20c9d622011-10-12 13:18:04 -0700827 mMockRecips.length + 1);
828 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800829 .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700830 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800831 .length(), DrawableRecipientChip.class).length, 0);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700832 assertEquals(mEditable.toString(), first + second + third + "<user1>, user2@user.com");
833
834 // Test a complete token pasted in at the end. It should be turned into a chip.
835 mEditable = new SpannableStringBuilder();
836 mEditable.append("user1, user2@user.com,");
837 view.setSelection(mEditable.length());
838 view.handlePaste();
Scott Kennedy194d4272013-03-06 22:06:45 -0800839 assertEquals(mEditable.getSpans(0, mEditable.length(), DrawableRecipientChip.class).length, 2);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700840 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("<user1>"), mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800841 .toString().indexOf("user2@user.com") - 1, DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700842 assertEquals(mEditable.getSpans(mEditable.toString().indexOf("user2@user.com"), mEditable
Scott Kennedy194d4272013-03-06 22:06:45 -0800843 .length(), DrawableRecipientChip.class).length, 1);
Mindy Pereira20c9d622011-10-12 13:18:04 -0700844 assertEquals(mEditable.toString(), "<user1>, <user2@user.com>, ");
845 }
846
Régis Décamps219cbfb2014-06-04 14:29:54 +0200847 @TargetApi(16)
848 public void testHandlePasteClip() {
849 MockRecipientEditTextView view = createViewForTesting();
850
851 ClipData clipData = null;
852 mEditable = new SpannableStringBuilder();
853 view.handlePasteClip(clipData);
854 assertEquals("", view.getText().toString());
855
856 clipData = ClipData.newPlainText("user label", "<foo@example.com>");
857 mEditable = new SpannableStringBuilder();
858 view.handlePasteClip(clipData);
859 assertEquals("<foo@example.com>", view.getText().toString());
860
861 clipData = ClipData.newHtmlText("user label",
862 "<bar@example.com>", "<a href=\"mailto:bar@example.com\">email</a>");
863 mEditable = new SpannableStringBuilder();
864 view.handlePasteClip(clipData);
865 assertEquals("<bar@example.com>", view.getText().toString());
866
867 ClipData.Item clipImageData = new ClipData.Item(Uri.parse("content://my/image"));
868 clipData = new ClipData("user label", new String[]{"image/jpeg"}, clipImageData);
869 mEditable = new SpannableStringBuilder();
870 view.handlePasteClip(clipData);
871 assertEquals("", view.getText().toString()
872 );
873 }
874
Mindy Pereira20c9d622011-10-12 13:18:04 -0700875 public void testGetPastTerminators() {
876 MockRecipientEditTextView view = createViewForTesting();
877 view.setMoreItem(createTestMoreItem());
878 view.setChipBackground(createChipBackground());
879 view.setChipHeight(48);
880 String test = "test";
881 mEditable = new SpannableStringBuilder();
882 mEditable.append(test);
883 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)),
884 test.length());
885
886 test = "test,";
887 mEditable = new SpannableStringBuilder();
888 mEditable.append(test);
889 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)),
890 test.length());
891
892 test = "test, ";
893 mEditable = new SpannableStringBuilder();
894 mEditable.append(test);
895 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)),
896 test.length());
897
898 test = "test;";
899 mEditable = new SpannableStringBuilder();
900 mEditable.append(test);
901 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)),
902 test.length());
903
904 test = "test; ";
905 mEditable = new SpannableStringBuilder();
906 mEditable.append(test);
907 assertEquals(view.movePastTerminators(mTokenizer.findTokenEnd(mEditable.toString(), 0)),
908 test.length());
909 }
910
911 public void testIsCompletedToken() {
912 MockRecipientEditTextView view = createViewForTesting();
913 view.setMoreItem(createTestMoreItem());
914 view.setChipBackground(createChipBackground());
915 view.setChipHeight(48);
916 assertTrue(view.isCompletedToken("test;"));
917 assertTrue(view.isCompletedToken("test,"));
918 assertFalse(view.isCompletedToken("test"));
919 assertFalse(view.isCompletedToken("test "));
920 }
921
Mindy Pereiraaca23c42011-10-13 16:22:09 -0700922 public void testGetLastChip() {
923 populateMocks(3);
924 MockRecipientEditTextView view = createViewForTesting();
925 view.setMoreItem(createTestMoreItem());
926 view.setChipBackground(createChipBackground());
927 view.setChipHeight(48);
928 String first = (String) mTokenizer.terminateToken("FIRST");
929 String second = (String) mTokenizer.terminateToken("SECOND");
930 String third = (String) mTokenizer.terminateToken("THIRD");
931 mEditable = new SpannableStringBuilder();
932 mEditable.append(first + second + third);
933
934 // Test replacing the first chip with a new chip.
935 int firstStart = mEditable.toString().indexOf(first);
936 int firstEnd = firstStart + first.trim().length();
937 int secondStart = mEditable.toString().indexOf(second);
938 int secondEnd = secondStart + second.trim().length();
939 int thirdStart = mEditable.toString().indexOf(third);
940 int thirdEnd = thirdStart + third.trim().length();
941 mEditable.setSpan(mMockRecips[mMockRecips.length - 3], firstStart, firstEnd, 0);
942 mEditable.setSpan(mMockRecips[mMockRecips.length - 2], secondStart, secondEnd, 0);
943 mEditable.setSpan(mMockRecips[mMockRecips.length - 1], thirdStart, thirdEnd, 0);
944 assertEquals(view.getLastChip(), mMockRecips[mMockRecips.length - 1]);
945 mEditable.append("extra");
946 assertEquals(view.getLastChip(), mMockRecips[mMockRecips.length - 1]);
947 }
948
Mindy Pereira97cb2592011-09-26 16:11:41 -0700949 private Drawable createChipBackground() {
950 Bitmap drawable = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
951 return new BitmapDrawable(getContext().getResources(), drawable);
952 }
953
Mindy Pereirad7192502011-09-22 08:04:45 -0700954 private TextView createTestMoreItem() {
955 TextView view = new TextView(getContext());
956 view.setText("<xliff:g id='count'>%1$s</xliff:g> more...");
957 return view;
958 }
959
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700960 private void populateMocks(int size) {
961 mMockEntries = new RecipientEntry[size];
962 for (int i = 0; i < size; i++) {
963 mMockEntries[i] = RecipientEntry.constructGeneratedEntry("user",
Scott Kennedyb1cddbb2013-03-06 10:38:07 -0800964 "user@username.com", true);
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700965 }
Scott Kennedy194d4272013-03-06 22:06:45 -0800966 mMockRecips = new DrawableRecipientChip[size];
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700967 for (int i = 0; i < size; i++) {
Scott Kennedyf7e202d2013-03-06 21:38:10 -0800968 mMockRecips[i] = new VisibleRecipientChip(null, mMockEntries[i]);
Mindy Pereira8eb031e2011-09-20 15:42:32 -0700969 }
Mindy Pereira7cb970b2011-09-19 13:33:10 -0700970 }
Scott Kennedy20c8aa72013-03-06 22:23:59 -0800971
972 /**
973 * <p>
974 * Ensure the original text is always accurate, regardless of the type of email. The original
975 * text is used to determine where to display the chip span. If this test fails, it means some
976 * text that should be turned into one whole chip may behave unexpectedly.
977 * </p>
978 * <p>
979 * For example, a bug was seen where
980 *
981 * <pre>
982 * "Android User" <android@example.com>
983 * </pre>
984 *
985 * was converted to
986 *
987 * <pre>
988 * Android User [android@example.com]
989 * </pre>
990 *
991 * where text inside [] is a chip.
992 * </p>
993 */
994 public void testCreateReplacementChipOriginalText() {
995 // Name in quotes + email address
996 testCreateReplacementChipOriginalText("\"Android User\" <android@example.com>,");
997 // Name in quotes + email address without brackets
998 testCreateReplacementChipOriginalText("\"Android User\" android@example.com,");
999 // Name in quotes
1000 testCreateReplacementChipOriginalText("\"Android User\",");
1001 // Name without quotes + email address
1002 testCreateReplacementChipOriginalText("Android User <android@example.com>,");
1003 // Name without quotes
1004 testCreateReplacementChipOriginalText("Android User,");
1005 // Email address
1006 testCreateReplacementChipOriginalText("<android@example.com>,");
1007 // Email address without brackets
1008 testCreateReplacementChipOriginalText("android@example.com,");
1009 }
1010
1011 private void testCreateReplacementChipOriginalText(final String email) {
1012 // No trailing space
1013 attemptCreateReplacementChipOriginalText(email.trim());
1014 // Trailing space
1015 attemptCreateReplacementChipOriginalText(email.trim() + " ");
1016 }
1017
1018 private void attemptCreateReplacementChipOriginalText(final String email) {
1019 final RecipientEditTextView view = new RecipientEditTextView(getContext(), null);
1020
1021 view.setText(email);
1022 view.mPendingChips.add(email);
1023
1024 view.createReplacementChip(0, email.length(), view.getText(), true);
1025 // The "original text" should be the email without the comma or space(s)
1026 assertEquals(email.replaceAll(",\\s*$", ""),
1027 view.mTemporaryRecipients.get(0).getOriginalText().toString().trim());
1028 }
Scott Kennedy983c99b2013-03-22 09:42:03 -07001029
1030 public void testCreateTokenizedEntryForPhone() {
1031 final String phonePattern = "[^\\d]*888[^\\d]*555[^\\d]*1234[^\\d]*";
1032 final String phone1 = "8885551234";
1033 final String phone2 = "888-555-1234";
1034 final String phone3 = "(888) 555-1234";
1035
1036 final RecipientEditTextView view = new RecipientEditTextView(getContext(), null);
1037 final BaseRecipientAdapter adapter = new TestBaseRecipientAdapter(getContext(), 10,
1038 BaseRecipientAdapter.QUERY_TYPE_PHONE);
1039 view.setAdapter(adapter);
1040
1041 final RecipientEntry entry1 = view.createTokenizedEntry(phone1);
1042 final String destination1 = entry1.getDestination();
1043 assertTrue(phone1 + " failed with " + destination1,
1044 Pattern.matches(phonePattern, destination1));
1045
1046 final RecipientEntry entry2 = view.createTokenizedEntry(phone2);
1047 final String destination2 = entry2.getDestination();
1048 assertTrue(phone2 + " failed with " + destination2,
1049 Pattern.matches(phonePattern, destination2));
1050
1051 final RecipientEntry entry3 = view.createTokenizedEntry(phone3);
1052 final String destination3 = entry3.getDestination();
1053 assertTrue(phone3 + " failed with " + destination3,
1054 Pattern.matches(phonePattern, destination3));
1055 }
Mindy Pereira7cb970b2011-09-19 13:33:10 -07001056}