WordComposer.java revision d52bec00695a6e43b8e8836112919c02952d4dcc
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 30fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at 70fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * 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 118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and 148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under 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 197ede642df417c0f732573f639970b138f0bee18cJean Chalardimport com.android.inputmethod.event.CombinerChain; 20f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport com.android.inputmethod.event.Event; 21f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport com.android.inputmethod.latin.utils.CollectionUtils; 22d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalardimport com.android.inputmethod.latin.utils.CoordinateUtils; 235fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalardimport com.android.inputmethod.latin.utils.StringUtils; 24887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 25f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport java.util.ArrayList; 26f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport java.util.Collections; 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 */ 31a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class WordComposer { 32ffcbbaf12788a9fc9398607a548e552d7d2bf05eSatoshi Kataoka private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; 330e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 348fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 35adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_OFF = 0; 36adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits 37adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // aren't used anywhere in the code 38adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_MANUAL_SHIFTED = 0x1; 39adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_MANUAL_SHIFT_LOCKED = 0x3; 40adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_AUTO_SHIFTED = 0x5; 41adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_AUTO_SHIFT_LOCKED = 0x7; 42adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard 437ede642df417c0f732573f639970b138f0bee18cJean Chalard private CombinerChain mCombinerChain; 447ede642df417c0f732573f639970b138f0bee18cJean Chalard 4575715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // An array of code points representing the characters typed so far. 4675715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // The array is limited to MAX_WORD_LENGTH code points, but mTypedWord extends past that 4775715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // and mCodePointSize can go past that. If mCodePointSize is greater than MAX_WORD_LENGTH, 4875715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // this just does not contain the associated code points past MAX_WORD_LENGTH. 4975715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard private int[] mPrimaryKeyCodes; 50f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard // The list of events that served to compose this string. 51f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard private final ArrayList<Event> mEvents; 5296b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); 532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // The previous word (before the composing word). Used as context for suggestions. May be null 542fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // after resetting and before starting a new composing word, or when there is no context like 557cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard // at the start of text for example. It can also be set to null externally when the user 567cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard // enters a separator that does not let bigrams across, like a period or a comma. 577cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard private String mPreviousWordForSuggestion; 58bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String mAutoCorrection; 594b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard private boolean mIsResumed; 60d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka private boolean mIsBatchMode; 61d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // A memory of the last rejected batch mode suggestion, if any. This goes like this: the user 62d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // gestures a word, is displeased with the results and hits backspace, then gestures again. 63d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // At the very least we should avoid re-suggesting the same thing, and to do that we memorize 64d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // the rejected suggestion in this variable. 65d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // TODO: this should be done in a comprehensive way by the User History feature instead of 66d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // as an ad-hockery here. 67d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard private String mRejectedBatchModeSuggestion; 684a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 69be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard // Cache these values for performance 703285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard private CharSequence mTypedWordCache; 714a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 72e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard private int mDigitsCount; 73adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard private int mCapitalizedMode; 74117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard private int mTrailingSingleQuotesCount; 755fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // This is the number of code points entered so far. This is not limited to MAX_WORD_LENGTH. 765fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // In general, this contains the size of mPrimaryKeyCodes, except when this is greater than 775fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // MAX_WORD_LENGTH in which case mPrimaryKeyCodes only contain the first MAX_WORD_LENGTH 785fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // code points. 7901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private int mCodePointSize; 806a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard private int mCursorPositionWithinWord; 81c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 830b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether the user chose to capitalize the first char of the word. 84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 850b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa private boolean mIsFirstCharCapitalized; 86923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 87979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 887ede642df417c0f732573f639970b138f0bee18cJean Chalard mCombinerChain = new CombinerChain(); 8975715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard mPrimaryKeyCodes = new int[MAX_WORD_LENGTH]; 90f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents = CollectionUtils.newArrayList(); 91be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 92117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 934b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 94d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = false; 956a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 96d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 977cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard mPreviousWordForSuggestion = null; 983285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 99923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 105cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 106f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents.clear(); 107be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 1084a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 109e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = 0; 110ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka mIsFirstCharCapitalized = false; 111117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard mTrailingSingleQuotesCount = 0; 1124b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 113d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = false; 1146a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 115d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 1167cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard mPreviousWordForSuggestion = null; 1173285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 11801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok } 11901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok 1203285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard private final void refreshTypedWordCache() { 1213285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard mTypedWordCache = mCombinerChain.getComposingWordWithCombiningFeedback(); 1223285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard mCodePointSize = Character.codePointCount(mTypedWordCache, 0, mTypedWordCache.length()); 123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 12970d9152c7f9e06d7d02dbbcb53af5c8f19d16b8dJean Chalard // This may be made public if need be, but right now it's not used anywhere 13070d9152c7f9e06d7d02dbbcb53af5c8f19d16b8dJean Chalard /* package for tests */ int size() { 13101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return mCodePointSize; 132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 13470d9152c7f9e06d7d02dbbcb53af5c8f19d16b8dJean Chalard public boolean isSingleLetter() { 13570d9152c7f9e06d7d02dbbcb53af5c8f19d16b8dJean Chalard return size() == 1; 13670d9152c7f9e06d7d02dbbcb53af5c8f19d16b8dJean Chalard } 13770d9152c7f9e06d7d02dbbcb53af5c8f19d16b8dJean Chalard 1388e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard // When the composition contains trailing quotes, we don't pass them to the suggestion engine. 1398e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard // This is because "'tgis'" should be corrected to "'this'", but we can't afford to consider 1408e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard // single quotes as separators because of their very common use as apostrophes. 1418e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard public int sizeWithoutTrailingSingleQuotes() { 1428e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard return size() - mTrailingSingleQuotesCount; 1438e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard } 1448e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard 145196d82cdd740580ed79d801483dbc282be85d076Jean Chalard public final boolean isComposingWord() { 14601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return size() > 0; 147196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } 148196d82cdd740580ed79d801483dbc282be85d076Jean Chalard 14975715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // TODO: make sure that the index should not exceed MAX_WORD_LENGTH 15075715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard public int getCodeAt(int index) { 15175715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard if (index >= MAX_WORD_LENGTH) { 15275715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard return -1; 15375715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard } 15475715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard return mPrimaryKeyCodes[index]; 15575715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard } 15675715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard 15771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka public InputPointers getInputPointers() { 15871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka return mInputPointers; 1598fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1608fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 161bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private static boolean isFirstCharCapitalized(final int index, final int codePoint, 162bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final boolean previous) { 163ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka if (index == 0) return Character.isUpperCase(codePoint); 164436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka return previous && !Character.isUpperCase(codePoint); 165ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka } 166ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka 167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 168d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * Process an input event. 169d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * 170d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * All input events should be supported, including software/hardware events, characters as well 171d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * as deletions, multiple inputs and gestures. 172d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * 173d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * @param event the event to process. 174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 175d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard public void processEvent(final Event event) { 176dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int primaryCode = event.mCodePoint; 177dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int keyX = event.mX; 178dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int keyY = event.mY; 179dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int newIndex = size(); 1800f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard mCombinerChain.processEvent(mEvents, event); 1810f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard mEvents.add(event); 1820f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard refreshTypedWordCache(); 183dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard mCursorPositionWithinWord = mCodePointSize; 184dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard // We may have deleted the last one. 185dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard if (0 == mCodePointSize) { 186dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard mIsFirstCharCapitalized = false; 187dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard } 1883e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard if (Constants.CODE_DELETE == event.mKeyCode) { 1893e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard if (mTrailingSingleQuotesCount > 0) { 1903e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard --mTrailingSingleQuotesCount; 1913e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } else { 1923e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard // Delete, but we didn't end in a quote: must recompute mTrailingSingleQuotesCount 1933e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard // We're only searching for single quotes, so no need to account for code points 1943e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard for (int i = mTypedWordCache.length() - 1; i > 0; --i) { 1953e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard if (Constants.CODE_SINGLE_QUOTE != mTypedWordCache.charAt(i)) { 1963e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard break; 1973e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } 1983e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard ++mTrailingSingleQuotesCount; 1993e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } 2003e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } 2013e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } else { 2023e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard if (Constants.CODE_SINGLE_QUOTE == primaryCode) { 2033e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard ++mTrailingSingleQuotesCount; 2043e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } else { 2053e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard mTrailingSingleQuotesCount = 0; 2063e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } 207633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (newIndex < MAX_WORD_LENGTH) { 208633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard mPrimaryKeyCodes[newIndex] = primaryCode >= Constants.CODE_SPACE 209633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard ? Character.toLowerCase(primaryCode) : primaryCode; 210633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // In the batch input mode, the {@code mInputPointers} holds batch input points and 211633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // shouldn't be overridden by the "typed key" coordinates 212633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // (See {@link #setBatchInputWord}). 213633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (!mIsBatchMode) { 214633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // TODO: Set correct pointer id and time 215633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); 216633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard } 217633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard } 218633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard mIsFirstCharCapitalized = isFirstCharCapitalized( 219633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard newIndex, primaryCode, mIsFirstCharCapitalized); 220633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (Character.isUpperCase(primaryCode)) mCapsCount++; 221633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (Character.isDigit(primaryCode)) mDigitsCount++; 2223e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } 223dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard mAutoCorrection = null; 2240f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard } 2250f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard 2266a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard public void setCursorPositionWithinWord(final int posWithinWord) { 2276a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = posWithinWord; 228f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard // TODO: compute where that puts us inside the events 2296a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 2306a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 2310e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard public boolean isCursorFrontOrMiddleOfComposingWord() { 2320e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (DBG && mCursorPositionWithinWord > mCodePointSize) { 2330e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard throw new RuntimeException("Wrong cursor position : " + mCursorPositionWithinWord 2340e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard + "in a word of size " + mCodePointSize); 2350e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 2360e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard return mCursorPositionWithinWord != mCodePointSize; 2376a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 2386a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 239f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard /** 240f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * When the cursor is moved by the user, we need to update its position. 241f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * If it falls inside the currently composing word, we don't reset the composition, and 242f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * only update the cursor position. 243f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * 244f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * @param expectedMoveAmount How many java chars to move the cursor. Negative values move 245f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * the cursor backward, positive values move the cursor forward. 246f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * @return true if the cursor is still inside the composing word, false otherwise. 247f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard */ 248f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) { 249cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard // TODO: should uncommit the composing feedback 250cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 251f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard int actualMoveAmountWithinWord = 0; 252f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard int cursorPos = mCursorPositionWithinWord; 25375715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard final int[] codePoints; 25475715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard if (mCodePointSize >= MAX_WORD_LENGTH) { 25575715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // If we have more than MAX_WORD_LENGTH characters, we don't have everything inside 25675715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // mPrimaryKeyCodes. This should be rare enough that we can afford to just compute 25775715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard // the array on the fly when this happens. 2583285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard codePoints = StringUtils.toCodePointArray(mTypedWordCache); 25975715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard } else { 26075715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard codePoints = mPrimaryKeyCodes; 26175715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard } 262f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard if (expectedMoveAmount >= 0) { 263f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // Moving the cursor forward for the expected amount or until the end of the word has 264f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // been reached, whichever comes first. 265f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard while (actualMoveAmountWithinWord < expectedMoveAmount && cursorPos < mCodePointSize) { 2665fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard actualMoveAmountWithinWord += Character.charCount(codePoints[cursorPos]); 267f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard ++cursorPos; 268f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 269f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } else { 270f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // Moving the cursor backward for the expected amount or until the start of the word 271f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // has been reached, whichever comes first. 272f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard while (actualMoveAmountWithinWord > expectedMoveAmount && cursorPos > 0) { 273f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard --cursorPos; 2745fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard actualMoveAmountWithinWord -= Character.charCount(codePoints[cursorPos]); 275f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 276f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 277f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // If the actual and expected amounts differ, we crossed the start or the end of the word 278f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // so the result would not be inside the composing word. 279f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard if (actualMoveAmountWithinWord != expectedMoveAmount) return false; 280f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard mCursorPositionWithinWord = cursorPos; 281f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard return true; 282f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 283f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard 284bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setBatchInputPointers(final InputPointers batchPointers) { 285eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mInputPointers.set(batchPointers); 286d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = true; 287d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka } 288d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka 289bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setBatchInputWord(final String word) { 290eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang reset(); 291eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mIsBatchMode = true; 292eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int length = word.length(); 293eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { 294eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int codePoint = Character.codePointAt(word, i); 295eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // We don't want to override the batch input points that are held in mInputPointers 296eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // (See {@link #add(int,int,int)}). 297d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); 298eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 299eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 300eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 3026b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Set the currently composing word to the one passed as an argument. 3036b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. 304d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard * @param codePoints the code points to set as the composing word. 305d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard * @param coordinates the x, y coordinates of the key in the CoordinateUtils format 3062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @param previousWord the previous word, to use as context for suggestions. Can be null if 3072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * the context is nil (typically, at start of text). 3086b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 309d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard public void setComposingWord(final int[] codePoints, final int[] coordinates, 3101284e556f4ec998c6f3ea80905d690cbb4c9dc82Jean Chalard final CharSequence previousWord) { 3116b1f500da451de56932a8b2a99c63857994ece85Jean Chalard reset(); 312d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard final int length = codePoints.length; 313d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard for (int i = 0; i < length; ++i) { 314d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], 315f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard CoordinateUtils.xFromArray(coordinates, i), 316f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard CoordinateUtils.yFromArray(coordinates, i))); 3176b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 3184b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = true; 3194752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString(); 3206b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 3216b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 3226b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 324117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * @return the word that was typed so far. Never returns null. 325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 3265c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 3273285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard return mTypedWordCache.toString(); 328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 3307cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard public String getPreviousWordForSuggestion() { 3317cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard return mPreviousWordForSuggestion; 3322fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 334923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 335923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Whether or not the user typed a capital letter as the first letter in the word 336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 337923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 3380b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isFirstCharCapitalized() { 3390b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa return mIsFirstCharCapitalized; 340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 3410b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 342117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard public int trailingSingleQuotesCount() { 343117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard return mTrailingSingleQuotesCount; 344c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard } 345c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 3460b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 3470b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 3480b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 3490b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 3500b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 351ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard if (size() <= 1) { 352ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED 353ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED; 354ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard } else { 355ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard return mCapsCount == size(); 356ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard } 3571eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard } 3581eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard 3591eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard public boolean wasShiftedNoLock() { 3601eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFTED 3611eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFTED; 3620b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 3630b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 364923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 3654a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 3664a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 3674a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 3684a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 3694a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 3701c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 3710fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard /** 372e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard * Returns true if we have digits in the composing word. 373e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard */ 374e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard public boolean hasDigits() { 375e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard return mDigitsCount > 0; 376e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard } 377e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard 378e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard /** 3792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * Saves the caps mode and the previous word at the start of composing. 380adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * 3812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * WordComposer needs to know about the caps mode for several reasons. The first is, we need 3822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * to know after the fact what the reason was, to register the correct form into the user 3832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * history dictionary: if the word was automatically capitalized, we should insert it in 3842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * all-lower case but if it's a manual pressing of shift, then it should be inserted as is. 385adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * Also, batch input needs to know about the current caps mode to display correctly 386adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * capitalized suggestions. 387adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * @param mode the mode at the time of start 3882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * @param previousWord the previous word as context for suggestions. May be null if none. 3891c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 3902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode, 3914752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard final CharSequence previousWord) { 392adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mCapitalizedMode = mode; 3934752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard mPreviousWordForSuggestion = null == previousWord ? null : previousWord.toString(); 3941c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 3951c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 3961c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 3971c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 3981c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 3991c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 400adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public boolean wasAutoCapitalized() { 401adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED 402adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard || mCapitalizedMode == CAPS_MODE_AUTO_SHIFTED; 4031c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 404117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 405117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 406117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Sets the auto-correction for this word. 407117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 408bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setAutoCorrection(final String correction) { 409be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = correction; 410117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 411117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 412117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 413f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard * @return the auto-correction for this word, or null if none. 414117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 415bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public String getAutoCorrectionOrNull() { 416be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mAutoCorrection; 417117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 418c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 4194b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard /** 4204b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard * @return whether we started composing this word by resuming suggestion on an existing string 4214b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard */ 4224b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard public boolean isResumed() { 4234b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard return mIsResumed; 4244b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard } 4254b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard 426267563d1bb4d8091293fbd8774f0f95ef59f03c4Jean Chalard // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. 4274752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard // committedWord should contain suggestion spans if applicable. 4284752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard public LastComposedWord commitWord(final int type, final CharSequence committedWord, 429bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String separatorString, final String prevWord) { 4309271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK 4319271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate 4329271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // the last composed word to ensure this does not happen. 43375715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard final int[] primaryKeyCodes = mPrimaryKeyCodes; 43475715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard mPrimaryKeyCodes = new int[MAX_WORD_LENGTH]; 43575715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes, mEvents, 4363285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard mInputPointers, mTypedWordCache.toString(), committedWord, separatorString, 437b6b7f5e39e9ea1bf9a05203c536327a6be7e7214Jean Chalard prevWord, mCapitalizedMode); 43871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.reset(); 4399271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD 4409271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { 441449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard lastComposedWord.deactivate(); 442449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard } 443e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mCapsCount = 0; 444e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = 0; 445e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mIsBatchMode = false; 4464752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard mPreviousWordForSuggestion = committedWord.toString(); 447cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 448f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents.clear(); 4498914555776a4d3dfd6afc4926a69169ca1c82a0eJean Chalard mCodePointSize = 0; 4502a37fb9d30848aee42757546e8478cb7a9e45bc6Jean Chalard mTrailingSingleQuotesCount = 0; 451e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mIsFirstCharCapitalized = false; 4528914555776a4d3dfd6afc4926a69169ca1c82a0eJean Chalard mCapitalizedMode = CAPS_MODE_OFF; 4533285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 454be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 4556a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 4564b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 457d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 4581f8fc62ccb5018716457dc309ab11ad3e1506ad1Jean Chalard return lastComposedWord; 459c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 460fae1ba767ca177510adc08b363987f67bbf40d90Jean Chalard 4617cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard // Call this when the recorded previous word should be discarded. This is typically called 4627cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard // when the user inputs a separator that's not whitespace (including the case of the 4637cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard // double-space-to-period feature). 4647cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard public void discardPreviousWordForSuggestion() { 4657cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard mPreviousWordForSuggestion = null; 466fae1ba767ca177510adc08b363987f67bbf40d90Jean Chalard } 467c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 4682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, 4692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final String previousWord) { 47075715f7d9fb0b19c2ddaf73bf62148c7d19f0a99Jean Chalard mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; 471f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents.clear(); 472f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard Collections.copy(mEvents, lastComposedWord.mEvents); 47371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.set(lastComposedWord.mInputPointers); 474cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 4753285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 476b6b7f5e39e9ea1bf9a05203c536327a6be7e7214Jean Chalard mCapitalizedMode = lastComposedWord.mCapitalizedMode; 477cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. 4786a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = mCodePointSize; 479d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 4804b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = true; 4817cd7cf73f4ce6f0e577d6382eb0fc25f60dc63e1Jean Chalard mPreviousWordForSuggestion = previousWord; 4829e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard } 483d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka 484d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka public boolean isBatchMode() { 485d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka return mIsBatchMode; 486d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka } 487d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard 488d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard public void setRejectedBatchModeSuggestion(final String rejectedSuggestion) { 489d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = rejectedSuggestion; 490d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard } 491d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard 492d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard public String getRejectedBatchModeSuggestion() { 493d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard return mRejectedBatchModeSuggestion; 494d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard } 495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 496