19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 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.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Editable; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannableString; 22a4a5758b5f51834f7555ec909e8188c432fc5dc4Gilles Debunneimport android.text.Spanned; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.QwertyKeyListener; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 268a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 278a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An editable text view, extending {@link AutoCompleteTextView}, that 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can show completion suggestions for the substring of the text where 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the user is typing instead of necessarily for the entire thing. 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 34979154ffd3dc3a3a76ec11fbf3f50440c13b70b6Daisuke Miyakawa * You must provide a {@link Tokenizer} to distinguish the 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * various substrings. 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>The following code snippet shows how to create a text view which suggests 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * various countries names while the user is typing:</p> 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre class="prettyprint"> 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * public class CountriesActivity extends Activity { 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * protected void onCreate(Bundle savedInstanceState) { 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * super.onCreate(savedInstanceState); 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * setContentView(R.layout.autocomplete_7); 45979154ffd3dc3a3a76ec11fbf3f50440c13b70b6Daisuke Miyakawa * 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * android.R.layout.simple_dropdown_item_1line, COUNTRIES); 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * MultiAutoCompleteTextView textView = (MultiAutoCompleteTextView) findViewById(R.id.edit); 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * textView.setAdapter(adapter); 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * textView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer()); 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * } 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * private static final String[] COUNTRIES = new String[] { 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "Belgium", "France", "Italy", "Germany", "Spain" 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * }; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * }</pre> 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class MultiAutoCompleteTextView extends AutoCompleteTextView { 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Tokenizer mTokenizer; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public MultiAutoCompleteTextView(Context context) { 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public MultiAutoCompleteTextView(Context context, AttributeSet attrs) { 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, attrs, com.android.internal.R.attr.autoCompleteTextViewStyle); 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public MultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs, defStyle); 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ void finishInit() { } 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the Tokenizer that will be used to determine the relevant 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * range of the text where the user is typing. 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setTokenizer(Tokenizer t) { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTokenizer = t; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Instead of filtering on the entire contents of the edit box, 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this subclass method filters on the range from 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link Tokenizer#findTokenStart} to {@link #getSelectionEnd} 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * if the length of that range meets or exceeds {@link #getThreshold}. 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void performFiltering(CharSequence text, int keyCode) { 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (enoughToFilter()) { 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getSelectionEnd(); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = mTokenizer.findTokenStart(text, end); 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project performFiltering(text, start, end, keyCode); 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dismissDropDown(); 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Filter f = getFilter(); 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f != null) { 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project f.filter(null); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Instead of filtering whenever the total length of the text 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * exceeds the threshhold, this subclass filters only when the 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * length of the range from 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link Tokenizer#findTokenStart} to {@link #getSelectionEnd} 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * meets or exceeds {@link #getThreshold}. 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean enoughToFilter() { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Editable text = getText(); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getSelectionEnd(); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end < 0 || mTokenizer == null) { 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = mTokenizer.findTokenStart(text, end); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end - start >= getThreshold()) { 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Instead of validating the entire text, this subclass method validates 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * each token of the text individually. Empty tokens are removed. 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 136979154ffd3dc3a3a76ec11fbf3f50440c13b70b6Daisuke Miyakawa @Override 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void performValidation() { 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Validator v = getValidator(); 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (v == null || mTokenizer == null) { 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Editable e = getText(); 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = getText().length(); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i > 0) { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = mTokenizer.findTokenStart(e, i); 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = mTokenizer.findTokenEnd(e, start); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CharSequence sub = e.subSequence(start, end); 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (TextUtils.isEmpty(sub)) { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.replace(start, i, ""); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!v.isValid(sub)) { 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.replace(start, i, 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTokenizer.terminateToken(v.fixText(sub))); 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = start; 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Starts filtering the content of the drop down list. The filtering 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * pattern is the specified range of text from the edit box. Subclasses may 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * override this method to filter with a different pattern, for 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * instance a smaller substring of <code>text</code>.</p> 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void performFiltering(CharSequence text, int start, int end, 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int keyCode) { 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getFilter().filter(text.subSequence(start, end), this); 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>Performs the text completion by replacing the range from 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link Tokenizer#findTokenStart} to {@link #getSelectionEnd} by the 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the result of passing <code>text</code> through 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link Tokenizer#terminateToken}. 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * In addition, the replaced region will be marked as an AutoText 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * substition so that if the user immediately presses DEL, the 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * completion will be undone. 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Subclasses may override this method to do some different 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * insertion of the content into the edit box.</p> 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param text the selected suggestion in the drop down list 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void replaceText(CharSequence text) { 188c1d2748d442f06a7266be04b9e9c7d20609ad5ccDaisuke Miyakawa clearComposingText(); 189c1d2748d442f06a7266be04b9e9c7d20609ad5ccDaisuke Miyakawa 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = getSelectionEnd(); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = mTokenizer.findTokenStart(getText(), end); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Editable editable = getText(); 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String original = TextUtils.substring(editable, start, end); 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project QwertyKeyListener.markAsReplaced(editable, start, end, original); 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project editable.replace(start, end, mTokenizer.terminateToken(text)); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2008a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 2018a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 2028a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 2038a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(MultiAutoCompleteTextView.class.getName()); 2048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 2058a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 2068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 2078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 2088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 2098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(MultiAutoCompleteTextView.class.getName()); 2108a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 2118a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static interface Tokenizer { 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the start of the token that ends at offset 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <code>cursor</code> within <code>text</code>. 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findTokenStart(CharSequence text, int cursor); 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the end of the token (minus trailing punctuation) 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * that begins at offset <code>cursor</code> within <code>text</code>. 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findTokenEnd(CharSequence text, int cursor); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns <code>text</code>, modified, if necessary, to ensure that 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * it ends with a token terminator (for example a space or comma). 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence terminateToken(CharSequence text); 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This simple Tokenizer can be used for lists where the items are 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * separated by a comma and one or more spaces. 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class CommaTokenizer implements Tokenizer { 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findTokenStart(CharSequence text, int cursor) { 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = cursor; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i > 0 && text.charAt(i - 1) != ',') { 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i--; 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < cursor && text.charAt(i) == ' ') { 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int findTokenEnd(CharSequence text, int cursor) { 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = cursor; 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = text.length(); 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i < len) { 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (text.charAt(i) == ',') { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i++; 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return len; 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence terminateToken(CharSequence text) { 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i = text.length(); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (i > 0 && text.charAt(i - 1) == ' ') { 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i--; 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i > 0 && text.charAt(i - 1) == ',') { 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return text; 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (text instanceof Spanned) { 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SpannableString sp = new SpannableString(text + ", "); 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.copySpansFrom((Spanned) text, 0, text.length(), 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object.class, sp, 0); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sp; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return text + ", "; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 287