WordComposer.java revision be79227dc99421ff7be62224c51c553b3fa73777
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 30fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 70fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 90fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 199e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalardimport android.text.TextUtils; 209e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard 216b1f500da451de56932a8b2a99c63857994ece85Jean Chalardimport com.android.inputmethod.keyboard.Key; 22887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 233708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 24887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.ArrayList; 26c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport java.util.Arrays; 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer { 328fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 33887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; 348fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public static final int NOT_A_COORDINATE = -1; 35887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 36be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard final int N = BinaryDictionary.MAX_WORD_LENGTH; 378fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 38be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private ArrayList<int[]> mCodes; 39be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private int[] mXCoordinates; 40be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private int[] mYCoordinates; 41be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private StringBuilder mTypedWord; 42be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private CharSequence mAutoCorrection; 434a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 44be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard // Cache these values for performance 454a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 461c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani private boolean mAutoCapitalized; 47117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard private int mTrailingSingleQuotesCount; 48c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 500b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 520b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 54979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 55be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes = new ArrayList<int[]>(N); 56be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord = new StringBuilder(N); 57be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates = new int[N]; 58be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mYCoordinates = new int[N]; 59be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 60117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 63f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok public WordComposer(WordComposer source) { 649fbfd5877305ed19a20663630b498b6b3fdae942satok init(source); 659fbfd5877305ed19a20663630b498b6b3fdae942satok } 669fbfd5877305ed19a20663630b498b6b3fdae942satok 679fbfd5877305ed19a20663630b498b6b3fdae942satok public void init(WordComposer source) { 68be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes = new ArrayList<int[]>(source.mCodes); 69be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord = new StringBuilder(source.mTypedWord); 70be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); 71be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); 72ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mCapsCount = source.mCapsCount; 73ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; 74ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mAutoCapitalized = source.mAutoCapitalized; 75117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount; 76979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 77979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 82be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes.clear(); 83be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 84be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 854a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 86ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 87117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 88923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 90923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 91923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 94ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka public final int size() { 95be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mTypedWord.length(); 96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 98196d82cdd740580ed79d801483dbc282be85d076Jean Chalard public final boolean isComposingWord() { 99196d82cdd740580ed79d801483dbc282be85d076Jean Chalard return size() > 0; 100196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } 101196d82cdd740580ed79d801483dbc282be85d076Jean Chalard 102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the codes at a particular position in the word. 104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param index the position in the word 105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the unicode for the pressed and surrounding keys 106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public int[] getCodesAt(int index) { 108be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mCodes.get(index); 109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1118fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public int[] getXCoordinates() { 112be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mXCoordinates; 1138fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1148fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 1158fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public int[] getYCoordinates() { 116be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mYCoordinates; 1178fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1188fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 119ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { 120ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (index == 0) return Character.isUpperCase(codePoint); 121436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka return previous && !Character.isUpperCase(codePoint); 122ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka } 123ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka 124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of 126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param codes the array of unicode values 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1298fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public void add(int primaryCode, int[] codes, int x, int y) { 130ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int newIndex = size(); 131be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.append((char) primaryCode); 132231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani correctPrimaryJuxtapos(primaryCode, codes); 133be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes.add(codes); 134ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { 135be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates[newIndex] = x; 136be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mYCoordinates[newIndex] = y; 1378fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 138ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = isFirstCharCapitalized( 139ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka newIndex, primaryCode, mIsFirstCharCapitalized); 140ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(primaryCode)) mCapsCount++; 141117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { 142117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 143117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } else { 144117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 145117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 146be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 1506b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Internal method to retrieve reasonable proximity info for a character. 1516b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 1523708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka private void addKeyInfo(final int codePoint, final Keyboard keyboard, 1536b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final KeyDetector keyDetector) { 1546b1f500da451de56932a8b2a99c63857994ece85Jean Chalard for (final Key key : keyboard.mKeys) { 1556b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (key.mCode == codePoint) { 1566b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int x = key.mX + key.mWidth / 2; 1576b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int y = key.mY + key.mHeight / 2; 1586b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int[] codes = keyDetector.newCodeArray(); 159e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka keyDetector.getKeyAndNearbyCodes(x, y, codes); 1606b1f500da451de56932a8b2a99c63857994ece85Jean Chalard add(codePoint, codes, x, y); 1616b1f500da451de56932a8b2a99c63857994ece85Jean Chalard return; 1626b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1636b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1646b1f500da451de56932a8b2a99c63857994ece85Jean Chalard add(codePoint, new int[] { codePoint }, 1656b1f500da451de56932a8b2a99c63857994ece85Jean Chalard WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); 1666b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1676b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 1686b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 1696b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Set the currently composing word to the one passed as an argument. 1706b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. 1716b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 1723708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka public void setComposingWord(final CharSequence word, final Keyboard keyboard, 1736b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final KeyDetector keyDetector) { 1746b1f500da451de56932a8b2a99c63857994ece85Jean Chalard reset(); 1756b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int length = word.length(); 1766b1f500da451de56932a8b2a99c63857994ece85Jean Chalard for (int i = 0; i < length; ++i) { 1776b1f500da451de56932a8b2a99c63857994ece85Jean Chalard int codePoint = word.charAt(i); 1786b1f500da451de56932a8b2a99c63857994ece85Jean Chalard addKeyInfo(codePoint, keyboard, keyDetector); 1796b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1806b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1816b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 1826b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 1836b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard. 1846b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 1853708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka public void setComposingWord(final CharSequence word, final Keyboard keyboard) { 1866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final KeyDetector keyDetector = new KeyDetector(0); 1876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard keyDetector.setKeyboard(keyboard, 0, 0); 1886b1f500da451de56932a8b2a99c63857994ece85Jean Chalard keyDetector.setProximityCorrectionEnabled(true); 1896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth); 1906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard setComposingWord(word, keyboard, keyDetector); 1916b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1926b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 1936b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 194231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * Swaps the first and second values in the codes array if the primary code is not the first 195231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * value in the array but the second. This happens when the preferred key is not the key that 196231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * the user released the finger on. 197231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param primaryCode the preferred character 198231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani * @param codes array of codes based on distance from touch point 199231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani */ 2008fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { 201231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes.length < 2) return; 202231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { 203231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[1] = codes[0]; 204231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani codes[0] = primaryCode; 205231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 206231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani } 207231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani 208231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani /** 209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Delete the last keystroke as a result of hitting backspace. 210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void deleteLast() { 212ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int size = size(); 213ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size > 0) { 214ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka final int lastPos = size - 1; 215be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard char lastChar = mTypedWord.charAt(lastPos); 216be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes.remove(lastPos); 217be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.deleteCharAt(lastPos); 218ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(lastChar)) mCapsCount--; 219d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka } 220ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size() == 0) { 221ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 222117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 223117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (mTrailingSingleQuotesCount > 0) { 224117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard --mTrailingSingleQuotesCount; 225c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } else { 226be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard for (int i = mTypedWord.length() - 1; i >= 0; --i) { 227be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; 228117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 229117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 2308fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 231be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 232923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 233923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 234923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 236117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * @return the word that was typed so far. Never returns null. 237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 2385c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 239be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mTypedWord.toString(); 240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 2460b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 2470b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2490b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 250117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard public int trailingSingleQuotesCount() { 251117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard return mTrailingSingleQuotesCount; 252c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } 253c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 2540b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 2550b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 2560b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 2570b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 2580b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 2590b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return (mCapsCount > 0) && (mCapsCount == size()); 2600b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 2610b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 2634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 2644a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 2654a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 2664a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 2674a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 2681c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 2690fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard /** 2701c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Saves the reason why the word is capitalized - whether it was automatic or 2711c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * due to the user hitting shift in the middle of a sentence. 2721c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @param auto whether it was an automatic capitalization due to start of sentence 2731c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2741c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public void setAutoCapitalized(boolean auto) { 2751c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani mAutoCapitalized = auto; 2761c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 2771c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 2781c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 2791c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 2801c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 2811c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2821c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public boolean isAutoCapitalized() { 2831c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani return mAutoCapitalized; 2841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 285117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 286117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 287117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Sets the auto-correction for this word. 288117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 289117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public void setAutoCorrection(final CharSequence correction) { 290be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = correction; 291117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 292117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 293117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 294f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard * @return the auto-correction for this word, or null if none. 295117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 296117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public CharSequence getAutoCorrectionOrNull() { 297be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mAutoCorrection; 298117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 299c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 300267563d1bb4d8091293fbd8774f0f95ef59f03c4Jean Chalard // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. 3012692a8700737d8eed268039aa27b22a31669da08Jean Chalard public LastComposedWord commitWord(final int type) { 3020d0f01da674e89e294d14061837711996dc5a693Ken Wakasa // Note: currently, we come here whenever we commit a word. If it's any *other* kind than 3030fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. 3040fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user 3050fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // typed because the IME decided *not* to auto-correct for whatever reason. 3060fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. 3070fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // As it happens these two cases should behave differently, because the former can be 3080fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // canceled while the latter can't. Currently, we figure this out in 3092712f23acbb197af3b125da4cc47108e71b7446dJean Chalard // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally 3102712f23acbb197af3b125da4cc47108e71b7446dJean Chalard // cleaner to do it here, but it would be slower (since we would #equals() for each commit, 3112712f23acbb197af3b125da4cc47108e71b7446dJean Chalard // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. 312be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard final LastComposedWord lastComposedWord = new LastComposedWord(type, mCodes, 313be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates, mYCoordinates, mTypedWord.toString(), 314be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) || (null == mAutoCorrection) 315be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard ? null : mAutoCorrection.toString()); 316be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes.clear(); 317be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 318be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 3191f8fc62ccb5018716457dc309ab11ad3e1506ad1Jean Chalard return lastComposedWord; 320c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 321c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 3222712f23acbb197af3b125da4cc47108e71b7446dJean Chalard public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { 323be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mCodes = lastComposedWord.mCodes; 324be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates = lastComposedWord.mXCoordinates; 325be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mYCoordinates = lastComposedWord.mYCoordinates; 326be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 327be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.append(lastComposedWord.mTypedWord); 328be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = lastComposedWord.mAutoCorrection; 3299e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard } 330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 331