diff options
Diffstat (limited to 'java')
18 files changed, 301 insertions, 242 deletions
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml index 056bc355e..8fe415d11 100644 --- a/java/res/values-ka-rGE/strings.xml +++ b/java/res/values-ka-rGE/strings.xml @@ -167,7 +167,7 @@ <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ინსტალაციისათვის აირჩიეთ ლექსიკონის ფაილი"</string> <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ნამდვილად გსურთ ამ ფაილის <xliff:g id="LANGUAGE_NAME">%s</xliff:g>-ისთვის ინსტალაცია?"</string> <string name="error" msgid="8940763624668513648">"წარმოიშვა შეცდომა"</string> - <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"კონტაქტების საქაღალდის ჩამოწერა"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"კონტაქტების საქაღალდის ამონაწერი"</string> <string name="prefs_dump_user_dict" msgid="294870685041741951">"პერსონალური საქაღალდის ჩამოწერა"</string> <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"მომხმ. ისტორიის საქაღალდის ჩამოწერა"</string> <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"პერსონალიზაციის საქაღალდის ჩამოწერა"</string> diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml index 9f28cd1bb..dae75e350 100644 --- a/java/res/values-lo-rLA/strings.xml +++ b/java/res/values-lo-rLA/strings.xml @@ -167,7 +167,7 @@ <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ເລືອກໄຟລ໌ວັດຈະນານຸກົມເພື່ອຕິດຕັ້ງ"</string> <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ຕິດຕັ້ງໄຟລ໌ນີ້ສຳລັບ <xliff:g id="LANGUAGE_NAME">%s</xliff:g> ແທ້ບໍ່??"</string> <string name="error" msgid="8940763624668513648">"ມີຂໍ້ຜິດພາດເກີດຂຶ້ນ"</string> - <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ເທຂໍ້ມູນວັດຈະນານຸກົມລາຍຊື່ຜູ່ຕິດຕໍ່"</string> + <string name="prefs_dump_contacts_dict" msgid="7227327764402323097">"ດຶງຂໍ້ມູນວັດຈະນານຸກົມລາຍຊື່ຜູ່ຕິດຕໍ່"</string> <string name="prefs_dump_user_dict" msgid="294870685041741951">"ເທຂໍ້ມູນວັດຈະນານຸກົມສ່ວນໂຕ"</string> <string name="prefs_dump_user_history_dict" msgid="6821075152449554628">"ເທຂໍ້ມູນວັດຈະນານຸກົມປະຫວັດຜູ່ໃຊ້"</string> <string name="prefs_dump_personalization_dict" msgid="7558387996151745284">"ເທຂໍ້ມູນວັດຈະນານຸກົມຄວາມເປັນໂຕຕົນ"</string> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index ddff7697c..5efa73362 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -491,8 +491,6 @@ mobile devices. [CHAR LIMIT=25] --> <string name="prefs_key_popup_dismiss_end_scale_settings" translatable="false">Key popup dismiss end scale</string> <!-- Title of the settings for reading an external dictionary file --> <string name="prefs_read_external_dictionary">Read external dictionary file</string> - <!-- Title of the settings for using only personalization dictionary --> - <string name="prefs_use_only_personalization_dictionary" translatable="false">Use only personalization dictionary</string> <!-- Message to show when there are no files to install as an external dictionary [CHAR LIMIT=100] --> <string name="read_external_dictionary_no_files_message">No dictionary files in the Downloads folder</string> <!-- Title of the dialog that selects a file to install as an external dictionary [CHAR LIMIT=50] --> diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml index 81a5d98b9..7b2b8eab4 100644 --- a/java/res/xml/prefs_for_debug.xml +++ b/java/res/xml/prefs_for_debug.xml @@ -65,11 +65,6 @@ android:key="pref_key_preview_dismiss_duration" android:title="@string/prefs_key_popup_dismiss_duration_settings" latin:maxValue="100" /> <!-- milliseconds --> - <CheckBoxPreference - android:defaultValue="false" - android:key="use_only_personalization_dictionary_for_debug" - android:persistent="true" - android:title="@string/prefs_use_only_personalization_dictionary" /> <PreferenceScreen android:key="read_external_dictionary" android:title="@string/prefs_read_external_dictionary" /> diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java new file mode 100644 index 000000000..5e046a80e --- /dev/null +++ b/java/src/com/android/inputmethod/event/InputTransaction.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.event; + +/** + * An object encapsulating a single transaction for input. + */ +public class InputTransaction { + // UPDATE_LATER is stronger than UPDATE_NOW. The reason for this is, if we have to update later, + // it's because something will change that we can't evaluate now, which means that even if we + // re-evaluate now we'll have to do it again later. The only case where that wouldn't apply + // would be if we needed to update now to find out the new state right away, but then we + // can't do it with this deferred mechanism anyway. + public static final int SHIFT_NO_UPDATE = 0; + public static final int SHIFT_UPDATE_NOW = 1; + public static final int SHIFT_UPDATE_LATER = 2; + + // Initial conditions + public final int mShiftState; + + // Outputs + private int mRequiredShiftUpdate = SHIFT_NO_UPDATE; + + public InputTransaction(final int shiftState) { + mShiftState = shiftState; + } + + public void requireShiftUpdate(final int updateType) { + mRequiredShiftUpdate = Math.max(mRequiredShiftUpdate, updateType); + } + public int getRequiredShiftUpdate() { + return mRequiredShiftUpdate; + } +} diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 6c56b8aab..3590c486b 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -700,12 +700,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { + public void onCancelMoreKeysPanel() { PointerTracker.dismissAllMoreKeysPanels(); } @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { + public void onDismissMoreKeysPanel() { dimEntireKeyboard(false /* dimmed */); if (isShowingMoreKeysPanel()) { mMoreKeysPanel.removeFromParent(); diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java index 1891dfc74..fc331970b 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java @@ -122,7 +122,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel onMoveKeyInternal(x, y, pointerId); if (hasOldKey && mCurrentKey == null) { // If the pointer has moved too far away from any target then cancel the panel. - mController.onCancelMoreKeysPanel(this); + mController.onCancelMoreKeysPanel(); } } @@ -184,7 +184,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel if (!isShowingInParent()) { return; } - mController.onDismissMoreKeysPanel(this); + mController.onDismissMoreKeysPanel(); } @Override diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java index 4a33e6536..7bddd09f6 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysPanel.java @@ -29,24 +29,22 @@ public interface MoreKeysPanel { /** * Remove the current {@link MoreKeysPanel} from the target view. - * @param panel the panel to be dismissed. */ - public void onDismissMoreKeysPanel(final MoreKeysPanel panel); + public void onDismissMoreKeysPanel(); /** * Instructs the parent to cancel the panel (e.g., when entering a different input mode). - * @param panel the panel to be canceled. */ - public void onCancelMoreKeysPanel(final MoreKeysPanel panel); + public void onCancelMoreKeysPanel(); } public static final Controller EMPTY_CONTROLLER = new Controller() { @Override public void onShowMoreKeysPanel(final MoreKeysPanel panel) {} @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) {} + public void onDismissMoreKeysPanel() {} @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) {} + public void onCancelMoreKeysPanel() {} }; /** diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java index cd18a6ba5..d6178fcee 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java @@ -55,7 +55,6 @@ public class DictionaryFacilitatorForSuggest { private final ConcurrentHashMap<String, Dictionary> mDictionaries = CollectionUtils.newConcurrentHashMap(); - private HashSet<String> mDictionarySubsetForDebug = null; private Dictionary mMainDictionary; private ContactsBinaryDictionary mContactsDictionary; @@ -85,7 +84,6 @@ public class DictionaryFacilitatorForSuggest { mContext = context; mLocale = locale; mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1); - initForDebug(settingsValues); loadMainDict(context, locale, listener); setUserDictionary(new UserBinaryDictionary(context, locale)); resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues); @@ -101,7 +99,6 @@ public class DictionaryFacilitatorForSuggest { final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) { mContext = oldDictionaryFacilitator.mContext; mLocale = oldDictionaryFacilitator.mLocale; - mDictionarySubsetForDebug = oldDictionaryFacilitator.mDictionarySubsetForDebug; mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1); loadMainDict(mContext, mLocale, listener); // Transfer user dictionary. @@ -130,7 +127,6 @@ public class DictionaryFacilitatorForSuggest { mContext = oldDictionaryFacilitator.mContext; mLocale = oldDictionaryFacilitator.mLocale; mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0); - initForDebug(settingsValues); // Transfer main dictionary. setMainDictionary(oldDictionaryFacilitator.mMainDictionary); oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_MAIN); @@ -197,12 +193,12 @@ public class DictionaryFacilitatorForSuggest { } } - // initialize a debug flag for the personalization - private void initForDebug(final SettingsValues settingsValues) { - if (settingsValues.mUseOnlyPersonalizationDictionaryForDebug) { - mDictionarySubsetForDebug = new HashSet<String>(); - mDictionarySubsetForDebug.add(Dictionary.TYPE_PERSONALIZATION); - } + public boolean needsToBeRecreated(final Locale newLocale, + final SettingsValues newSettingsValues) { + return !mLocale.equals(newLocale) + || (newSettingsValues.mUseContactsDict != (mContactsDictionary != null)) + || (newSettingsValues.mUsePersonalizedDicts != (mUserHistoryDictionary != null)) + || (newSettingsValues.mUsePersonalizedDicts != hasPersonalizationDictionary()); } public void close() { @@ -531,10 +527,6 @@ public class DictionaryFacilitatorForSuggest { } private void addOrReplaceDictionary(final String key, final Dictionary dict) { - if (mDictionarySubsetForDebug != null && !mDictionarySubsetForDebug.contains(key)) { - Log.w(TAG, "Ignore add " + key + " dictionary for debug."); - return; - } final Dictionary oldDict; if (dict == null) { oldDict = mDictionaries.remove(key); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index bfc578082..44353ba06 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -78,7 +78,6 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; import com.android.inputmethod.latin.utils.ApplicationUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; -import com.android.inputmethod.latin.utils.CompletionInfoUtils; import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.ImportantNoticeUtils; import com.android.inputmethod.latin.utils.IntentUtils; @@ -124,9 +123,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private View mKeyPreviewBackingView; private SuggestionStripView mSuggestionStripView; - // TODO[IL]: remove this member completely. - public CompletionInfo[] mApplicationSpecifiedCompletions; - private RichInputMethodManager mRichImm; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; @@ -192,8 +188,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; switch (msg.what) { case MSG_UPDATE_SUGGESTION_STRIP: + cancelUpdateSuggestionStrip(); latinIme.mInputLogic.performUpdateSuggestionStripSync( - latinIme.mSettings.getCurrent(), this /* handler */); + latinIme.mSettings.getCurrent()); break; case MSG_UPDATE_SHIFT_STATE: switcher.updateShiftState(); @@ -530,27 +527,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final EditorInfo editorInfo = getCurrentInputEditorInfo(); final InputAttributes inputAttributes = new InputAttributes(editorInfo, isFullscreenMode()); mSettings.loadSettings(this, locale, inputAttributes); - AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(mSettings.getCurrent()); - // To load the keyboard we need to load all the settings once, but resetting the - // contacts dictionary should be deferred until after the new layout has been displayed - // to improve responsivity. In the language switching process, we post a reopenDictionaries - // message, then come here to read the settings for the new language before we change - // the layout; at this time, we need to skip resetting the contacts dictionary. It will - // be done later inside {@see #initSuggest()} when the reopenDictionaries message is - // processed. final SettingsValues currentSettingsValues = mSettings.getCurrent(); - final Suggest suggest = mInputLogic.mSuggest; - if (!mHandler.hasPendingReopenDictionaries() && suggest != null) { + AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues); + // This method is called on startup and language switch, before the new layout has + // been displayed. Opening dictionaries never affects responsivity as dictionaries are + // asynchronously loaded. + initOrResetSuggestForSettingsValues(mInputLogic.mSuggest, locale, currentSettingsValues); + } + + private void initOrResetSuggestForSettingsValues(final Suggest oldSuggest, + final Locale locale, final SettingsValues settingsValues) { + if (!mHandler.hasPendingReopenDictionaries() && oldSuggest != null) { // May need to reset dictionaries depending on the user settings. final DictionaryFacilitatorForSuggest oldDictionaryFacilitator = - suggest.mDictionaryFacilitator; + oldSuggest.mDictionaryFacilitator; + if (!oldDictionaryFacilitator.needsToBeRecreated(locale, settingsValues)) { + // Continue to use the same dictionary facilitator if no configuration has changed. + refreshPersonalizationDictionarySession(); + return; + } final DictionaryFacilitatorForSuggest dictionaryFacilitator = - new DictionaryFacilitatorForSuggest(currentSettingsValues, - oldDictionaryFacilitator); + new DictionaryFacilitatorForSuggest(settingsValues, oldDictionaryFacilitator); // Create Suggest instance with the new dictionary facilitator. - resetSuggest(new Suggest(suggest /* oldSuggest */, dictionaryFacilitator)); - } else if (suggest == null) { - initSuggestForLocale(locale); + replaceSuggest(new Suggest(oldSuggest, dictionaryFacilitator)); + } else if (oldSuggest == null) { + initSuggest(); } } @@ -610,13 +611,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } else { subtypeLocale = switcherSubtypeLocale; } - initSuggestForLocale(subtypeLocale); + initSuggestForLocale(mInputLogic.mSuggest, subtypeLocale); } - private void initSuggestForLocale(final Locale locale) { + private void initSuggestForLocale(final Suggest oldSuggest, final Locale locale) { final SettingsValues settingsValues = mSettings.getCurrent(); final DictionaryFacilitatorForSuggest oldDictionaryFacilitator = - (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator; + (oldSuggest == null) ? null : oldSuggest.mDictionaryFacilitator; // Creates new dictionary facilitator for the new locale. final DictionaryFacilitatorForSuggest dictionaryFacilitator = new DictionaryFacilitatorForSuggest(this /* context */, locale, settingsValues, @@ -625,7 +626,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (settingsValues.mCorrectionEnabled) { newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold); } - resetSuggest(newSuggest); + replaceSuggest(newSuggest); } /* package private */ void resetSuggestMainDict() { @@ -633,10 +634,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mInputLogic.mSuggest.mDictionaryFacilitator; final DictionaryFacilitatorForSuggest dictionaryFacilitator = new DictionaryFacilitatorForSuggest(this /* listener */, oldDictionaryFacilitator); - resetSuggest(new Suggest(mInputLogic.mSuggest /* oldSuggest */, dictionaryFacilitator)); + replaceSuggest(new Suggest(mInputLogic.mSuggest /* oldSuggest */, dictionaryFacilitator)); } - private void resetSuggest(final Suggest newSuggest) { + private void replaceSuggest(final Suggest newSuggest) { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.getInstance().initDictionary(newSuggest.mDictionaryFacilitator); } @@ -808,7 +809,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); - mApplicationSpecifiedCompletions = null; // The app calling setText() has the effect of clearing the composing // span, so we should reset our state unconditionally, even if restarting is true. @@ -875,7 +875,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // This will set the punctuation suggestions if next word suggestion is off; // otherwise it will clear the suggestion strip. - setNeutralSuggestionStripInternal(); + setNeutralSuggestionStrip(); mHandler.cancelUpdateSuggestionStrip(); mHandler.cancelDoubleSpacePeriodTimer(); @@ -950,8 +950,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown(). // TODO: find a better way to simulate actual execution. if (isInputViewShown() && - mInputLogic.onUpdateSelection(mSettings.getCurrent(), oldSelStart, oldSelEnd, - newSelStart, newSelEnd, composingSpanStart, composingSpanEnd)) { + mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd)) { mKeyboardSwitcher.updateShiftState(); } @@ -1030,8 +1029,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } return; } - mApplicationSpecifiedCompletions = - CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions); final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = SuggestedWords.getFromApplicationSpecifiedCompletions( @@ -1046,18 +1043,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - private void setSuggestionStripShownInternal(final boolean isSuggestionStripVisible) { - // TODO: Modify this if we support suggestions with hard keyboard - if (!onEvaluateInputViewShown() || !hasSuggestionStripView()) { - return; - } - if (isSuggestionStripVisible) { - mSuggestionStripView.setVisibility(View.VISIBLE); - } else { - mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE); - } - } - private int getAdjustedBackingViewHeight() { final int currentHeight = mKeyPreviewBackingView.getHeight(); if (currentHeight > 0) { @@ -1295,7 +1280,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onStartBatchInput() { - mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); + mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); } @Override @@ -1305,7 +1290,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void onEndBatchInput(final InputPointers batchPointers) { - mInputLogic.onEndBatchInput(mSettings.getCurrent(), batchPointers); + mInputLogic.onEndBatchInput(batchPointers); } @Override @@ -1383,13 +1368,23 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void setSuggestedWords(final SuggestedWords suggestedWords, final boolean isSuggestionStripVisible) { mInputLogic.setSuggestedWords(suggestedWords); + // TODO: Modify this when we support suggestions with hard keyboard if (!hasSuggestionStripView()) { return; } + mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); + if (!onEvaluateInputViewShown()) { + return; + } + if (!isSuggestionStripVisible) { + mSuggestionStripView.setVisibility(isFullscreenMode() ? View.GONE : View.INVISIBLE); + return; + } + mSuggestionStripView.setVisibility(View.VISIBLE); + final SettingsValues currentSettings = mSettings.getCurrent(); final boolean showSuggestions; - if (SuggestedWords.EMPTY == suggestedWords - || suggestedWords.isPunctuationSuggestions() + if (SuggestedWords.EMPTY == suggestedWords || suggestedWords.isPunctuationSuggestions() || !currentSettings.isSuggestionsRequested()) { showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle( currentSettings.mInputAttributes); @@ -1400,8 +1395,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSuggestionStripView.setSuggestions(suggestedWords, SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); } - mKeyboardSwitcher.onAutoCorrectionStateChanged(suggestedWords.mWillAutoCorrect); - setSuggestionStripShownInternal(isSuggestionStripVisible); } // TODO[IL]: Move this out of LatinIME. @@ -1445,32 +1438,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen sequenceNumber, callback); } - // TODO[IL]: Move this to InputLogic - public SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord, - final SuggestedWords suggestedWords, final SuggestedWords previousSuggestedWords) { - // TODO: consolidate this into getSuggestedWords - // We update the suggestion strip only when we have some suggestions to show, i.e. when - // the suggestion count is > 1; else, we leave the old suggestions, with the typed word - // replaced with the new one. However, when the length of the typed word is 1 or 0 (after - // a deletion typically), we do want to remove the old suggestions. Also, if we are showing - // the "add to dictionary" hint, we need to revert to suggestions - although it is unclear - // how we can come here if it's displayed. - if (suggestedWords.size() > 1 || typedWord.length() <= 1 - || !hasSuggestionStripView() || isShowingAddToDictionaryHint()) { - return suggestedWords; - } else { - final SuggestedWords punctuationList = - mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList; - final SuggestedWords oldSuggestedWords = previousSuggestedWords == punctuationList - ? SuggestedWords.EMPTY : previousSuggestedWords; - final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = - SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); - return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, - false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, - true /* isObsoleteSuggestions */, false /* isPrediction */); - } - } - @Override public void showSuggestionStrip(final SuggestedWords sourceSuggestedWords) { final SuggestedWords suggestedWords = @@ -1511,15 +1478,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSuggestionStripView.showAddToDictionaryHint(word); } - // TODO[IL]: Define a clean interface for this // This will show either an empty suggestion strip (if prediction is enabled) or // punctuation suggestions (if it's disabled). @Override public void setNeutralSuggestionStrip() { - setNeutralSuggestionStripInternal(); - } - - private void setNeutralSuggestionStripInternal() { final SettingsValues currentSettings = mSettings.getCurrent(); final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled ? SuggestedWords.EMPTY : currentSettings.mSpacingAndPunctuations.mSuggestPuncList; @@ -1733,7 +1695,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final DictionaryFacilitatorForSuggest dictionaryFacilitator = new DictionaryFacilitatorForSuggest(this, locale, mSettings.getCurrent(), this /* listener */, oldDictionaryFacilitator); - resetSuggest(new Suggest(locale, dictionaryFacilitator)); + replaceSuggest(new Suggest(locale, dictionaryFacilitator)); } // DO NOT USE THIS for any other purpose than testing. diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 6b6bbf3a7..630a03670 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -50,7 +50,7 @@ public final class RichInputMethodManager { private static final RichInputMethodManager sInstance = new RichInputMethodManager(); private InputMethodManagerCompatWrapper mImmWrapper; - private InputMethodInfo mInputMethodInfoOfThisIme; + private InputMethodInfoCache mInputMethodInfoCache; final HashMap<InputMethodInfo, List<InputMethodSubtype>> mSubtypeListCacheWithImplicitlySelectedSubtypes = CollectionUtils.newHashMap(); final HashMap<InputMethodInfo, List<InputMethodSubtype>> @@ -83,7 +83,8 @@ public final class RichInputMethodManager { return; } mImmWrapper = new InputMethodManagerCompatWrapper(context); - mInputMethodInfoOfThisIme = getInputMethodInfoOfThisIme(context); + mInputMethodInfoCache = new InputMethodInfoCache( + mImmWrapper.mImm, context.getPackageName()); // Initialize additional subtypes. SubtypeLocaleUtils.init(context); @@ -99,20 +100,10 @@ public final class RichInputMethodManager { return mImmWrapper.mImm; } - private InputMethodInfo getInputMethodInfoOfThisIme(final Context context) { - final String packageName = context.getPackageName(); - for (final InputMethodInfo imi : mImmWrapper.mImm.getInputMethodList()) { - if (imi.getPackageName().equals(packageName)) { - return imi; - } - } - throw new RuntimeException("Input method id for " + packageName + " not found."); - } - public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList( boolean allowsImplicitlySelectedSubtypes) { - return getEnabledInputMethodSubtypeList(mInputMethodInfoOfThisIme, - allowsImplicitlySelectedSubtypes); + return getEnabledInputMethodSubtypeList( + getInputMethodInfoOfThisIme(), allowsImplicitlySelectedSubtypes); } public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) { @@ -153,10 +144,10 @@ public final class RichInputMethodManager { private boolean switchToNextInputMethodAndSubtype(final IBinder token) { final InputMethodManager imm = mImmWrapper.mImm; final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); - final int currentIndex = getImiIndexInList(mInputMethodInfoOfThisIme, enabledImis); + final int currentIndex = getImiIndexInList(getInputMethodInfoOfThisIme(), enabledImis); if (currentIndex == INDEX_NOT_FOUND) { Log.w(TAG, "Can't find current IME in enabled IMEs: IME package=" - + mInputMethodInfoOfThisIme.getPackageName()); + + getInputMethodInfoOfThisIme().getPackageName()); return false; } final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis); @@ -213,16 +204,45 @@ public final class RichInputMethodManager { return true; } + private static class InputMethodInfoCache { + private final InputMethodManager mImm; + private final String mImePackageName; + + private InputMethodInfo mCachedValue; + + public InputMethodInfoCache(final InputMethodManager imm, final String imePackageName) { + mImm = imm; + mImePackageName = imePackageName; + } + + public synchronized InputMethodInfo get() { + if (mCachedValue != null) { + return mCachedValue; + } + for (final InputMethodInfo imi : mImm.getInputMethodList()) { + if (imi.getPackageName().equals(mImePackageName)) { + mCachedValue = imi; + return imi; + } + } + throw new RuntimeException("Input method id for " + mImePackageName + " not found."); + } + + public synchronized void clear() { + mCachedValue = null; + } + } + public InputMethodInfo getInputMethodInfoOfThisIme() { - return mInputMethodInfoOfThisIme; + return mInputMethodInfoCache.get(); } public String getInputMethodIdOfThisIme() { - return mInputMethodInfoOfThisIme.getId(); + return getInputMethodInfoOfThisIme().getId(); } public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) { - return checkIfSubtypeBelongsToImeAndEnabled(mInputMethodInfoOfThisIme, subtype); + return checkIfSubtypeBelongsToImeAndEnabled(getInputMethodInfoOfThisIme(), subtype); } public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled( @@ -258,7 +278,7 @@ public final class RichInputMethodManager { } public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) { - return getSubtypeIndexInIme(subtype, mInputMethodInfoOfThisIme) != INDEX_NOT_FOUND; + return getSubtypeIndexInIme(subtype, getInputMethodInfoOfThisIme()) != INDEX_NOT_FOUND; } private static int getSubtypeIndexInIme(final InputMethodSubtype subtype, @@ -286,7 +306,8 @@ public final class RichInputMethodManager { public boolean hasMultipleEnabledSubtypesInThisIme( final boolean shouldIncludeAuxiliarySubtypes) { - final List<InputMethodInfo> imiList = Collections.singletonList(mInputMethodInfoOfThisIme); + final List<InputMethodInfo> imiList = Collections.singletonList( + getInputMethodInfoOfThisIme()); return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); } @@ -340,7 +361,7 @@ public final class RichInputMethodManager { public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString, final String keyboardLayoutSetName) { - final InputMethodInfo myImi = mInputMethodInfoOfThisIme; + final InputMethodInfo myImi = getInputMethodInfoOfThisIme(); final int count = myImi.getSubtypeCount(); for (int i = 0; i < count; i++) { final InputMethodSubtype subtype = myImi.getSubtypeAt(i); @@ -355,13 +376,14 @@ public final class RichInputMethodManager { public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) { mImmWrapper.mImm.setInputMethodAndSubtype( - token, mInputMethodInfoOfThisIme.getId(), subtype); + token, getInputMethodIdOfThisIme(), subtype); } public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) { mImmWrapper.mImm.setAdditionalInputMethodSubtypes( - mInputMethodInfoOfThisIme.getId(), subtypes); - // Clear the cache so that we go read the subtypes again next time. + getInputMethodIdOfThisIme(), subtypes); + // Clear the cache so that we go read the {@link InputMethodInfo} of this IME and list of + // subtypes again next time. clearSubtypeCaches(); } @@ -382,5 +404,6 @@ public final class RichInputMethodManager { public void clearSubtypeCaches() { mSubtypeListCacheWithImplicitlySelectedSubtypes.clear(); mSubtypeListCacheWithoutImplicitlySelectedSubtypes.clear(); + mInputMethodInfoCache.clear(); } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index df25b0c29..ba64028ca 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -60,6 +60,7 @@ public final class Suggest { // Locale used for upper- and title-casing words public final Locale mLocale; + // TODO: Move dictionaryFacilitator constructing logics from LatinIME to Suggest. public Suggest(final Locale locale, final DictionaryFacilitatorForSuggest dictionaryFacilitator) { mLocale = locale; diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 06bc90c97..dc2c9fd0e 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -167,15 +167,10 @@ public class SuggestedWords { final CompletionInfo[] infos) { final ArrayList<SuggestedWordInfo> result = CollectionUtils.newArrayList(); for (final CompletionInfo info : infos) { - if (info == null) continue; - final CharSequence text = info.getText(); - if (null == text) continue; - final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(), - SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED, - Dictionary.DICTIONARY_APPLICATION_DEFINED, - SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, - SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */); - result.add(suggestedWordInfo); + if (null == info || null == info.getText()) { + continue; + } + result.add(new SuggestedWordInfo(info)); } return result; } @@ -234,6 +229,9 @@ public class SuggestedWords { public static final int KIND_FLAG_EXACT_MATCH = 0x40000000; public final String mWord; + // The completion info from the application. Null for suggestions that don't come from + // the application (including keyboard-computed ones, so this is almost always null) + public final CompletionInfo mApplicationSpecifiedCompletionInfo; public final int mScore; public final int mKind; // one of the KIND_* constants above public final int mCodePointCount; @@ -260,6 +258,7 @@ public class SuggestedWords { final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord, final int autoCommitFirstWordConfidence) { mWord = word; + mApplicationSpecifiedCompletionInfo = null; mScore = score; mKind = kind; mSourceDict = sourceDict; @@ -268,6 +267,22 @@ public class SuggestedWords { mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence; } + /** + * Create a new suggested word info from an application-specified completion. + * If the passed argument or its contained text is null, this throws a NPE. + * @param applicationSpecifiedCompletion The application-specified completion info. + */ + public SuggestedWordInfo(final CompletionInfo applicationSpecifiedCompletion) { + mWord = applicationSpecifiedCompletion.getText().toString(); + mApplicationSpecifiedCompletionInfo = applicationSpecifiedCompletion; + mScore = SuggestedWordInfo.MAX_SCORE; + mKind = SuggestedWordInfo.KIND_APP_DEFINED; + mSourceDict = Dictionary.DICTIONARY_APPLICATION_DEFINED; + mCodePointCount = StringUtils.codePointCount(mWord); + mIndexOfTouchPointOfSecondWord = SuggestedWordInfo.NOT_AN_INDEX; + mAutoCommitFirstWordConfidence = SuggestedWordInfo.NOT_A_CONFIDENCE; + } + public boolean isEligibleForAutoCommit() { return (KIND_CORRECTION == mKind && NOT_AN_INDEX != mIndexOfTouchPointOfSecondWord); } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index f2f9f1e68..daaac5913 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -23,12 +23,12 @@ import android.text.style.SuggestionSpan; import android.util.Log; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.event.EventInterpreter; +import com.android.inputmethod.event.InputTransaction; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Dictionary; @@ -74,7 +74,7 @@ public final class InputLogic { // TODO : make all these fields private as soon as possible. // Current space state of the input method. This can be any of the above constants. - public int mSpaceState; + private int mSpaceState; // Never null public SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; // TODO: mSuggest should be touched by a single thread. @@ -85,7 +85,7 @@ public final class InputLogic { public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; public final WordComposer mWordComposer; public final RichInputConnection mConnection; - public final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); + private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); private int mDeleteCount; private long mLastKeyTime; @@ -96,7 +96,7 @@ public final class InputLogic { // TODO: This boolean is persistent state and causes large side effects at unexpected times. // Find a way to remove it for readability. - public boolean mIsAutoCorrectionIndicatorOn; + private boolean mIsAutoCorrectionIndicatorOn; public InputLogic(final LatinIME latinIME, final SuggestionStripViewAccessor suggestionStripViewAccessor) { @@ -227,17 +227,16 @@ public final class InputLogic { } } - // TODO: stop relying on mApplicationSpecifiedCompletions. The SuggestionInfo object - // should contain a reference to the CompletionInfo instead. - if (settingsValues.isApplicationSpecifiedCompletionsOn() - && mLatinIME.mApplicationSpecifiedCompletions != null - && index >= 0 && index < mLatinIME.mApplicationSpecifiedCompletions.length) { + // TODO: We should not need the following branch. We should be able to take the same + // code path as for other kinds, use commitChosenWord, and do everything normally. We will + // however need to reset the suggestion strip right away, because we know we can't take + // the risk of calling commitCompletion twice because we don't know how the app will react. + if (SuggestedWordInfo.KIND_APP_DEFINED == suggestionInfo.mKind) { mSuggestedWords = SuggestedWords.EMPTY; mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); keyboardSwitcher.updateShiftState(); resetComposingState(true /* alsoResetLastComposedWord */); - final CompletionInfo completionInfo = mLatinIME.mApplicationSpecifiedCompletions[index]; - mConnection.commitCompletion(completionInfo); + mConnection.commitCompletion(suggestionInfo.mApplicationSpecifiedCompletionInfo); mConnection.endBatchEdit(); return; } @@ -290,19 +289,14 @@ public final class InputLogic { * Consider an update to the cursor position. Evaluate whether this update has happened as * part of normal typing or whether it was an explicit cursor move by the user. In any case, * do the necessary adjustments. - * @param settingsValues the current settings * @param oldSelStart old selection start * @param oldSelEnd old selection end * @param newSelStart new selection start * @param newSelEnd new selection end - * @param composingSpanStart composing span start - * @param composingSpanEnd composing span end * @return whether the cursor has moved as a result of user interaction. */ - public boolean onUpdateSelection(final SettingsValues settingsValues, - final int oldSelStart, final int oldSelEnd, - final int newSelStart, final int newSelEnd, - final int composingSpanStart, final int composingSpanEnd) { + public boolean onUpdateSelection(final int oldSelStart, final int oldSelEnd, + final int newSelStart, final int newSelEnd) { if (mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart, oldSelEnd, newSelEnd)) { return false; } @@ -335,8 +329,7 @@ public final class InputLogic { // we'd have the suggestion strip noticeably janky. To avoid that, we don't clear // it here, which means we'll keep outdated suggestions for a split second but the // visual result is better. - resetEntireInputState(settingsValues, newSelStart, newSelEnd, - false /* clearSuggestionStrip */); + resetEntireInputState(newSelStart, newSelEnd, false /* clearSuggestionStrip */); } else { // resetEntireInputState calls resetCachesUponCursorMove, but forcing the // composition to end. But in all cases where we don't reset the entire input @@ -372,6 +365,8 @@ public final class InputLogic { ResearchLogger.latinIME_onCodeInput(code, x, y); } final long when = SystemClock.uptimeMillis(); + final InputTransaction inputTransaction = new InputTransaction( + getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode())); if (code != Constants.CODE_DELETE || when > mLastKeyTime + Constants.LONG_PRESS_MILLISECONDS) { mDeleteCount = 0; @@ -396,12 +391,12 @@ public final class InputLogic { boolean didAutoCorrect = false; switch (code) { case Constants.CODE_DELETE: - handleBackspace(settingsValues, spaceState, handler, keyboardSwitcher); + handleBackspace(settingsValues, spaceState, inputTransaction, handler); LatinImeLogger.logOnDelete(x, y); break; case Constants.CODE_SHIFT: performRecapitalization(settingsValues); - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); break; case Constants.CODE_CAPSLOCK: // Note: Changing keyboard to shift lock state is handled in @@ -456,12 +451,12 @@ public final class InputLogic { // No action label, and the action from imeOptions is NONE: this is a regular // enter key that should input a carriage return. didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER, - x, y, spaceState, keyboardSwitcher, handler); + x, y, spaceState, inputTransaction, handler); } break; case Constants.CODE_SHIFT_ENTER: didAutoCorrect = handleNonSpecialCharacter(settingsValues, Constants.CODE_ENTER, - x, y, spaceState, keyboardSwitcher, handler); + x, y, spaceState, inputTransaction, handler); break; case Constants.CODE_ALPHA_FROM_EMOJI: // Note: Switching back from Emoji keyboard to the main keyboard is being handled in @@ -469,7 +464,7 @@ public final class InputLogic { break; default: didAutoCorrect = handleNonSpecialCharacter(settingsValues, - code, x, y, spaceState, keyboardSwitcher, handler); + code, x, y, spaceState, inputTransaction, handler); break; } // Reset after any single keystroke, except shift, capslock, and symbol-shift @@ -481,6 +476,15 @@ public final class InputLogic { mEnteredText = null; } mConnection.endBatchEdit(); + switch (inputTransaction.getRequiredShiftUpdate()) { + case InputTransaction.SHIFT_UPDATE_LATER: + mLatinIME.mHandler.postUpdateShiftState(); + break; + case InputTransaction.SHIFT_UPDATE_NOW: + keyboardSwitcher.updateShiftState(); + break; + default: // SHIFT_NO_UPDATE + } } public void onStartBatchInput(final SettingsValues settingsValues, @@ -504,7 +508,7 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the batch input at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else if (wordComposerSize <= 1) { // We auto-correct the previous (typed, not gestured) string iff it's one character @@ -585,8 +589,7 @@ public final class InputLogic { mInputLogicHandler.onUpdateBatchInput(batchPointers, mAutoCommitSequenceNumber); } - public void onEndBatchInput(final SettingsValues settingValues, - final InputPointers batchPointers) { + public void onEndBatchInput(final InputPointers batchPointers) { mInputLogicHandler.onEndBatchInput(batchPointers, mAutoCommitSequenceNumber); ++mAutoCommitSequenceNumber; } @@ -630,18 +633,20 @@ public final class InputLogic { * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. * @param spaceState the space state at start of the batch input. + * @param inputTransaction The transaction in progress. * @return whether this caused an auto-correction to happen. */ private boolean handleNonSpecialCharacter(final SettingsValues settingsValues, final int codePoint, final int x, final int y, final int spaceState, - // TODO: remove these arguments - final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { mSpaceState = SpaceState.NONE; final boolean didAutoCorrect; if (settingsValues.isWordSeparator(codePoint) || Character.getType(codePoint) == Character.OTHER_SYMBOL) { didAutoCorrect = handleSeparator(settingsValues, codePoint, - Constants.SUGGESTION_STRIP_COORDINATE == x, spaceState, keyboardSwitcher, + Constants.SUGGESTION_STRIP_COORDINATE == x, spaceState, inputTransaction, handler); if (settingsValues.mIsInternal) { LatinImeLoggerUtils.onSeparator((char)codePoint, x, y); @@ -658,14 +663,14 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } else { commitTyped(settingsValues, LastComposedWord.NOT_A_SEPARATOR); } } handleNonSeparator(settingsValues, codePoint, x, y, spaceState, - keyboardSwitcher, handler); + inputTransaction, handler); } return didAutoCorrect; } @@ -677,11 +682,13 @@ public final class InputLogic { * @param x the x-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. * @param y the y-coordinate of the key press, or Contants.NOT_A_COORDINATE if not applicable. * @param spaceState the space state at start of the batch input. + * @param inputTransaction The transaction in progress. */ private void handleNonSeparator(final SettingsValues settingsValues, final int codePoint, final int x, final int y, final int spaceState, - // TODO: Remove these arguments - final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + final InputTransaction inputTransaction, + // TODO: Remove this argument + final LatinIME.UIHandler handler) { // TODO: refactor this method to stop flipping isComposingWord around all the time, and // make it shorter (possibly cut into several pieces). Also factor handleNonSpecialCharacter // which has the same name as other handle* methods but is not the same. @@ -700,7 +707,7 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the character at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); isComposingWord = false; } @@ -737,8 +744,7 @@ public final class InputLogic { // We pass 1 to getPreviousWordForSuggestion because we were not composing a word // yet, so the word we want is the 1st word before the cursor. mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime( - getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()), - getNthPreviousWordForSuggestion( + inputTransaction.mShiftState, getNthPreviousWordForSuggestion( settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */)); } mConnection.setComposingText(getTextWithUnderline( @@ -750,7 +756,7 @@ public final class InputLogic { sendKeyCodePoint(settingsValues, codePoint); if (swapWeakSpace) { - swapSwapperAndSpace(keyboardSwitcher); + swapSwapperAndSpace(inputTransaction); mSpaceState = SpaceState.WEAK; } // In case the "add to dictionary" hint was still displayed. @@ -768,12 +774,14 @@ public final class InputLogic { * @param codePoint the code point associated with the key. * @param isFromSuggestionStrip whether this code point comes from the suggestion strip. * @param spaceState the space state at start of the batch input. + * @param inputTransaction The transaction in progress. * @return whether this caused an auto-correction to happen. */ private boolean handleSeparator(final SettingsValues settingsValues, final int codePoint, final boolean isFromSuggestionStrip, final int spaceState, - // TODO: remove these arguments - final KeyboardSwitcher keyboardSwitcher, final LatinIME.UIHandler handler) { + final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { boolean didAutoCorrect = false; // We avoid sending spaces in languages without spaces if we were composing. final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint @@ -782,7 +790,7 @@ public final class InputLogic { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the separator at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); } // isComposingWord() may have changed since we stored wasComposing @@ -828,7 +836,7 @@ public final class InputLogic { if (Constants.CODE_SPACE == codePoint) { if (settingsValues.isSuggestionsRequested()) { if (maybeDoubleSpacePeriod(settingsValues, handler)) { - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); mSpaceState = SpaceState.DOUBLE; } else if (!mSuggestedWords.isPunctuationSuggestions()) { mSpaceState = SpaceState.WEAK; @@ -839,7 +847,7 @@ public final class InputLogic { handler.postUpdateSuggestionStrip(); } else { if (swapWeakSpace) { - swapSwapperAndSpace(keyboardSwitcher); + swapSwapperAndSpace(inputTransaction); mSpaceState = SpaceState.SWAP_PUNCTUATION; } else if ((SpaceState.PHANTOM == spaceState && settingsValues.isUsuallyFollowedBySpace(codePoint)) @@ -864,7 +872,7 @@ public final class InputLogic { mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); } - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); return didAutoCorrect; } @@ -872,23 +880,24 @@ public final class InputLogic { * Handle a press on the backspace key. * @param settingsValues The current settings values. * @param spaceState The space state at start of this batch edit. + * @param inputTransaction The transaction in progress. */ private void handleBackspace(final SettingsValues settingsValues, final int spaceState, - // TODO: remove these arguments - final LatinIME.UIHandler handler, final KeyboardSwitcher keyboardSwitcher) { + final InputTransaction inputTransaction, + // TODO: remove this argument + final LatinIME.UIHandler handler) { mSpaceState = SpaceState.NONE; - final int deleteCountAtStart = mDeleteCount; mDeleteCount++; // In many cases, we may have to put the keyboard in auto-shift state again. However // we want to wait a few milliseconds before doing it to avoid the keyboard flashing // during key repeat. - handler.postUpdateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_LATER); if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can remove the character at the current cursor position. - resetEntireInputState(settingsValues, mConnection.getExpectedSelectionStart(), + resetEntireInputState(mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(), true /* clearSuggestionStrip */); // When we exit this if-clause, mWordComposer.isComposingWord() will return false. } @@ -909,7 +918,7 @@ public final class InputLogic { if (!mWordComposer.isComposingWord()) { // If we just removed the last character, auto-caps mode may have changed so we // need to re-evaluate. - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } else { if (mLastComposedWord.canRevertCommit()) { @@ -1021,7 +1030,7 @@ public final class InputLogic { true /* includeResumedWordInSuggestions */); } // We just removed at least one character. We need to update the auto-caps state. - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } @@ -1037,9 +1046,9 @@ public final class InputLogic { * * This method will check that there are two characters before the cursor and that the first * one is a space before it does the actual swapping. + * @param inputTransaction The transaction in progress. */ - // TODO: Remove this argument - private void swapSwapperAndSpace(final KeyboardSwitcher keyboardSwitcher) { + private void swapSwapperAndSpace(final InputTransaction inputTransaction) { final CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { @@ -1049,7 +1058,7 @@ public final class InputLogic { if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); } - keyboardSwitcher.updateShiftState(); + inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); } } @@ -1205,11 +1214,7 @@ public final class InputLogic { timeStampInSeconds); } - public void performUpdateSuggestionStripSync(final SettingsValues settingsValues, - // TODO: Remove this argument - final LatinIME.UIHandler handler) { - handler.cancelUpdateSuggestionStrip(); - + public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) { // Check if we have a suggestion engine attached. if (mSuggest == null || !settingsValues.isSuggestionsRequested()) { if (mWordComposer.isComposingWord()) { @@ -1229,11 +1234,15 @@ public final class InputLogic { SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(final SuggestedWords suggestedWords) { - final SuggestedWords suggestedWordsWithMaybeOlderSuggestions = - mLatinIME.maybeRetrieveOlderSuggestions( - mWordComposer.getTypedWord(), suggestedWords, - mSuggestedWords); - holder.set(suggestedWordsWithMaybeOlderSuggestions); + final String typedWord = mWordComposer.getTypedWord(); + // Show new suggestions if we have at least one. Otherwise keep the old + // suggestions with the new typed word. Exception: if the length of the + // typed word is <= 1 (after a deletion typically) we clear old suggestions. + if (suggestedWords.size() > 1 || typedWord.length() <= 1) { + holder.set(suggestedWords); + } else { + holder.set(retrieveOlderSuggestions(typedWord, mSuggestedWords)); + } } } ); @@ -1485,7 +1494,9 @@ public final class InputLogic { */ private int getActualCapsMode(final SettingsValues settingsValues, final int keyboardShiftMode) { - if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; + if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) { + return keyboardShiftMode; + } final int auto = getCurrentAutoCapsState(settingsValues); if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; @@ -1623,15 +1634,13 @@ public final class InputLogic { * This will clear the composing word, reset the last composed word, clear the suggestion * strip and tell the input connection about it so that it can refresh its caches. * - * @param settingsValues the current values of the settings. * @param newSelStart the new selection start, in java characters. * @param newSelEnd the new selection end, in java characters. * @param clearSuggestionStrip whether this method should clear the suggestion strip. */ // TODO: how is this different from startInput ?! - // TODO: remove all references to this in LatinIME and make this private - public void resetEntireInputState(final SettingsValues settingsValues, - final int newSelStart, final int newSelEnd, final boolean clearSuggestionStrip) { + private void resetEntireInputState(final int newSelStart, final int newSelEnd, + final boolean clearSuggestionStrip) { final boolean shouldFinishComposition = mWordComposer.isComposingWord(); resetComposingState(true /* alsoResetLastComposedWord */); if (clearSuggestionStrip) { @@ -1649,8 +1658,7 @@ public final class InputLogic { * * @param alsoResetLastComposedWord whether to also reset the last composed word. */ - // TODO: remove all references to this in LatinIME and make this private. - public void resetComposingState(final boolean alsoResetLastComposedWord) { + private void resetComposingState(final boolean alsoResetLastComposedWord) { mWordComposer.reset(); if (alsoResetLastComposedWord) { mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; @@ -1658,6 +1666,27 @@ public final class InputLogic { } /** + * Make a {@link com.android.inputmethod.latin.SuggestedWords} object containing a typed word + * and obsolete suggestions. + * See {@link com.android.inputmethod.latin.SuggestedWords#getTypedWordAndPreviousSuggestions( + * String, com.android.inputmethod.latin.SuggestedWords)}. + * @param typedWord The typed word as a string. + * @param previousSuggestedWords The previously suggested words. + * @return Obsolete suggestions with the newly typed word. + */ + private SuggestedWords retrieveOlderSuggestions(final String typedWord, + final SuggestedWords previousSuggestedWords) { + final SuggestedWords oldSuggestedWords = + previousSuggestedWords.isPunctuationSuggestions() ? SuggestedWords.EMPTY + : previousSuggestedWords; + final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = + SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); + return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, + false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, + true /* isObsoleteSuggestions */, false /* isPrediction */); + } + + /** * Gets a chunk of text with or the auto-correction indicator underline span as appropriate. * * This method looks at the old state of the auto-correction indicator to put or not put @@ -1674,9 +1703,8 @@ public final class InputLogic { * @param text the text on which to maybe apply the span. * @return the same text, with the auto-correction underline span if that's appropriate. */ - // TODO: remove all references to this in LatinIME and make this private. Also, shouldn't - // this go in some *Utils class instead? - public CharSequence getTextWithUnderline(final String text) { + // TODO: Shouldn't this go in some *Utils class instead? + private CharSequence getTextWithUnderline(final String text) { return mIsAutoCorrectionIndicatorOn ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(mLatinIME, text) : text; @@ -1741,8 +1769,7 @@ public final class InputLogic { * * @param settingsValues the current values of the settings. */ - // TODO: Make this private. - public void promotePhantomSpace(final SettingsValues settingsValues) { + private void promotePhantomSpace(final SettingsValues settingsValues) { if (settingsValues.shouldInsertSpacesAutomatically() && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces && !mConnection.textBeforeCursorLooksLikeURL()) { @@ -1848,7 +1875,8 @@ public final class InputLogic { final LatinIME.UIHandler handler) { // Complete any pending suggestions query first if (handler.hasPendingUpdateSuggestions()) { - performUpdateSuggestionStripSync(settingsValues, handler); + handler.cancelUpdateSuggestionStrip(); + performUpdateSuggestionStripSync(settingsValues); } final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); final String typedWord = mWordComposer.getTypedWord(); @@ -1892,8 +1920,7 @@ public final class InputLogic { * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_* * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none. */ - // TODO: Make this private - public void commitChosenWord(final SettingsValues settingsValues, final String chosenWord, + private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord, final int commitType, final String separatorString) { final SuggestedWords suggestedWords = mSuggestedWords; final CharSequence chosenWordWithSuggestions = diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index c87dd1589..11d369282 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -42,8 +42,6 @@ public final class DebugSettings extends PreferenceFragment public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch"; public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; public static final String PREF_STATISTICS_LOGGING = "enable_logging"; - public static final String PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG = - "use_only_personalization_dictionary_for_debug"; public static final String PREF_KEY_PREVIEW_SHOW_UP_START_SCALE = "pref_key_preview_show_up_start_scale"; public static final String PREF_KEY_PREVIEW_DISMISS_END_SCALE = diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 77968f79a..50fbbb19f 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -84,7 +84,6 @@ public final class SettingsValues { public final float mAutoCorrectionThreshold; public final boolean mCorrectionEnabled; public final int mSuggestionVisibility; - public final boolean mUseOnlyPersonalizationDictionaryForDebug; public final int mDisplayOrientation; private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds; @@ -168,8 +167,6 @@ public final class SettingsValues { prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_SCALE, ResourceUtils.getFloatFromFraction( res, R.fraction.config_key_preview_dismiss_end_scale)); - mUseOnlyPersonalizationDictionaryForDebug = prefs.getBoolean( - DebugSettings.PREF_USE_ONLY_PERSONALIZATION_DICTIONARY_FOR_DEBUG, false); mDisplayOrientation = res.getConfiguration().orientation; mAppWorkarounds = new AsyncResultHolder<AppWorkaroundsUtils>(); final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo( @@ -390,8 +387,6 @@ public final class SettingsValues { sb.append("" + mCorrectionEnabled); sb.append("\n mSuggestionVisibility = "); sb.append("" + mSuggestionVisibility); - sb.append("\n mUseOnlyPersonalizationDictionaryForDebug = "); - sb.append("" + mUseOnlyPersonalizationDictionaryForDebug); sb.append("\n mDisplayOrientation = "); sb.append("" + mDisplayOrientation); sb.append("\n mAppWorkarounds = "); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 4ef562d8f..43cb11b14 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -35,7 +35,6 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.MainKeyboardView; import com.android.inputmethod.keyboard.MoreKeysPanel; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; @@ -281,8 +280,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick private final MoreKeysPanel.Controller mMoreSuggestionsController = new MoreKeysPanel.Controller() { @Override - public void onDismissMoreKeysPanel(final MoreKeysPanel panel) { - mMainKeyboardView.onDismissMoreKeysPanel(panel); + public void onDismissMoreKeysPanel() { + mMainKeyboardView.onDismissMoreKeysPanel(); } @Override @@ -291,7 +290,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } @Override - public void onCancelMoreKeysPanel(final MoreKeysPanel panel) { + public void onCancelMoreKeysPanel() { dismissMoreSuggestionsPanel(); } }; @@ -312,7 +311,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick } boolean showMoreSuggestions() { - final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard(); + final Keyboard parentKeyboard = mMainKeyboardView.getKeyboard(); if (parentKeyboard == null) { return false; } @@ -320,6 +319,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick if (!layoutHelper.mMoreSuggestionsAvailable) { return false; } + // Dismiss another {@link MoreKeysPanel} that may be being showed, for example + // {@link MoreKeysKeyboardView}. + mMainKeyboardView.onDismissMoreKeysPanel(); + // Dismiss all key previews and sliding key input preview that may be being showed. + mMainKeyboardView.dismissAllKeyPreviews(); + mMainKeyboardView.dismissSlidingKeyInputPreview(); final int stripWidth = getWidth(); final View container = mMoreSuggestionsContainer; final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); diff --git a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java index ef1d0f42c..2bb30a2ba 100644 --- a/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtils.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.latin.R; @@ -42,6 +43,7 @@ public final class AdditionalSubtypeUtils { // This utility class is not publicly instantiable. } + @UsedForTesting public static boolean isAdditionalSubtype(final InputMethodSubtype subtype) { return subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE); } |