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