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 19b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheikimport com.android.inputmethod.annotations.UsedForTesting; 207ede642df417c0f732573f639970b138f0bee18cJean Chalardimport com.android.inputmethod.event.CombinerChain; 21f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport com.android.inputmethod.event.Event; 22176ad53c6fee47df7595e7501e7e2829d990364dJean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 23ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalardimport com.android.inputmethod.latin.common.ComposedData; 249342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants; 255b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.CoordinateUtils; 2636799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardimport com.android.inputmethod.latin.common.InputPointers; 274beeb9253a06482299e0c67467531d30436a02fcJean Chalardimport com.android.inputmethod.latin.common.StringUtils; 282dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaokaimport com.android.inputmethod.latin.define.DebugFlags; 290f7d881dc72132dfd75c8b4fe61a69fc5cdcd460Mohammadinamul Sheikimport com.android.inputmethod.latin.define.DecoderSpecificConstants; 30887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka 31f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport java.util.ArrayList; 32f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalardimport java.util.Collections; 33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 347f545a57c987862d55966ac08ef64cfe0b9f51e4Ken Wakasaimport javax.annotation.Nonnull; 357f545a57c987862d55966ac08ef64cfe0b9f51e4Ken Wakasa 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well 38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 39a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class WordComposer { 400f7d881dc72132dfd75c8b4fe61a69fc5cdcd460Mohammadinamul Sheik private static final int MAX_WORD_LENGTH = DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; 412dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaoka private static final boolean DBG = DebugFlags.DEBUG_ENABLED; 428fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 43adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_OFF = 0; 44adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // 1 is shift bit, 2 is caps bit, 4 is auto bit but this is just a convention as these bits 45adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // aren't used anywhere in the code 46adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_MANUAL_SHIFTED = 0x1; 47adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_MANUAL_SHIFT_LOCKED = 0x3; 48adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_AUTO_SHIFTED = 0x5; 49adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public static final int CAPS_MODE_AUTO_SHIFT_LOCKED = 0x7; 50adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard 517ede642df417c0f732573f639970b138f0bee18cJean Chalard private CombinerChain mCombinerChain; 52be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard private String mCombiningSpec; // Memory so that we don't uselessly recreate the combiner chain 537ede642df417c0f732573f639970b138f0bee18cJean Chalard 54f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard // The list of events that served to compose this string. 55f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard private final ArrayList<Event> mEvents; 5696b22200beb98fd1a6288f4cf53e38611a09cdd0Ken Wakasa private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH); 57176ad53c6fee47df7595e7501e7e2829d990364dJean Chalard private SuggestedWordInfo mAutoCorrection; 584b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard private boolean mIsResumed; 59d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka private boolean mIsBatchMode; 60d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // A memory of the last rejected batch mode suggestion, if any. This goes like this: the user 61d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // gestures a word, is displeased with the results and hits backspace, then gestures again. 62d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // At the very least we should avoid re-suggesting the same thing, and to do that we memorize 63d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // the rejected suggestion in this variable. 64d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // TODO: this should be done in a comprehensive way by the User History feature instead of 65d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard // as an ad-hockery here. 66d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard private String mRejectedBatchModeSuggestion; 674a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 68be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard // Cache these values for performance 693285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard private CharSequence mTypedWordCache; 704a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani private int mCapsCount; 71e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard private int mDigitsCount; 72adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard private int mCapitalizedMode; 735fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // This is the number of code points entered so far. This is not limited to MAX_WORD_LENGTH. 745fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // In general, this contains the size of mPrimaryKeyCodes, except when this is greater than 755fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // MAX_WORD_LENGTH in which case mPrimaryKeyCodes only contain the first MAX_WORD_LENGTH 765fa2202e36a84bd5808fa10ca25c9179acb1b173Jean Chalard // code points. 7701ab7c8b59a7f12862fbd95fb252e56719f1757fsatok private int mCodePointSize; 786a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard private int mCursorPositionWithinWord; 79c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard 80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 81367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard * Whether the composing word has the only first char capitalized. 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 83367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard private boolean mIsOnlyFirstCharCapitalized; 84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 85979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public WordComposer() { 865ce39dfa782031fd53af167c0fd9a9bc63d21149Jean Chalard mCombinerChain = new CombinerChain(""); 87a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka mEvents = new ArrayList<>(); 88be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 894b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 90d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = false; 916a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 92d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 933285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 96ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalard public ComposedData getComposedDataSnapshot() { 97ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalard return new ComposedData(getInputPointers(), isBatchMode(), mTypedWordCache.toString()); 98ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalard } 99ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalard 100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 1015ce39dfa782031fd53af167c0fd9a9bc63d21149Jean Chalard * Restart the combiners, possibly with a new spec. 102be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard * @param combiningSpec The spec string for combining. This is found in the extra value. 103be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard */ 1045ce39dfa782031fd53af167c0fd9a9bc63d21149Jean Chalard public void restartCombining(final String combiningSpec) { 105be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard final String nonNullCombiningSpec = null == combiningSpec ? "" : combiningSpec; 1065ce39dfa782031fd53af167c0fd9a9bc63d21149Jean Chalard if (!nonNullCombiningSpec.equals(mCombiningSpec)) { 1075ce39dfa782031fd53af167c0fd9a9bc63d21149Jean Chalard mCombinerChain = new CombinerChain( 108e1758feeffa388f2b75040e8f54b466c3591a148Dan Zivkovic mCombinerChain.getComposingWordWithCombiningFeedback().toString()); 109be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard mCombiningSpec = nonNullCombiningSpec; 110be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard } 111be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard } 112be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard 113be99616afa2243fe48dc406d0a3f442cb05453b4Jean Chalard /** 114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Clear out the keys registered so far. 115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void reset() { 117cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 118f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents.clear(); 119be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 1204a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani mCapsCount = 0; 121e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = 0; 122367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard mIsOnlyFirstCharCapitalized = false; 1234b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 124d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = false; 1256a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 126d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 1273285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 12801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok } 12901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok 1303285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard private final void refreshTypedWordCache() { 1313285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard mTypedWordCache = mCombinerChain.getComposingWordWithCombiningFeedback(); 1323285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard mCodePointSize = Character.codePointCount(mTypedWordCache, 0, mTypedWordCache.length()); 133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 136923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Number of keystrokes in the composing word. 137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return the number of keystrokes 138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 139c92c883fdf2287b49392692fa2e8d109dc26f785David Faden public int size() { 14001ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return mCodePointSize; 141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1435f430e0189f6c0a1a34edb0e00809bc53a525a7bJean Chalard public boolean isSingleLetter() { 1445f430e0189f6c0a1a34edb0e00809bc53a525a7bJean Chalard return size() == 1; 1458e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard } 1468e829c37dff9fb5eec62390bf0e2c6f12fd6781bJean Chalard 147196d82cdd740580ed79d801483dbc282be85d076Jean Chalard public final boolean isComposingWord() { 14801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok return size() > 0; 149196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } 150196d82cdd740580ed79d801483dbc282be85d076Jean Chalard 15171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka public InputPointers getInputPointers() { 15271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka return mInputPointers; 1538fbd55229243cb66c03d5ea1f79dfb39f596590dsatok } 1548fbd55229243cb66c03d5ea1f79dfb39f596590dsatok 155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 1567196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard * Process an event and return an event, and return a processed event to apply. 1577196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard * @param event the unprocessed event. 1588e38b12e9ccc48bcb18b2eeec4d53d19cf7a29c9Jean Chalard * @return the processed event. Never null, but may be marked as consumed. 1597196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard */ 1607f545a57c987862d55966ac08ef64cfe0b9f51e4Ken Wakasa @Nonnull 161d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka public Event processEvent(@Nonnull final Event event) { 1627196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard final Event processedEvent = mCombinerChain.processEvent(mEvents, event); 163e0bad8e988a23553181fb670f8a2589a79f22c40Jean Chalard // The retained state of the combiner chain may have changed while processing the event, 164e0bad8e988a23553181fb670f8a2589a79f22c40Jean Chalard // so we need to update our cache. 165e0bad8e988a23553181fb670f8a2589a79f22c40Jean Chalard refreshTypedWordCache(); 1667196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard mEvents.add(event); 1677196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard return processedEvent; 1687196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard } 1697196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard 1707196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard /** 1717196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard * Apply a processed input event. 172d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * 173d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * All input events should be supported, including software/hardware events, characters as well 174d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * as deletions, multiple inputs and gestures. 175d52bec00695a6e43b8e8836112919c02952d4dccJean Chalard * 1768e38b12e9ccc48bcb18b2eeec4d53d19cf7a29c9Jean Chalard * @param event the event to apply. Must not be null. 177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 1787196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard public void applyProcessedEvent(final Event event) { 1798e38b12e9ccc48bcb18b2eeec4d53d19cf7a29c9Jean Chalard mCombinerChain.applyProcessedEvent(event); 180dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int primaryCode = event.mCodePoint; 181dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int keyX = event.mX; 182dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int keyY = event.mY; 183dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard final int newIndex = size(); 1840f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard refreshTypedWordCache(); 185dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard mCursorPositionWithinWord = mCodePointSize; 186dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard // We may have deleted the last one. 187dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard if (0 == mCodePointSize) { 188367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard mIsOnlyFirstCharCapitalized = false; 189dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard } 1901ef9d5938e671ce7a9d5c29d95c1364d6d6249eaJean Chalard if (Constants.CODE_DELETE != event.mKeyCode) { 191633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (newIndex < MAX_WORD_LENGTH) { 192633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // In the batch input mode, the {@code mInputPointers} holds batch input points and 193633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // shouldn't be overridden by the "typed key" coordinates 194633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // (See {@link #setBatchInputWord}). 195633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (!mIsBatchMode) { 196633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard // TODO: Set correct pointer id and time 197633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0); 198633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard } 199633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard } 200367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard if (0 == newIndex) { 201367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard mIsOnlyFirstCharCapitalized = Character.isUpperCase(primaryCode); 202367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard } else { 203367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard mIsOnlyFirstCharCapitalized = mIsOnlyFirstCharCapitalized 204367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard && !Character.isUpperCase(primaryCode); 205367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard } 206633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (Character.isUpperCase(primaryCode)) mCapsCount++; 207633e4f45330cf32d76c29d999b723ddeafd3a90cJean Chalard if (Character.isDigit(primaryCode)) mDigitsCount++; 2083e160bbe6b91c2d50a410ebd28e10f3e58b2c73aJean Chalard } 209dfaeb125eb27172e4d38e1e5a87a13a3320c1e82Jean Chalard mAutoCorrection = null; 2100f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard } 2110f913ff5ba71c40a4492994a23010336cd25be8eJean Chalard 2126a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard public void setCursorPositionWithinWord(final int posWithinWord) { 2136a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = posWithinWord; 214f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard // TODO: compute where that puts us inside the events 2156a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 2166a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 2170e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard public boolean isCursorFrontOrMiddleOfComposingWord() { 2180e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (DBG && mCursorPositionWithinWord > mCodePointSize) { 2190e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard throw new RuntimeException("Wrong cursor position : " + mCursorPositionWithinWord 2200e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard + "in a word of size " + mCodePointSize); 2210e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 2220e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard return mCursorPositionWithinWord != mCodePointSize; 2236a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 2246a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 225f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard /** 226f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * When the cursor is moved by the user, we need to update its position. 227f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * If it falls inside the currently composing word, we don't reset the composition, and 228f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * only update the cursor position. 229f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * 230f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * @param expectedMoveAmount How many java chars to move the cursor. Negative values move 231f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * the cursor backward, positive values move the cursor forward. 232f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard * @return true if the cursor is still inside the composing word, false otherwise. 233f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard */ 234f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) { 23569c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic int actualMoveAmount = 0; 236f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard int cursorPos = mCursorPositionWithinWord; 2371ef9d5938e671ce7a9d5c29d95c1364d6d6249eaJean Chalard // TODO: Don't make that copy. We can do this directly from mTypedWordCache. 2381ef9d5938e671ce7a9d5c29d95c1364d6d6249eaJean Chalard final int[] codePoints = StringUtils.toCodePointArray(mTypedWordCache); 239f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard if (expectedMoveAmount >= 0) { 240f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // Moving the cursor forward for the expected amount or until the end of the word has 241f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // been reached, whichever comes first. 24269c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic while (actualMoveAmount < expectedMoveAmount && cursorPos < codePoints.length) { 24369c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic actualMoveAmount += Character.charCount(codePoints[cursorPos]); 244f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard ++cursorPos; 245f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 246f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } else { 247f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // Moving the cursor backward for the expected amount or until the start of the word 248f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // has been reached, whichever comes first. 24969c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic while (actualMoveAmount > expectedMoveAmount && cursorPos > 0) { 250f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard --cursorPos; 25169c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic actualMoveAmount -= Character.charCount(codePoints[cursorPos]); 252f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 253f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 254f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // If the actual and expected amounts differ, we crossed the start or the end of the word 255f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard // so the result would not be inside the composing word. 25669c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic if (actualMoveAmount != expectedMoveAmount) { 25769c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic return false; 25869c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic } 259f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard mCursorPositionWithinWord = cursorPos; 26069c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic mCombinerChain.applyProcessedEvent(mCombinerChain.processEvent( 26169c04cadc7c017f9de53f13ea045347b80316d4aDan Zivkovic mEvents, Event.createCursorMovedEvent(cursorPos))); 262f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard return true; 263f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard } 264f0af452ce261590b5978a1bb679ce27b71f9dc70Jean Chalard 265bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setBatchInputPointers(final InputPointers batchPointers) { 266eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mInputPointers.set(batchPointers); 267d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka mIsBatchMode = true; 268d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka } 269d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka 270bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void setBatchInputWord(final String word) { 271eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang reset(); 272eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mIsBatchMode = true; 273eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int length = word.length(); 274eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { 275eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int codePoint = Character.codePointAt(word, i); 276eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // We don't want to override the batch input points that are held in mInputPointers 277eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // (See {@link #add(int,int,int)}). 2787196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard final Event processedEvent = 2797196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard processEvent(Event.createEventForCodePointFromUnknownSource(codePoint)); 2807196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard applyProcessedEvent(processedEvent); 281eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 282eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 283eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 2856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Set the currently composing word to the one passed as an argument. 2866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity. 287d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard * @param codePoints the code points to set as the composing word. 288d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard * @param coordinates the x, y coordinates of the key in the CoordinateUtils format 2896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 290367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard public void setComposingWord(final int[] codePoints, final int[] coordinates) { 2916b1f500da451de56932a8b2a99c63857994ece85Jean Chalard reset(); 292d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard final int length = codePoints.length; 293d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard for (int i = 0; i < length; ++i) { 2947196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard final Event processedEvent = 2957196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard processEvent(Event.createEventForCodePointFromAlreadyTypedText(codePoints[i], 296f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard CoordinateUtils.xFromArray(coordinates, i), 297f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard CoordinateUtils.yFromArray(coordinates, i))); 2987196566d4f2048a4160acc6271ccb26c73d6fcd6Jean Chalard applyProcessedEvent(processedEvent); 2996b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 3004b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = true; 3016b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 3026b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 3036b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Returns the word as it was typed, without any correction applied. 305117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * @return the word that was typed so far. Never returns null. 306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 3075c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard public String getTypedWord() { 3083285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard return mTypedWordCache.toString(); 309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 312deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * Whether this composer is composing or about to compose a word in which only the first letter 313deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * is a capital. 314deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * 315deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * If we do have a composing word, we just return whether the word has indeed only its first 316deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * character capitalized. If we don't, then we return a value based on the capitalized mode, 317deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * which tell us what is likely to happen for the next composing word. 318deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * 319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @return capitalization preference 320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 321deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard public boolean isOrWillBeOnlyFirstCharCapitalized() { 322deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard return isComposingWord() ? mIsOnlyFirstCharCapitalized 323deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard : (CAPS_MODE_OFF != mCapitalizedMode); 324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 3250b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 3260b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa /** 3270b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * Whether or not all of the user typed chars are upper case 3280b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa * @return true if all user typed chars are upper case, false otherwise 3290b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa */ 3300b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa public boolean isAllUpperCase() { 331ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard if (size() <= 1) { 332ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED 333ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFT_LOCKED; 334ad0642cf258ca9b123f74ca0ae8bf970792908f1Jean Chalard } 3355f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka return mCapsCount == size(); 3361eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard } 3371eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard 3381eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard public boolean wasShiftedNoLock() { 3391eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFTED 3401eba97d92fb5caa4f23425837b6680ccc2a23ae8Jean Chalard || mCapitalizedMode == CAPS_MODE_MANUAL_SHIFTED; 3410b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa } 3420b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa 343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 3444a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani * Returns true if more than one character is upper case, otherwise returns false. 3454a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani */ 3464a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani public boolean isMostlyCaps() { 3474a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani return mCapsCount > 1; 3484a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani } 3491c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 3500fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard /** 351e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard * Returns true if we have digits in the composing word. 352e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard */ 353e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard public boolean hasDigits() { 354e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard return mDigitsCount > 0; 355e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard } 356e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard 357e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard /** 358367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard * Saves the caps mode at the start of composing. 359adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * 3602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * WordComposer needs to know about the caps mode for several reasons. The first is, we need 3612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * to know after the fact what the reason was, to register the correct form into the user 3622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * history dictionary: if the word was automatically capitalized, we should insert it in 3632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * all-lower case but if it's a manual pressing of shift, then it should be inserted as is. 364adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * Also, batch input needs to know about the current caps mode to display correctly 365adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * capitalized suggestions. 366adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard * @param mode the mode at the time of start 3671c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 368367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard public void setCapitalizedModeAtStartComposingTime(final int mode) { 369adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mCapitalizedMode = mode; 3701c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 3711c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 3721c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani /** 373deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * Before fetching suggestions, we don't necessarily know about the capitalized mode yet. 374deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * 375deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * If we don't have a composing word yet, we take a note of this mode so that we can then 376deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * supply this information to the suggestion process. If we have a composing word, then 377deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * the previous mode has priority over this. 378deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard * @param mode the mode just before fetching suggestions 379deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard */ 380deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard public void adviseCapitalizedModeBeforeFetchingSuggestions(final int mode) { 381deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard if (!isComposingWord()) { 382deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard mCapitalizedMode = mode; 383deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard } 384deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard } 385deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard 386deccc23564304b11d58590041f25adffdf6e1b6aJean Chalard /** 3871c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * Returns whether the word was automatically capitalized. 3881c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani * @return whether the word was automatically capitalized 3891c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani */ 390adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard public boolean wasAutoCapitalized() { 391adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return mCapitalizedMode == CAPS_MODE_AUTO_SHIFT_LOCKED 392adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard || mCapitalizedMode == CAPS_MODE_AUTO_SHIFTED; 3931c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 394117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 395117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 396117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard * Sets the auto-correction for this word. 397117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 398176ad53c6fee47df7595e7501e7e2829d990364dJean Chalard public void setAutoCorrection(final SuggestedWordInfo autoCorrection) { 399176ad53c6fee47df7595e7501e7e2829d990364dJean Chalard mAutoCorrection = autoCorrection; 400117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 401117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard 402117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard /** 403f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard * @return the auto-correction for this word, or null if none. 404117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard */ 405176ad53c6fee47df7595e7501e7e2829d990364dJean Chalard public SuggestedWordInfo getAutoCorrectionOrNull() { 406be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard return mAutoCorrection; 407117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard } 408c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard 4094b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard /** 4104b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard * @return whether we started composing this word by resuming suggestion on an existing string 4114b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard */ 4124b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard public boolean isResumed() { 4134b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard return mIsResumed; 4144b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard } 4154b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard 416267563d1bb4d8091293fbd8774f0f95ef59f03c4Jean Chalard // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. 4174752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard // committedWord should contain suggestion spans if applicable. 4184752b68f5a62ede099677bdea0514ba1d5082606Jean Chalard public LastComposedWord commitWord(final int type, final CharSequence committedWord, 419bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi final String separatorString, final NgramContext ngramContext) { 4209271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK 4219271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate 4229271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard // the last composed word to ensure this does not happen. 4231ef9d5938e671ce7a9d5c29d95c1364d6d6249eaJean Chalard final LastComposedWord lastComposedWord = new LastComposedWord(mEvents, 4243285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard mInputPointers, mTypedWordCache.toString(), committedWord, separatorString, 425bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi ngramContext, mCapitalizedMode); 42671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.reset(); 4279271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD 4289271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) { 429449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard lastComposedWord.deactivate(); 430449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard } 431e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mCapsCount = 0; 432e7c471a52f38c48cd38e412d88901bddb6f903a9Jean Chalard mDigitsCount = 0; 433e9808694fecbf7be776cd5cf8ec0333e158286b1Jean Chalard mIsBatchMode = false; 434cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 435f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents.clear(); 4368914555776a4d3dfd6afc4926a69169ca1c82a0eJean Chalard mCodePointSize = 0; 437367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard mIsOnlyFirstCharCapitalized = false; 4388914555776a4d3dfd6afc4926a69169ca1c82a0eJean Chalard mCapitalizedMode = CAPS_MODE_OFF; 4393285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 440be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard mAutoCorrection = null; 4416a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = 0; 4424b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = false; 443d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 4441f8fc62ccb5018716457dc309ab11ad3e1506ad1Jean Chalard return lastComposedWord; 445c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard } 446fae1ba767ca177510adc08b363987f67bbf40d90Jean Chalard 447367c199de16f7ce8e608bdf38bf35df8995e18a0Jean Chalard public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { 448f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard mEvents.clear(); 449f8accd8839d291f10b218e64aa6b8eb154c92c4cJean Chalard Collections.copy(mEvents, lastComposedWord.mEvents); 45071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka mInputPointers.set(lastComposedWord.mInputPointers); 451cbed462d192d0c5af9614f5f997b2768f3d0eb56Jean Chalard mCombinerChain.reset(); 4523285b68c97d966d86c08aeb837e5bf5633981357Jean Chalard refreshTypedWordCache(); 453b6b7f5e39e9ea1bf9a05203c536327a6be7e7214Jean Chalard mCapitalizedMode = lastComposedWord.mCapitalizedMode; 454cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard mAutoCorrection = null; // This will be filled by the next call to updateSuggestion. 4556a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mCursorPositionWithinWord = mCodePointSize; 456d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = null; 4574b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard mIsResumed = true; 4589e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard } 459d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka 460d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka public boolean isBatchMode() { 461d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka return mIsBatchMode; 462d82dcdc9246b340c4b355e34efc6079f3278efa6Tadashi G. Takaoka } 463d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard 464d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard public void setRejectedBatchModeSuggestion(final String rejectedSuggestion) { 465d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mRejectedBatchModeSuggestion = rejectedSuggestion; 466d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard } 467d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard 468d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard public String getRejectedBatchModeSuggestion() { 469d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard return mRejectedBatchModeSuggestion; 470d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard } 471b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik 472b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik @UsedForTesting 473b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik void addInputPointerForTest(int index, int keyX, int keyY) { 474b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik mInputPointers.addPointerAt(index, keyX, keyY, 0, 0); 475b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik } 476b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik 477b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik @UsedForTesting 478b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik void setTypedWordCacheForTests(String typedWordCacheForTests) { 479b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik mTypedWordCache = typedWordCacheForTests; 480b00c054125d9f2aa31c2147920cc52cbf2a45cccMohammadinamul Sheik } 481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 482