19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text.util; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.MultiAutoCompleteTextView; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 2278a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghoshimport java.util.Collection; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class works as a Tokenizer for MultiAutoCompleteTextView for 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * address list fields, and also provides a method for converting 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a string of addresses (such as might be typed into such a field) 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * into a series of Rfc822Tokens. 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Rfc822Tokenizer implements MultiAutoCompleteTextView.Tokenizer { 3178a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This constructor will try to take a string like 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "Foo Bar (something) <foo\@google.com>, 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * blah\@google.com (something)" 3678a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * and convert it into one or more Rfc822Tokens, output into the supplied 3778a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * collection. 3878a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * It does *not* decode MIME encoded-words; charset conversion 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * must already have taken place if necessary. 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * It will try to be tolerant of broken syntax instead of 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returning an error. 4378a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4578a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh public static void tokenize(CharSequence text, Collection<Rfc822Token> out) { 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder name = new StringBuilder(); 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder address = new StringBuilder(); 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuilder comment = new StringBuilder(); 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = 0; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int cursor = text.length(); 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor) { 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = text.charAt(i); 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == ',' || c == ';') { 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor && text.charAt(i) == ' ') { 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project crunch(name); 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (address.length() > 0) { 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.add(new Rfc822Token(name.toString(), 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address.toString(), 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.toString())); 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.length() > 0) { 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.add(new Rfc822Token(null, 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.toString(), 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.toString())); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.setLength(0); 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address.setLength(0); 7799c7dea7546bf0bd9ec1c03d300b11d93d9306ddErik comment.setLength(0); 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '"') { 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor) { 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = text.charAt(i); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == '"') { 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '\\') { 889694f9056a86081aadc1d7caab82d340847b3884Henrik Hall if (i + 1 < cursor) { 899694f9056a86081aadc1d7caab82d340847b3884Henrik Hall name.append(text.charAt(i + 1)); 909694f9056a86081aadc1d7caab82d340847b3884Henrik Hall } 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i += 2; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.append(c); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '(') { 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int level = 1; 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor && level > 0) { 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = text.charAt(i); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == ')') { 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (level > 1) { 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.append(c); 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project level--; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '(') { 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.append(c); 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project level++; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '\\') { 1169694f9056a86081aadc1d7caab82d340847b3884Henrik Hall if (i + 1 < cursor) { 1179694f9056a86081aadc1d7caab82d340847b3884Henrik Hall comment.append(text.charAt(i + 1)); 1189694f9056a86081aadc1d7caab82d340847b3884Henrik Hall } 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i += 2; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.append(c); 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '<') { 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor) { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = text.charAt(i); 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == '>') { 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address.append(c); 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == ' ') { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.append('\0'); 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.append(c); 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project crunch(name); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (address.length() > 0) { 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.add(new Rfc822Token(name.toString(), 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project address.toString(), 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.toString())); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.length() > 0) { 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out.add(new Rfc822Token(null, 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.toString(), 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project comment.toString())); 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15978a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh } 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16178a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh /** 16278a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * This method will try to take a string like 16378a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * "Foo Bar (something) <foo\@google.com>, 16478a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * blah\@google.com (something)" 16578a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * and convert it into one or more Rfc822Tokens. 16678a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * It does *not* decode MIME encoded-words; charset conversion 16778a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * must already have taken place if necessary. 16878a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * It will try to be tolerant of broken syntax instead of 16978a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh * returning an error. 17078a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh */ 17178a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh public static Rfc822Token[] tokenize(CharSequence text) { 17278a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh ArrayList<Rfc822Token> out = new ArrayList<Rfc822Token>(); 17378a5b8106a4768f7a67e5a29c58f23cd95f6c47cDebajit Ghosh tokenize(text, out); 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return out.toArray(new Rfc822Token[out.size()]); 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void crunch(StringBuilder sb) { 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = 0; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = sb.length(); 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len) { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = sb.charAt(i); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == '\0') { 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == 0 || i == len - 1 || 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.charAt(i - 1) == ' ' || 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.charAt(i - 1) == '\0' || 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.charAt(i + 1) == ' ' || 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.charAt(i + 1) == '\0') { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.deleteCharAt(i); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project len--; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < len; i++) { 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sb.charAt(i) == '\0') { 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sb.setCharAt(i, ' '); 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@inheritDoc} 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findTokenStart(CharSequence text, int cursor) { 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * It's hard to search backward, so search forward until 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * we reach the cursor. 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int best = 0; 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = 0; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor) { 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = findTokenEnd(text, i); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i < cursor) { 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; // Skip terminating punctuation 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor && text.charAt(i) == ' ') { 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i < cursor) { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project best = i; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return best; 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@inheritDoc} 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findTokenEnd(CharSequence text, int cursor) { 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = text.length(); 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = cursor; 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len) { 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = text.charAt(i); 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == ',' || c == ';') { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '"') { 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len) { 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = text.charAt(i); 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == '"') { 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 259114f98a75334813fe116da3d95567db8984d45b9Mattias Niklewski } else if (c == '\\' && i + 1 < len) { 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i += 2; 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '(') { 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int level = 1; 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len && level > 0) { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = text.charAt(i); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == ')') { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project level--; 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '(') { 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project level++; 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 278114f98a75334813fe116da3d95567db8984d45b9Mattias Niklewski } else if (c == '\\' && i + 1 < len) { 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i += 2; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (c == '<') { 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len) { 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = text.charAt(i); 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == '>') { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Terminates the specified address with a comma and space. 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This assumes that the specified text already has valid syntax. 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The Adapter subclass's convertToString() method must make that 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * guarantee. 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence terminateToken(CharSequence text) { 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return text + ", "; 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 315