WordComposer.java revision 01ab7c8b59a7f12862fbd95fb252e56719f1757f
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 196b1f500da451de56932a8b2a99c63857994ece85Jean Chalardimport com.android.inputmethod.keyboard.Key; 20887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 213708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 22ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatokimport com.android.inputmethod.keyboard.KeyboardActionListener; 23887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 24c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport java.util.Arrays; 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer { 308fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 31887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; 328fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public static final int NOT_A_COORDINATE = -1; 33887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 3401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private static final int N = BinaryDictionary.MAX_WORD_LENGTH; 358fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 3601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private int[] mPrimaryKeyCodes; 37be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private int[] mXCoordinates; 38be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private int[] mYCoordinates; 39be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private StringBuilder mTypedWord; 40be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard private CharSequence mAutoCorrection; 414a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 42be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard // Cache these values for performance 434a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 441c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani private boolean mAutoCapitalized; 45117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard private int mTrailingSingleQuotesCount; 4601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private int mCodePointSize; 47c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 490b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 510b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 53979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 5401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes = new int[N]; 55be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord = new StringBuilder(N); 56be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates = new int[N]; 57be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mYCoordinates = new int[N]; 58be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 59117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 6001ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 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) { 6801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length); 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; 7601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 77979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 78979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 83be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 84be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 854a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 86ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 87117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 8801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 8901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok } 9001ab7c8b59a7f12862fbd95fb252e56719f1757fsatok 9101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok public final void refreshSize() { 9201ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length()); 93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 99ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka public final int size() { 10001ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return mCodePointSize; 101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 103196d82cdd740580ed79d801483dbc282be85d076Jean Chalard public final boolean isComposingWord() { 10401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return size() > 0; 105196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } 106196d82cdd740580ed79d801483dbc282be85d076Jean Chalard 10701ab7c8b59a7f12862fbd95fb252e56719f1757fsatok public int getCodeAt(int index) { 10801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return mPrimaryKeyCodes[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 124ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok // TODO: remove input keyDetector 125691f1c174b660f3bcfe1823d16e55990b4c829dasatok public void add(int primaryCode, int x, int y, KeyDetector keyDetector) { 126ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok final int[] codes; 127691f1c174b660f3bcfe1823d16e55990b4c829dasatok final int keyX; 128691f1c174b660f3bcfe1823d16e55990b4c829dasatok final int keyY; 129081616cd2f472295449268cecb570771b969cba3Jean Chalard if (null == keyDetector 130081616cd2f472295449268cecb570771b969cba3Jean Chalard || x == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE 131691f1c174b660f3bcfe1823d16e55990b4c829dasatok || y == KeyboardActionListener.SUGGESTION_STRIP_COORDINATE 132691f1c174b660f3bcfe1823d16e55990b4c829dasatok || x == KeyboardActionListener.NOT_A_TOUCH_COORDINATE 133691f1c174b660f3bcfe1823d16e55990b4c829dasatok || y == KeyboardActionListener.NOT_A_TOUCH_COORDINATE) { 134ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok codes = new int[] { primaryCode }; 135691f1c174b660f3bcfe1823d16e55990b4c829dasatok keyX = x; 136691f1c174b660f3bcfe1823d16e55990b4c829dasatok keyY = y; 137ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } else { 1381caff47ecdfcf413df709371a919cf9377e26bf7satok final Key key = keyDetector.detectHitKey(x, y); 139728d1c884e99e1fd25aa253b5ad30dbdb046ad5fsatok // TODO: Pass an integer instead of an integer array 1401caff47ecdfcf413df709371a919cf9377e26bf7satok codes = new int[] { key != null ? key.mCode : NOT_A_CODE }; 141691f1c174b660f3bcfe1823d16e55990b4c829dasatok keyX = keyDetector.getTouchX(x); 142853d9020edb058e39c46a6af1215dfcfeb865ad8satok keyY = keyDetector.getTouchY(y); 143ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 144ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok add(primaryCode, codes, keyX, keyY); 145ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 146ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok 147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of 149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the array containing unicode for adjacent keys, sorted by reducing probability/proximity. 150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param codes the array of unicode values 151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 152ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void add(int primaryCode, int[] codes, int keyX, int keyY) { 15301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final int newIndex = size(); 1549159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard mTypedWord.appendCodePoint(primaryCode); 15501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 15601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes[newIndex] = codes[0]; 157ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { 158ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mXCoordinates[newIndex] = keyX; 159ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mYCoordinates[newIndex] = keyY; 1608fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 161ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = isFirstCharCapitalized( 162ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka newIndex, primaryCode, mIsFirstCharCapitalized); 163ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(primaryCode)) mCapsCount++; 164117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) { 165117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 166117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } else { 167117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 168117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 169be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 1736b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Internal method to retrieve reasonable proximity info for a character. 1746b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 175a492790982c6d7df62f66344db30b31995800e1bJean Chalard private void addKeyInfo(final int codePoint, final Keyboard keyboard) { 1766b1f500da451de56932a8b2a99c63857994ece85Jean Chalard for (final Key key : keyboard.mKeys) { 1776b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (key.mCode == codePoint) { 1786b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int x = key.mX + key.mWidth / 2; 1796b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int y = key.mY + key.mHeight / 2; 180728d1c884e99e1fd25aa253b5ad30dbdb046ad5fsatok // TODO: Pass an integer instead of an integer array 181728d1c884e99e1fd25aa253b5ad30dbdb046ad5fsatok add(codePoint, new int[] { key.mCode }, x, y); 1826b1f500da451de56932a8b2a99c63857994ece85Jean Chalard return; 1836b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1846b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard add(codePoint, new int[] { codePoint }, 1866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); 1876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 1886b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 1896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 1906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Set the currently composing word to the one passed as an argument. 1916b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. 1926b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 193a492790982c6d7df62f66344db30b31995800e1bJean Chalard public void setComposingWord(final CharSequence word, final Keyboard keyboard) { 1946b1f500da451de56932a8b2a99c63857994ece85Jean Chalard reset(); 1956b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final int length = word.length(); 1969159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { 1979159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard int codePoint = Character.codePointAt(word, i); 198a492790982c6d7df62f66344db30b31995800e1bJean Chalard addKeyInfo(codePoint, keyboard); 1996b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2006b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 2016b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 2026b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Delete the last keystroke as a result of hitting backspace. 204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void deleteLast() { 20601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final int size = size(); 207ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (size > 0) { 2089159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs 2099159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard final int stringBuilderLength = mTypedWord.length(); 2109159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard if (stringBuilderLength < size) { 2119159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard throw new RuntimeException( 2129159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard "In WordComposer: mCodes and mTypedWords have non-matching lengths"); 2139159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard } 2149159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard final int lastChar = mTypedWord.codePointBefore(stringBuilderLength); 2159159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard if (Character.isSupplementaryCodePoint(lastChar)) { 2169159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength); 2179159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard } else { 2189159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard mTypedWord.deleteCharAt(stringBuilderLength - 1); 2199159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard } 220ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (Character.isUpperCase(lastChar)) mCapsCount--; 22101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 222d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka } 2239159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard // We may have deleted the last one. 22401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok if (0 == size()) { 225ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 226117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 227117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard if (mTrailingSingleQuotesCount > 0) { 228117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard --mTrailingSingleQuotesCount; 229c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } else { 230825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard int i = mTypedWord.length(); 231825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard while (i > 0) { 232825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard i = mTypedWord.offsetByCodePoints(i, -1); 233be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; 234117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ++mTrailingSingleQuotesCount; 235117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard } 2368fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 237be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 239923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 242117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * @return the word that was typed so far. Never returns null. 243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 2445c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 245be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mTypedWord.toString(); 246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 2520b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 2530b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2550b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 256117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard public int trailingSingleQuotesCount() { 257117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard return mTrailingSingleQuotesCount; 258c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } 259c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 2600b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 2610b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 2620b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 2630b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 2640b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 2650b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return (mCapsCount > 0) && (mCapsCount == size()); 2660b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 2670b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 2694a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 2704a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 2714a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 2724a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 2734a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 2741c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 2750fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard /** 2761c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Saves the reason why the word is capitalized - whether it was automatic or 2771c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * due to the user hitting shift in the middle of a sentence. 2781c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @param auto whether it was an automatic capitalization due to start of sentence 2791c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2801c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public void setAutoCapitalized(boolean auto) { 2811c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani mAutoCapitalized = auto; 2821c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 2831c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 2841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 2851c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 2861c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 2871c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 2881c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani public boolean isAutoCapitalized() { 2891c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani return mAutoCapitalized; 2901c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 291117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 292117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 293117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Sets the auto-correction for this word. 294117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 295117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public void setAutoCorrection(final CharSequence correction) { 296be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = correction; 297117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 298117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 299117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 300f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard * @return the auto-correction for this word, or null if none. 301117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 302117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard public CharSequence getAutoCorrectionOrNull() { 303be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mAutoCorrection; 304117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 305c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 306267563d1bb4d8091293fbd8774f0f95ef59f03c4Jean Chalard // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. 30766bb563535dbe3672f99f75bd71763a551444867Jean Chalard public LastComposedWord commitWord(final int type, final String committedWord, 30866bb563535dbe3672f99f75bd71763a551444867Jean Chalard final int separatorCode) { 3099271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK 3109271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate 3119271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // the last composed word to ensure this does not happen. 31201ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final int[] primaryKeyCodes = mPrimaryKeyCodes; 313a7f2500001c53dc5a6de9c2525a75229cc7c6645Jean Chalard final int[] xCoordinates = mXCoordinates; 314a7f2500001c53dc5a6de9c2525a75229cc7c6645Jean Chalard final int[] yCoordinates = mYCoordinates; 31501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes = new int[N]; 316a7f2500001c53dc5a6de9c2525a75229cc7c6645Jean Chalard mXCoordinates = new int[N]; 317a7f2500001c53dc5a6de9c2525a75229cc7c6645Jean Chalard mYCoordinates = new int[N]; 31801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, 31966bb563535dbe3672f99f75bd71763a551444867Jean Chalard xCoordinates, yCoordinates, mTypedWord.toString(), committedWord, separatorCode); 3209271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD 3219271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { 322449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard lastComposedWord.deactivate(); 323449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard } 324be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 32501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 326be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 3271f8fc62ccb5018716457dc309ab11ad3e1506ad1Jean Chalard return lastComposedWord; 328c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 329c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 3302712f23acbb197af3b125da4cc47108e71b7446dJean Chalard public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { 33101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; 332be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mXCoordinates = lastComposedWord.mXCoordinates; 333be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mYCoordinates = lastComposedWord.mYCoordinates; 334be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.setLength(0); 335be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mTypedWord.append(lastComposedWord.mTypedWord); 33601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok refreshSize(); 337cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. 3389e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard } 339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 340