19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 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.method; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.*; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.method.TextKeyListener.Capitalize; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyCharacterMap; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the standard key listener for alphabetic input on qwerty 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * keyboards. You should generally not need to instantiate this yourself; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TextKeyListener will do it for you. 30405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * <p></p> 31405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * As for all implementations of {@link KeyListener}, this class is only concerned 32405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * with hardware keyboards. Software input methods have no obligation to trigger 33405bc51c5dc73846a4abdc325cd234eb2d37469fJean Chalard * the methods in this class. 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class QwertyKeyListener extends BaseKeyListener { 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static QwertyKeyListener[] sInstance = 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new QwertyKeyListener[Capitalize.values().length * 2]; 3847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown private static QwertyKeyListener sFullKeyboardInstance; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4047e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown private Capitalize mAutoCap; 4147e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown private boolean mAutoText; 4247e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown private boolean mFullKeyboard; 4347e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown 4447e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown private QwertyKeyListener(Capitalize cap, boolean autoText, boolean fullKeyboard) { 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAutoCap = cap; 4647e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown mAutoText = autoText; 4747e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown mFullKeyboard = fullKeyboard; 4847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown } 4947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown 5047e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown public QwertyKeyListener(Capitalize cap, boolean autoText) { 5147e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown this(cap, autoText, false); 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a new or existing instance with the specified capitalization 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and correction properties. 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown public static QwertyKeyListener getInstance(boolean autoText, Capitalize cap) { 5947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown int off = cap.ordinal() * 2 + (autoText ? 1 : 0); 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sInstance[off] == null) { 6247e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown sInstance[off] = new QwertyKeyListener(cap, autoText); 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return sInstance[off]; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown /** 6947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown * Gets an instance of the listener suitable for use with full keyboards. 7047e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown * Disables auto-capitalization, auto-text and long-press initiated on-screen 7147e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown * character pickers. 7247e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown */ 7347e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown public static QwertyKeyListener getInstanceForFullKeyboard() { 7447e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown if (sFullKeyboardInstance == null) { 7547e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown sFullKeyboardInstance = new QwertyKeyListener(Capitalize.NONE, false, true); 7647e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown } 7747e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown return sFullKeyboardInstance; 7847e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown } 7947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getInputType() { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return makeTextContentType(mAutoCap, mAutoText); 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyDown(View view, Editable content, 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int keyCode, KeyEvent event) { 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int selStart, selEnd; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pref = 0; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pref = TextKeyListener.getInstance().getPrefs(view.getContext()); 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int a = Selection.getSelectionStart(content); 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int b = Selection.getSelectionEnd(content); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selStart = Math.min(a, b); 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selEnd = Math.max(a, b); 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selStart < 0 || selEnd < 0) { 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selStart = selEnd = 0; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Selection.setSelection(content, 0, 0); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int activeStart = content.getSpanStart(TextKeyListener.ACTIVE); 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int activeEnd = content.getSpanEnd(TextKeyListener.ACTIVE); 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // QWERTY keyboard normal case 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11114f10e5d5f51bc54ca2a45ee62d3cfb6debd3af0Raph Levien int i = event.getUnicodeChar(getMetaState(content, event)); 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11347e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown if (!mFullKeyboard) { 11447e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown int count = event.getRepeatCount(); 11547e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown if (count > 0 && selStart == selEnd && selStart > 0) { 11647e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown char c = content.charAt(selStart - 1); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 118e004b868f3e10d133798cfc719a69e3a1db0fa18Dmitry Tsyganyuk if ((c == i || c == Character.toUpperCase(i)) && view != null) { 11947e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown if (showCharacterPicker(view, content, c, false, count)) { 12047e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown resetMetaState(content); 12147e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown return true; 12247e6b1b5eef8ee99872f278f66bc498c4fcca0d8Jeff Brown } 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == KeyCharacterMap.PICKER_DIALOG_INPUT) { 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (view != null) { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showCharacterPicker(view, content, 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project KeyCharacterMap.PICKER_DIALOG_INPUT, true, 1); 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetMetaState(content); 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i == KeyCharacterMap.HEX_INPUT) { 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selStart == selEnd) { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start = selEnd; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (start > 0 && selEnd - start < 4 && 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Character.digit(content.charAt(start - 1), 16) >= 0) { 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start--; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start = selStart; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ch = -1; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String hex = TextUtils.substring(content, start, selEnd); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = Integer.parseInt(hex, 16); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException nfe) { } 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch >= 0) { 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selStart = start; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Selection.setSelection(content, selStart, selEnd); 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = ch; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = 0; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i != 0) { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean dead = false; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((i & KeyCharacterMap.COMBINING_ACCENT) != 0) { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dead = true; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = i & KeyCharacterMap.COMBINING_ACCENT_MASK; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (activeStart == selStart && activeEnd == selEnd) { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean replace = false; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selEnd - selStart - 1 == 0) { 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char accent = content.charAt(selStart); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int composed = event.getDeadChar(accent, i); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (composed != 0) { 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = composed; 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project replace = true; 183548655045a9c9791bd33e77a823afea5846228abJean Chalard dead = false; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!replace) { 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Selection.setSelection(content, selEnd); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(TextKeyListener.ACTIVE); 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selStart = selEnd; 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((pref & TextKeyListener.AUTO_CAP) != 0 && 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Character.isLowerCase(i) && 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextKeyListener.shouldCap(mAutoCap, content, selStart)) { 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int where = content.getSpanEnd(TextKeyListener.CAPPED); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int flags = content.getSpanFlags(TextKeyListener.CAPPED); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where == selStart && (((flags >> 16) & 0xFFFF) == i)) { 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(TextKeyListener.CAPPED); 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flags = i << 16; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i = Character.toUpperCase(i); 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selStart == 0) 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(TextKeyListener.CAPPED, 0, 0, 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_MARK_MARK | flags); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(TextKeyListener.CAPPED, 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selStart - 1, selStart, 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flags); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selStart != selEnd) { 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Selection.setSelection(content, selEnd); 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(OLD_SEL_START, selStart, selStart, 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_MARK_MARK); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.replace(selStart, selEnd, String.valueOf((char) i)); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oldStart = content.getSpanStart(OLD_SEL_START); 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selEnd = Selection.getSelectionEnd(content); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldStart < selEnd) { 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(TextKeyListener.LAST_TYPED, 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oldStart, selEnd, 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dead) { 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Selection.setSelection(content, oldStart, selEnd); 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(TextKeyListener.ACTIVE, oldStart, selEnd, 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustMetaAfterKeypress(content); 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // potentially do autotext replacement if the character 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // that was typed was an autotext terminator 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((pref & TextKeyListener.AUTO_TEXT) != 0 && mAutoText && 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (i == ' ' || i == '\t' || i == '\n' || 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i == ',' || i == '.' || i == '!' || i == '?' || 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i == '"' || Character.getType(i) == Character.END_PUNCTUATION) && 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.getSpanEnd(TextKeyListener.INHIBIT_REPLACEMENT) 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project != oldStart) { 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int x; 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (x = oldStart; x > 0; x--) { 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = content.charAt(x - 1); 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != '\'' && !Character.isLetter(c)) { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String rep = getReplacement(content, x, oldStart, view); 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rep != null) { 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Replaced[] repl = content.getSpans(0, content.length(), 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Replaced.class); 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int a = 0; a < repl.length; a++) 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(repl[a]); 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] orig = new char[oldStart - x]; 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.getChars(content, x, oldStart, orig, 0); 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(new Replaced(orig), x, oldStart, 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.replace(x, oldStart, rep); 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Replace two spaces by a period and a space. 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((pref & TextKeyListener.AUTO_PERIOD) != 0 && mAutoText) { 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project selEnd = Selection.getSelectionEnd(content); 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (selEnd - 3 >= 0) { 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (content.charAt(selEnd - 1) == ' ' && 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.charAt(selEnd - 2) == ' ') { 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = content.charAt(selEnd - 3); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = selEnd - 3; j > 0; j--) { 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c == '"' || 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Character.getType(c) == Character.END_PUNCTUATION) { 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = content.charAt(j - 1); 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Character.isLetter(c) || Character.isDigit(c)) { 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.replace(selEnd - 2, selEnd - 1, "."); 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 30314d0ca1473b991288b2dfab57409054dec7cd2faJeff Brown } else if (keyCode == KeyEvent.KEYCODE_DEL 30414d0ca1473b991288b2dfab57409054dec7cd2faJeff Brown && (event.hasNoModifiers() || event.hasModifiers(KeyEvent.META_ALT_ON)) 30514d0ca1473b991288b2dfab57409054dec7cd2faJeff Brown && selStart == selEnd) { 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // special backspace case for undoing autotext 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int consider = 1; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if backspacing over the last typed character, 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it undoes the autotext prior to that character 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // (unless the character typed was newline, in which 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // case this behavior would be confusing) 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (content.getSpanEnd(TextKeyListener.LAST_TYPED) == selStart) { 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (content.charAt(selStart - 1) != '\n') 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project consider = 2; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Replaced[] repl = content.getSpans(selStart - consider, selStart, 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Replaced.class); 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (repl.length > 0) { 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int st = content.getSpanStart(repl[0]); 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int en = content.getSpanEnd(repl[0]); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String old = new String(repl[0].mText); 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(repl[0]); 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3304df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project // only cancel the autocomplete if the cursor is at the end of 331c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // the replaced span (or after it, because the user is 332c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // backspacing over the space after the word, not the word 333c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project // itself). 334c39a6e0c51e182338deb8b63d07933b585134929The Android Open Source Project if (selStart >= en) { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT, 3364df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project en, en, Spannable.SPAN_POINT_POINT); 3374df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project content.replace(st, en, old); 3384df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project 3394df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project en = content.getSpanStart(TextKeyListener.INHIBIT_REPLACEMENT); 3404df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project if (en - 1 >= 0) { 3414df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT, 3424df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project en - 1, en, 3434df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 3444df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project } else { 3454df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project content.removeSpan(TextKeyListener.INHIBIT_REPLACEMENT); 3464df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project } 3474df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project adjustMetaAfterKeypress(content); 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3494df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project adjustMetaAfterKeypress(content); 3504df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project return super.onKeyDown(view, content, keyCode, event); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return super.onKeyDown(view, content, keyCode, event); 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String getReplacement(CharSequence src, int start, int end, 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View view) { 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = end - start; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean changecase = false; 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String replacement = AutoText.get(src, start, end, view); 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (replacement == null) { 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String key = TextUtils.substring(src, start, end).toLowerCase(); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project replacement = AutoText.get(key, 0, end - start, view); 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project changecase = true; 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (replacement == null) 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int caps = 0; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (changecase) { 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = start; j < end; j++) { 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Character.isUpperCase(src.charAt(j))) 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project caps++; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String out; 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (caps == 0) 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = replacement; 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (caps == 1) 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = toTitleCase(replacement); 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (caps == len) 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = replacement.toUpperCase(); 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project out = toTitleCase(replacement); 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (out.length() == len && 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.regionMatches(src, start, out, 0, len)) 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return out; 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Marks the specified region of <code>content</code> as having 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * contained <code>original</code> prior to AutoText replacement. 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Call this method when you have done or are about to do an 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * AutoText-style replacement on a region of text and want to let 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the same mechanism (the user pressing DEL immediately after the 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * change) undo the replacement. 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param content the Editable text where the replacement was made 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param start the start of the replaced region 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param end the end of the replaced region; the location of the cursor 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param original the text to be restored if the user presses DEL 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void markAsReplaced(Spannable content, int start, int end, 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String original) { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Replaced[] repl = content.getSpans(0, content.length(), Replaced.class); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int a = 0; a < repl.length; a++) { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.removeSpan(repl[a]); 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = original.length(); 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] orig = new char[len]; 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project original.getChars(0, len, orig, 0); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project content.setSpan(new Replaced(orig), start, end, 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static SparseArray<String> PICKER_SETS = 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new SparseArray<String>(); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 434a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5\u0104\u0100"); 435a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('C', "\u00C7\u0106\u010C"); 436a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('D', "\u010E"); 437a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB\u0118\u011A\u0112"); 438ec1f8a2ecedb4904ca93bce14b4e1e033539fa55Eric Fischer PICKER_SETS.put('G', "\u011E"); 439a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('L', "\u0141"); 4404ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A\u0130"); 441a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('N', "\u00D1\u0143\u0147"); 442a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6\u014C"); 443a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('R', "\u0158"); 444ec1f8a2ecedb4904ca93bce14b4e1e033539fa55Eric Fischer PICKER_SETS.put('S', "\u015A\u0160\u015E"); 445a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('T', "\u0164"); 446a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('U', "\u00D9\u00DA\u00DB\u00DC\u016E\u016A"); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PICKER_SETS.put('Y', "\u00DD\u0178"); 448a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('Z', "\u0179\u017B\u017D"); 449a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('a', "\u00E0\u00E1\u00E2\u00E4\u00E6\u00E3\u00E5\u0105\u0101"); 450a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('c', "\u00E7\u0107\u010D"); 451a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('d', "\u010F"); 452a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB\u0119\u011B\u0113"); 453ec1f8a2ecedb4904ca93bce14b4e1e033539fa55Eric Fischer PICKER_SETS.put('g', "\u011F"); 4544ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B\u0131"); 455a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('l', "\u0142"); 456a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('n', "\u00F1\u0144\u0148"); 457a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6\u014D"); 458a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('r', "\u0159"); 459ec1f8a2ecedb4904ca93bce14b4e1e033539fa55Eric Fischer PICKER_SETS.put('s', "\u00A7\u00DF\u015B\u0161\u015F"); 460a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('t', "\u0165"); 461a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('u', "\u00F9\u00FA\u00FB\u00FC\u016F\u016B"); 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PICKER_SETS.put('y', "\u00FD\u00FF"); 463a3ea3ae07ff3fec565215ad73fc7430a07b57418Eric Fischer PICKER_SETS.put('z', "\u017A\u017C\u017E"); 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT, 465d7c432bf7f9c0c9dd6d954fffcd68828c0e309a5Eric Fischer "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\|"); 466cebe347e7ff99c593a0136ae8bcb3cadab7d77b6Eric Fischer PICKER_SETS.put('/', "\\"); 4674ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer 4684ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer // From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml 4694ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer 4704ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('1', "\u00b9\u00bd\u2153\u00bc\u215b"); 4714ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('2', "\u00b2\u2154"); 4724ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('3', "\u00b3\u00be\u215c"); 4734ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('4', "\u2074"); 4744ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('5', "\u215d"); 4754ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('7', "\u215e"); 4764ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('0', "\u207f\u2205"); 4774ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('$', "\u00a2\u00a3\u20ac\u00a5\u20a3\u20a4\u20b1"); 4784ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('%', "\u2030"); 4794ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('*', "\u2020\u2021"); 4804ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('-', "\u2013\u2014"); 4814ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('+', "\u00b1"); 4824ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('(', "[{<"); 4834ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put(')', "]}>"); 4844ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('!', "\u00a1"); 4854ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('"', "\u201c\u201d\u00ab\u00bb\u02dd"); 4864ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('?', "\u00bf"); 4874ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put(',', "\u201a\u201e"); 4884ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer 4894ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer // From packages/inputmethods/LatinIME/res/xml/kbd_symbols_shift.xml 4904ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer 4914ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('=', "\u2260\u2248\u221e"); 4924ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('<', "\u2264\u00ab\u2039"); 4934ef29959bda59ae5f90aeeb48a8ef7e218500d03Eric Fischer PICKER_SETS.put('>', "\u2265\u00bb\u203a"); 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean showCharacterPicker(View view, Editable content, char c, 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean insert, int count) { 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String set = PICKER_SETS.get(c); 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (set == null) { 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == 1) { 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new CharacterPickerDialog(view.getContext(), 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project view, content, set, insert).show(); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String toTitleCase(String src) { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Character.toUpperCase(src.charAt(0)) + src.substring(1); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* package */ static class Replaced implements NoCopySpan 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Replaced(char[] text) { 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mText = text; 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private char[] mText; 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 525