diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
18 files changed, 479 insertions, 498 deletions
diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java index 307b81d43..460930f16 100644 --- a/java/src/com/android/inputmethod/latin/AutoDictionary.java +++ b/java/src/com/android/inputmethod/latin/AutoDictionary.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google Inc. + * Copyright (C) 2010 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 @@ -41,13 +41,8 @@ public class AutoDictionary extends ExpandableDictionary { static final int FREQUENCY_FOR_PICKED = 3; // Weight added to a user typing a new word that doesn't get corrected (or is reverted) static final int FREQUENCY_FOR_TYPED = 1; - // A word that is frequently typed and gets promoted to the user dictionary, uses this - // frequency. - static final int FREQUENCY_FOR_AUTO_ADD = 250; // If the user touches a typed word 2 times or more, it will become valid. private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED; - // If the user touches a typed word 4 times or more, it will be added to the user dict. - private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED; private LatinIME mIme; // Locale for which this auto dictionary is storing words @@ -151,11 +146,6 @@ public class AutoDictionary extends ExpandableDictionary { freq = freq < 0 ? addFrequency : freq + addFrequency; super.addWord(word, freq); - if (freq >= PROMOTION_THRESHOLD) { - mIme.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD); - freq = 0; - } - synchronized (mPendingWritesLock) { // Write a null frequency if it is to be deleted from the db mPendingWrites.put(word, freq == 0 ? null : new Integer(freq)); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index d95fb9638..9748d6006 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -196,8 +196,9 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); + final int proximityInfo = keyboard == null ? 0 : keyboard.getProximityInfo(); return getSuggestionsNative( - mNativeDict, keyboard.getProximityInfo(), + mNativeDict, proximityInfo, codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize, mFlags, outputChars, scores); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 562580d41..7ce92920d 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -78,16 +78,20 @@ class BinaryDictionaryGetter { } else { try { // If that was no-go, try to find a publicly exported dictionary. - return BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context); + List<AssetFileAddress> listFromContentProvider = + BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context); + if (null != listFromContentProvider) { + return listFromContentProvider; + } + // If the list is null, fall through and return the fallback } catch (FileNotFoundException e) { Log.e(TAG, "Unable to create dictionary file from provider for locale " + locale.toString() + ": falling back to internal dictionary"); - return Arrays.asList(loadFallbackResource(context, fallbackResId)); } catch (IOException e) { Log.e(TAG, "Unable to read source data for locale " + locale.toString() + ": falling back to internal dictionary"); - return Arrays.asList(loadFallbackResource(context, fallbackResId)); } + return Arrays.asList(loadFallbackResource(context, fallbackResId)); } } } diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index abdf30e6b..fe3c72f4c 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -16,8 +16,6 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; - import android.content.Context; import android.content.res.Resources; import android.graphics.Color; @@ -40,11 +38,12 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + import java.util.ArrayList; import java.util.List; @@ -57,6 +56,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private static final boolean DBG = LatinImeLogger.sDBG; private final ArrayList<View> mWords = new ArrayList<View>(); + private final ArrayList<View> mDividers = new ArrayList<View>(); private final boolean mConfigCandidateHighlightFontColorEnabled; private final CharacterStyle mInvertedForegroundColorSpan; private final CharacterStyle mInvertedBackgroundColorSpan; @@ -148,10 +148,11 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo tv.setOnClickListener(this); if (i == 0) tv.setOnLongClickListener(this); - ImageView divider = (ImageView)v.findViewById(R.id.candidate_divider); - // Do not display divider of first candidate. - divider.setVisibility(i == 0 ? INVISIBLE : VISIBLE); mWords.add(v); + if (i > 0) { + View divider = inflater.inflate(R.layout.candidate_divider, null); + mDividers.add(divider); + } } scrollTo(0, getScrollY()); @@ -237,6 +238,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } else { dv.setVisibility(GONE); } + if (i > 0) + addView(mDividers.get(i - 1)); addView(v); } @@ -275,7 +278,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo setSuggestions(builder.build()); mShowingAddToDictionary = true; // Disable R.string.hint_add_to_dictionary button - TextView tv = (TextView)getChildAt(1).findViewById(R.id.candidate_word); + TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word); tv.setClickable(false); } @@ -308,7 +311,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo previewText.setText(word); previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - View v = getChildAt(index); + View v = mWords.get(index); final int[] offsetInWindow = new int[2]; v.getLocationInWindow(offsetInWindow); final int posX = offsetInWindow[0]; diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 605676d70..bba331868 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -142,6 +142,25 @@ public class DictionaryFactory { return hasDictionary; } + // TODO: Do not use the size of the dictionary as an unique dictionary ID. + public static Long getDictionaryId(Context context, Locale locale) { + final Resources res = context.getResources(); + final Locale saveLocale = Utils.setSystemLocale(res, locale); + + final int resourceId = Utils.getMainDictionaryResourceId(res); + final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); + final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH) + ? afd.getLength() + : null; + try { + if (null != afd) afd.close(); + } catch (java.io.IOException e) { + } + + Utils.setSystemLocale(res, saveLocale); + return size; + } + // TODO: Find the Right Way to find out whether the resource is a placeholder or not. // Suggestion : strip the locale, open the placeholder file and store its offset. // Upon opening the file, if it's the same offset, then it's the placeholder. diff --git a/java/src/com/android/inputmethod/latin/EditingUtils.java b/java/src/com/android/inputmethod/latin/EditingUtils.java index 39e7e402f..e56aa695d 100644 --- a/java/src/com/android/inputmethod/latin/EditingUtils.java +++ b/java/src/com/android/inputmethod/latin/EditingUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. + * Copyright (C) 2009 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 diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 26391fe46..97a4a1816 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -229,6 +229,7 @@ public class ExpandableDictionary extends Dictionary { * Returns the word's frequency or -1 if not found */ protected int getWordFrequency(CharSequence word) { + // Case-sensitive search Node node = searchNode(mRoots, word, 0, word.length()); return (node == null) ? -1 : node.mFrequency; } @@ -366,12 +367,16 @@ public class ExpandableDictionary extends Dictionary { /** * Adds bigrams to the in-memory trie structure that is being used to retrieve any word - * @param frequency frequency for this bigrams - * @param addFrequency if true, it adds to current frequency + * @param frequency frequency for this bigram + * @param addFrequency if true, it adds to current frequency, else it overwrites the old value * @return returns the final frequency */ private int addOrSetBigram(String word1, String word2, int frequency, boolean addFrequency) { - Node firstWord = searchWord(mRoots, word1, 0, null); + // We don't want results to be different according to case of the looked up left hand side + // word. We do want however to return the correct case for the right hand side. + // So we want to squash the case of the left hand side, and preserve that of the right + // hand side word. + Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); Node secondWord = searchWord(mRoots, word2, 0, null); LinkedList<NextWord> bigram = firstWord.mNGrams; if (bigram == null || bigram.size() == 0) { @@ -437,8 +442,12 @@ public class ExpandableDictionary extends Dictionary { } } - private void runReverseLookUp(final CharSequence previousWord, final WordCallback callback) { - Node prevWord = searchNode(mRoots, previousWord, 0, previousWord.length()); + private void runBigramReverseLookUp(final CharSequence previousWord, + final WordCallback callback) { + // Search for the lowercase version of the word only, because that's where bigrams + // store their sons. + Node prevWord = searchNode(mRoots, previousWord.toString().toLowerCase(), 0, + previousWord.length()); if (prevWord != null && prevWord.mNGrams != null) { reverseLookUp(prevWord.mNGrams, callback); } @@ -448,7 +457,7 @@ public class ExpandableDictionary extends Dictionary { public void getBigrams(final WordComposer codes, final CharSequence previousWord, final WordCallback callback) { if (!reloadDictionaryIfRequired()) { - runReverseLookUp(previousWord, callback); + runBigramReverseLookUp(previousWord, callback); } } @@ -494,14 +503,20 @@ public class ExpandableDictionary extends Dictionary { } /** - * Search for the terminal node of the word + * Recursively search for the terminal node of the word. + * + * One iteration takes the full word to search for and the current index of the recursion. + * + * @param children the node of the trie to search under. + * @param word the word to search for. Only read [offset..length] so there may be trailing chars + * @param offset the index in {@code word} this recursion should operate on. + * @param length the length of the input word. * @return Returns the terminal node of the word if the word exists */ private Node searchNode(final NodeArray children, final CharSequence word, final int offset, final int length) { - // TODO Consider combining with addWordRec final int count = children.mLength; - char currentChar = word.charAt(offset); + final char currentChar = word.charAt(offset); for (int j = 0; j < count; j++) { final Node node = children.mData[j]; if (node.mCode == currentChar) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 8b130aecd..a4a04ffb1 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -16,21 +16,6 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.compat.CompatUtils; -import com.android.inputmethod.compat.EditorInfoCompatUtils; -import com.android.inputmethod.compat.InputConnectionCompatUtils; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; -import com.android.inputmethod.compat.InputTypeCompatUtils; -import com.android.inputmethod.deprecated.LanguageSwitcherProxy; -import com.android.inputmethod.deprecated.VoiceProxy; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardActionListener; -import com.android.inputmethod.keyboard.KeyboardSwitcher; -import com.android.inputmethod.keyboard.KeyboardView; -import com.android.inputmethod.keyboard.LatinKeyboard; -import com.android.inputmethod.keyboard.LatinKeyboardView; - import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -58,7 +43,6 @@ import android.util.PrintWriterPrinter; import android.util.Printer; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; @@ -68,7 +52,23 @@ import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.InputConnection; -import android.widget.LinearLayout; + +import com.android.inputmethod.compat.CompatUtils; +import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.compat.InputConnectionCompatUtils; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; +import com.android.inputmethod.compat.InputTypeCompatUtils; +import com.android.inputmethod.compat.SuggestionSpanUtils; +import com.android.inputmethod.deprecated.LanguageSwitcherProxy; +import com.android.inputmethod.deprecated.VoiceProxy; +import com.android.inputmethod.deprecated.recorrection.Recorrection; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.KeyboardSwitcher; +import com.android.inputmethod.keyboard.KeyboardView; +import com.android.inputmethod.keyboard.LatinKeyboard; +import com.android.inputmethod.keyboard.LatinKeyboardView; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -81,7 +81,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean PERF_DEBUG = false; private static final boolean TRACE = false; - private static boolean DEBUG = LatinImeLogger.sDBG; + private static boolean DEBUG; /** * The private IME option used to indicate that no microphone should be @@ -216,15 +216,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void handleMessage(Message msg) { final KeyboardSwitcher switcher = mKeyboardSwitcher; - final LatinKeyboardView inputView = switcher.getInputView(); + final LatinKeyboardView inputView = switcher.getKeyboardView(); switch (msg.what) { case MSG_UPDATE_SUGGESTIONS: updateSuggestions(); break; case MSG_UPDATE_OLD_SUGGESTIONS: - mRecorrection.setRecorrectionSuggestions(mVoiceProxy, mCandidateView, mSuggest, - mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, mLastSelectionStart, - mLastSelectionEnd, mSettingsValues.mWordSeparators); + mRecorrection.fetchAndDisplayRecorrectionSuggestions(mVoiceProxy, mCandidateView, + mSuggest, mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, + mLastSelectionStart, mLastSelectionEnd, mSettingsValues.mWordSeparators); break; case MSG_UPDATE_SHIFT_STATE: switcher.updateShiftState(); @@ -306,7 +306,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void startDisplayLanguageOnSpacebar(boolean localeChanged) { removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR); removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR); - final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + final LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) { final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard(); // The language is always displayed when the delay is negative. @@ -357,6 +357,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); mRecorrection = Recorrection.getInstance(); + DEBUG = LatinImeLogger.sDBG; loadSettings(); @@ -405,7 +406,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void initSuggest() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = new Locale(localeStr); + final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); final Resources res = mResources; final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale); @@ -439,7 +440,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /* package private */ void resetSuggestMainDict() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = new Locale(localeStr); + final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); int mainDicResId = Utils.getMainDictionaryResourceId(mResources); mSuggest.resetMainDict(this, mainDicResId, keyboardLocale); } @@ -486,24 +487,28 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } @Override - public View onCreateCandidatesView() { - LayoutInflater inflater = getLayoutInflater(); - LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null); - mCandidateViewContainer = container; - mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height); - mCandidateView = (CandidateView) container.findViewById(R.id.candidates); + public void setInputView(View view) { + super.setInputView(view); + mCandidateViewContainer = view.findViewById(R.id.candidates_container); + mCandidateView = (CandidateView) view.findViewById(R.id.candidates); mCandidateView.setService(this); - setCandidatesViewShown(true); - return container; + mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height); + } + + @Override + public void setCandidatesView(View view) { + // To ensure that CandidatesView will never be set. + return; } @Override public void onStartInputView(EditorInfo attribute, boolean restarting) { final KeyboardSwitcher switcher = mKeyboardSwitcher; - LatinKeyboardView inputView = switcher.getInputView(); + LatinKeyboardView inputView = switcher.getKeyboardView(); if (DEBUG) { - Log.d(TAG, "onStartInputView: " + inputView); + Log.d(TAG, "onStartInputView: inputType=" + ((attribute == null) ? "none" + : String.format("0x%08x", attribute.inputType))); } // In landscape mode, this method gets called without the input view being created. if (inputView == null) { @@ -549,13 +554,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switcher.updateShiftState(); } - setCandidatesViewShownInternal(isCandidateStripVisible(), false /* needsInputViewShown */ ); + setSuggestionStripShownInternal(isCandidateStripVisible(), /* needsInputViewShown */ false); // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); updateCorrectionMode(); - inputView.setKeyPreviewEnabled(mSettingsValues.mPopupOn); + inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn, + mSettingsValues.mKeyPreviewPopupDismissDelay); inputView.setProximityCorrectionEnabled(true); // If we just entered a text field, maybe it has some old text that requires correction mRecorrection.checkRecorrectionOnStart(); @@ -622,6 +628,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } @Override + public void onWindowHidden() { + super.onWindowHidden(); + KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); + if (inputView != null) inputView.closing(); + } + + @Override public void onFinishInput() { super.onFinishInput(); @@ -630,7 +643,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging); - KeyboardView inputView = mKeyboardSwitcher.getInputView(); + KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.closing(); if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites(); if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites(); @@ -639,7 +652,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onFinishInputView(boolean finishingInput) { super.onFinishInputView(finishingInput); - KeyboardView inputView = mKeyboardSwitcher.getInputView(); + KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.setForeground(false); // Remove pending messages related to update suggestions mHandler.cancelUpdateSuggestions(); @@ -684,7 +697,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // If the composing span has been cleared, save the typed word in the history for // recorrection before we reset the candidate strip. Then, we'll be able to show // suggestions for recorrection right away. - mRecorrection.saveWordInHistory(mWord, mComposing); + mRecorrection.saveRecorrectionSuggestion(mWord, mComposing); } mComposing.setLength(0); mHasUncommittedTypedChars = false; @@ -795,11 +808,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); mBestWord = null; - setCandidatesViewShown(true); + setSuggestionStripShown(true); } } - private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) { + private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { // TODO: Modify this if we support candidates with hard keyboard if (onEvaluateInputViewShown()) { final boolean shouldShowCandidates = shown @@ -807,26 +820,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isExtractViewShown()) { // No need to have extra space to show the key preview. mCandidateViewContainer.setMinimumHeight(0); - super.setCandidatesViewShown(shown); + mCandidateViewContainer.setVisibility( + shouldShowCandidates ? View.VISIBLE : View.GONE); } else { // We must control the visibility of the suggestion strip in order to avoid clipped // key previews, even when we don't show the suggestion strip. mCandidateViewContainer.setVisibility( shouldShowCandidates ? View.VISIBLE : View.INVISIBLE); - super.setCandidatesViewShown(true); } } } - @Override - public void setCandidatesViewShown(boolean shown) { - setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ ); + private void setSuggestionStripShown(boolean shown) { + setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); } @Override public void onComputeInsets(InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); - final KeyboardView inputView = mKeyboardSwitcher.getInputView(); + final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView == null) return; final int containerHeight = mCandidateViewContainer.getHeight(); @@ -868,8 +880,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: - if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) { - if (mKeyboardSwitcher.getInputView().handleBack()) { + if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getKeyboardView() != null) { + if (mKeyboardSwitcher.getKeyboardView().handleBack()) { return true; } } @@ -1005,14 +1017,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void onSettingsKeyPressed() { - if (!isShowingOptionDialog()) { - if (!mSettingsValues.mEnableShowSubtypeSettings) { - showSubtypeSelectorAndSettings(); - } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) { - showOptionsMenu(); - } else { - launchSettings(); - } + if (isShowingOptionDialog()) + return; + if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { + showSubtypeSelectorAndSettings(); + } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) { + showOptionsMenu(); + } else { + launchSettings(); } } @@ -1221,7 +1233,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mHasUncommittedTypedChars) { mHasUncommittedTypedChars = true; mComposing.setLength(0); - mRecorrection.saveWordInHistory(mWord, mBestWord); + mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord); mWord.reset(); clearSuggestions(); } @@ -1356,7 +1368,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar commitTyped(getCurrentInputConnection()); mVoiceProxy.handleClose(); requestHideSelf(0); - LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.closing(); } @@ -1392,7 +1404,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (DEBUG) { Log.d(TAG, "Switch to keyboard view."); } - View v = mKeyboardSwitcher.getInputView(); + View v = mKeyboardSwitcher.getKeyboardView(); if (v != null) { // Confirms that the keyboard view doesn't have parent view. ViewParent p = v.getParent(); @@ -1401,7 +1413,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } setInputView(v); } - setCandidatesViewShown(isCandidateStripVisible()); + setSuggestionStripShown(isCandidateStripVisible()); updateInputViewShown(); mHandler.postUpdateSuggestions(); } @@ -1411,9 +1423,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public void setSuggestions(SuggestedWords words) { - if (mVoiceProxy.getAndResetIsShowingHint()) { - setCandidatesView(mCandidateViewContainer); - } +// if (mVoiceProxy.getAndResetIsShowingHint()) { +// setCandidatesView(mCandidateViewContainer); +// } if (mCandidateView != null) { mCandidateView.setSuggestions(words); @@ -1443,7 +1455,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(), mSettingsValues.mWordSeparators); SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder( - mKeyboardSwitcher.getInputView(), word, prevWord); + mKeyboardSwitcher.getKeyboardView(), word, prevWord); boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection(); final CharSequence typedWord = word.getTypedWord(); @@ -1464,14 +1476,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // in most cases, suggestion count is 1 when typed word's length is 1, but we do always // need to clear the previous state when the user starts typing a word (i.e. typed word's // length == 1). - if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid - || mCandidateView.isShowingAddToDictionaryHint()) { - builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable); - } else { - final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); - if (previousSuggestions == mSettingsValues.mSuggestPuncList) - return; - builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); + if (typedWord != null) { + if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid + || mCandidateView.isShowingAddToDictionaryHint()) { + builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion( + correctionAvailable); + } else { + final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); + if (previousSuggestions == mSettingsValues.mSuggestPuncList) + return; + builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); + } } showSuggestions(builder.build(), typedWord); } @@ -1489,7 +1504,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { mBestWord = null; } - setCandidatesViewShown(isCandidateStripVisible()); + setSuggestionStripShown(isCandidateStripVisible()); } private boolean pickDefaultSuggestion(int separatorCode) { @@ -1501,7 +1516,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mBestWord != null && mBestWord.length() > 0) { TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord, separatorCode); mJustAccepted = true; - pickSuggestion(mBestWord); + commitBestWord(mBestWord); // Add the word to the auto dictionary if it's not a known word addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED); return true; @@ -1548,7 +1563,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // a magic space even if it was a normal space. This is meant to help in case the user // pressed space on purpose of displaying the suggestion strip punctuation. final char primaryCode = suggestion.charAt(0); - final int toLeft = (ic == null) ? 0 : ic.getTextBeforeCursor(1, 0).charAt(0); + final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : ""; + final int toLeft = (ic == null || TextUtils.isEmpty(beforeText)) + ? 0 : beforeText.charAt(0); final boolean oldMagicSpace = mJustAddedMagicSpace; if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true; onCodeInput(primaryCode, new int[] { primaryCode }, @@ -1566,7 +1583,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mWord.reset(); } mJustAccepted = true; - pickSuggestion(suggestion); + commitBestWord(suggestion); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED); @@ -1602,12 +1619,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // TextEntryState.State.PICKED_SUGGESTION state. TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); - // From there on onUpdateSelection() will fire so suggestions will be updated - } else if (!showingAddToDictionaryHint) { + } + if (!showingAddToDictionaryHint) { // If we're not showing the "Touch again to save", then show corrections again. // In case the cursor position doesn't change, make sure we show the suggestions again. - clearSuggestions(); - mHandler.postUpdateOldSuggestions(); + updateBigramPredictions(); + // Updating the predictions right away may be slow and feel unresponsive on slower + // terminals. On the other hand if we just postUpdateBigramPredictions() it will + // take a noticeable delay to update them which may feel uneasy. } if (showingAddToDictionaryHint) { mCandidateView.showAddToDictionaryHint(suggestion); @@ -1620,25 +1639,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * Commits the chosen word to the text field and saves it for later * retrieval. - * @param suggestion the suggestion picked by the user to be committed to - * the text field */ - private void pickSuggestion(CharSequence suggestion) { + private void commitBestWord(CharSequence bestWord) { KeyboardSwitcher switcher = mKeyboardSwitcher; if (!switcher.isKeyboardAvailable()) return; InputConnection ic = getCurrentInputConnection(); if (ic != null) { - mVoiceProxy.rememberReplacedWord(suggestion, mSettingsValues.mWordSeparators); - ic.commitText(suggestion, 1); + mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); + SuggestedWords suggestedWords = mCandidateView.getSuggestions(); + ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( + this, bestWord, suggestedWords), 1); } - mRecorrection.saveWordInHistory(mWord, suggestion); + mRecorrection.saveRecorrectionSuggestion(mWord, bestWord); mHasUncommittedTypedChars = false; - mCommittedLength = suggestion.length(); + mCommittedLength = bestWord.length(); } private static final WordComposer sEmptyWordComposer = new WordComposer(); - private void updateBigramPredictions() { + public void updateBigramPredictions() { if (mSuggest == null || !isSuggestionsRequested()) return; @@ -1650,7 +1669,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(), mSettingsValues.mWordSeparators); SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder( - mKeyboardSwitcher.getInputView(), sEmptyWordComposer, prevWord); + mKeyboardSwitcher.getKeyboardView(), sEmptyWordComposer, prevWord); if (builder.size() > 0) { // Explicitly supply an empty typed word (the no-second-arg version of @@ -1663,7 +1682,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void setPunctuationSuggestions() { setSuggestions(mSettingsValues.mSuggestPuncList); - setCandidatesViewShown(isCandidateStripVisible()); + setSuggestionStripShown(isCandidateStripVisible()); } private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) { @@ -1872,7 +1891,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // if mAudioManager is null, we don't have the ringer state yet // mAudioManager will be set by updateRingerMode if (mAudioManager == null) { - if (mKeyboardSwitcher.getInputView() != null) { + if (mKeyboardSwitcher.getKeyboardView() != null) { updateRingerMode(); } } @@ -1899,7 +1918,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!mSettingsValues.mVibrateOn) { return; } - LatinKeyboardView inputView = mKeyboardSwitcher.getInputView(); + LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) { inputView.performHapticFeedback( HapticFeedbackConstants.KEYBOARD_TAP, @@ -1907,18 +1926,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - public void promoteToUserDictionary(String word, int frequency) { - if (mUserDictionary.isValidWord(word)) return; - mUserDictionary.addWord(word, frequency); - } - public WordComposer getCurrentWord() { return mWord; } - public boolean getPopupOn() { - return mSettingsValues.mPopupOn; - } boolean isSoundOn() { return mSettingsValues.mSoundOn && !mSilentModeOn; } @@ -2026,7 +2037,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void showOptionsMenuInternal(CharSequence title, CharSequence[] items, DialogInterface.OnClickListener listener) { - final IBinder windowToken = mKeyboardSwitcher.getInputView().getWindowToken(); + final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken(); if (windowToken == null) return; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setCancelable(true); @@ -2062,7 +2073,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar p.println(" TextEntryState.state=" + TextEntryState.getState()); p.println(" mSoundOn=" + mSettingsValues.mSoundOn); p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn); - p.println(" mPopupOn=" + mSettingsValues.mPopupOn); + p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn); } // Characters per second measurement diff --git a/java/src/com/android/inputmethod/latin/Recorrection.java b/java/src/com/android/inputmethod/latin/Recorrection.java deleted file mode 100644 index 3fa6292ba..000000000 --- a/java/src/com/android/inputmethod/latin/Recorrection.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (C) 2011 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.latin; - -import com.android.inputmethod.compat.InputConnectionCompatUtils; -import com.android.inputmethod.deprecated.VoiceProxy; -import com.android.inputmethod.keyboard.KeyboardSwitcher; - -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.text.TextUtils; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; -import android.view.inputmethod.InputConnection; - -import java.util.ArrayList; - -/** - * Manager of re-correction functionalities - */ -public class Recorrection { - private static final Recorrection sInstance = new Recorrection(); - - private LatinIME mService; - private boolean mRecorrectionEnabled = false; - private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>(); - - public static Recorrection getInstance() { - return sInstance; - } - - public static void init(LatinIME context, SharedPreferences prefs) { - if (context == null || prefs == null) { - return; - } - sInstance.initInternal(context, prefs); - } - - private Recorrection() { - } - - public boolean isRecorrectionEnabled() { - return mRecorrectionEnabled; - } - - private void initInternal(LatinIME context, SharedPreferences prefs) { - final Resources res = context.getResources(); - // If the option should not be shown, do not read the re-correction preference - // but always use the default setting defined in the resources. - if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) { - mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED, - res.getBoolean(R.bool.config_default_recorrection_enabled)); - } else { - mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled); - } - mService = context; - } - - public void checkRecorrectionOnStart() { - if (!mRecorrectionEnabled) return; - - final InputConnection ic = mService.getCurrentInputConnection(); - if (ic == null) return; - // There could be a pending composing span. Clean it up first. - ic.finishComposingText(); - - if (mService.isShowingSuggestionsStrip() && mService.isSuggestionsRequested()) { - // First get the cursor position. This is required by setOldSuggestions(), so that - // it can pass the correct range to setComposingRegion(). At this point, we don't - // have valid values for mLastSelectionStart/End because onUpdateSelection() has - // not been called yet. - ExtractedTextRequest etr = new ExtractedTextRequest(); - etr.token = 0; // anything is fine here - ExtractedText et = ic.getExtractedText(etr, 0); - if (et == null) return; - mService.setLastSelection( - et.startOffset + et.selectionStart, et.startOffset + et.selectionEnd); - - // Then look for possible corrections in a delayed fashion - if (!TextUtils.isEmpty(et.text) && mService.isCursorTouchingWord()) { - mService.mHandler.postUpdateOldSuggestions(); - } - } - } - - public void updateRecorrectionSelection(KeyboardSwitcher keyboardSwitcher, - CandidateView candidateView, int candidatesStart, int candidatesEnd, int newSelStart, - int newSelEnd, int oldSelStart, int lastSelectionStart, - int lastSelectionEnd, boolean hasUncommittedTypedChars) { - if (mRecorrectionEnabled && mService.isShowingSuggestionsStrip()) { - // Don't look for corrections if the keyboard is not visible - if (keyboardSwitcher.isInputViewShown()) { - // Check if we should go in or out of correction mode. - if (mService.isSuggestionsRequested() - && (candidatesStart == candidatesEnd || newSelStart != oldSelStart - || TextEntryState.isRecorrecting()) - && (newSelStart < newSelEnd - 1 || !hasUncommittedTypedChars)) { - if (mService.isCursorTouchingWord() || lastSelectionStart < lastSelectionEnd) { - mService.mHandler.cancelUpdateBigramPredictions(); - mService.mHandler.postUpdateOldSuggestions(); - } else { - abortRecorrection(false); - // If showing the "touch again to save" hint, do not replace it. Else, - // show the bigrams if we are at the end of the text, punctuation otherwise. - if (candidateView != null - && !candidateView.isShowingAddToDictionaryHint()) { - InputConnection ic = mService.getCurrentInputConnection(); - if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) { - if (!mService.isShowingPunctuationList()) { - mService.setPunctuationSuggestions(); - } - } else { - mService.mHandler.postUpdateBigramPredictions(); - } - } - } - } - } - } - } - - public void saveWordInHistory(WordComposer word, CharSequence result) { - if (word.size() <= 1) { - return; - } - // Skip if result is null. It happens in some edge case. - if (TextUtils.isEmpty(result)) { - return; - } - - // Make a copy of the CharSequence, since it is/could be a mutable CharSequence - final String resultCopy = result.toString(); - WordAlternatives entry = new WordAlternatives(resultCopy, new WordComposer(word)); - mWordHistory.add(entry); - } - - public void clearWordsInHistory() { - mWordHistory.clear(); - } - - /** - * Tries to apply any typed alternatives for the word if we have any cached alternatives, - * otherwise tries to find new corrections and completions for the word. - * @param touching The word that the cursor is touching, with position information - * @return true if an alternative was found, false otherwise. - */ - public boolean applyTypedAlternatives(WordComposer word, Suggest suggest, - KeyboardSwitcher keyboardSwitcher, EditingUtils.SelectedWord touching) { - // If we didn't find a match, search for result in typed word history - WordComposer foundWord = null; - WordAlternatives alternatives = null; - // Search old suggestions to suggest re-corrected suggestions. - for (WordAlternatives entry : mWordHistory) { - if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) { - foundWord = entry.mWordComposer; - alternatives = entry; - break; - } - } - // If we didn't find a match, at least suggest corrections as re-corrected suggestions. - if (foundWord == null - && (AutoCorrection.isValidWord(suggest.getUnigramDictionaries(), - touching.mWord, true))) { - foundWord = new WordComposer(); - for (int i = 0; i < touching.mWord.length(); i++) { - foundWord.add(touching.mWord.charAt(i), - new int[] { touching.mWord.charAt(i) }, WordComposer.NOT_A_COORDINATE, - WordComposer.NOT_A_COORDINATE); - } - foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0))); - } - // Found a match, show suggestions - if (foundWord != null || alternatives != null) { - if (alternatives == null) { - alternatives = new WordAlternatives(touching.mWord, foundWord); - } - showRecorrections(suggest, keyboardSwitcher, alternatives); - if (foundWord != null) { - word.init(foundWord); - } else { - word.reset(); - } - return true; - } - return false; - } - - - private void showRecorrections(Suggest suggest, KeyboardSwitcher keyboardSwitcher, - WordAlternatives alternatives) { - SuggestedWords.Builder builder = alternatives.getAlternatives(suggest, keyboardSwitcher); - builder.setTypedWordValid(false).setHasMinimalSuggestion(false); - mService.showSuggestions(builder.build(), alternatives.getOriginalWord()); - } - - public void setRecorrectionSuggestions(VoiceProxy voiceProxy, CandidateView candidateView, - Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word, - boolean hasUncommittedTypedChars, int lastSelectionStart, int lastSelectionEnd, - String wordSeparators) { - if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; - voiceProxy.setShowingVoiceSuggestions(false); - if (candidateView != null && candidateView.isShowingAddToDictionaryHint()) { - return; - } - InputConnection ic = mService.getCurrentInputConnection(); - if (ic == null) return; - if (!hasUncommittedTypedChars) { - // Extract the selected or touching text - EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic, - lastSelectionStart, lastSelectionEnd, wordSeparators); - - if (touching != null && touching.mWord.length() > 1) { - ic.beginBatchEdit(); - - if (applyTypedAlternatives(word, suggest, keyboardSwitcher, touching) - || voiceProxy.applyVoiceAlternatives(touching)) { - TextEntryState.selectedForRecorrection(); - InputConnectionCompatUtils.underlineWord(ic, touching); - } else { - abortRecorrection(true); - } - - ic.endBatchEdit(); - } else { - abortRecorrection(true); - mService.setPunctuationSuggestions(); // Show the punctuation suggestions list - } - } else { - abortRecorrection(true); - } - } - - public void abortRecorrection(boolean force) { - if (force || TextEntryState.isRecorrecting()) { - TextEntryState.onAbortRecorrection(); - mService.setCandidatesViewShown(mService.isCandidateStripVisible()); - mService.getCurrentInputConnection().finishComposingText(); - mService.clearSuggestions(); - } - } -} diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 5eb365774..956c51e06 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -56,7 +56,7 @@ public class Settings extends PreferenceActivity public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings"; public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_SOUND_ON = "sound_on"; - public static final String PREF_POPUP_ON = "popup_on"; + public static final String PREF_KEY_PREVIEW_POPUP_ON = "popup_on"; public static final String PREF_RECORRECTION_ENABLED = "recorrection_enabled"; public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_SETTINGS_KEY = "settings_key"; @@ -77,6 +77,9 @@ public class Settings extends PreferenceActivity public static final String PREF_MISC_SETTINGS_KEY = "misc_settings"; + public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = + "pref_key_preview_popup_dismiss_delay"; + public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; // Dialog ids @@ -84,7 +87,6 @@ public class Settings extends PreferenceActivity public static class Values { // From resources: - public final boolean mEnableShowSubtypeSettings; public final boolean mSwipeDownDismissKeyboardEnabled; public final int mDelayBeforeFadeoutLanguageOnSpacebar; public final int mDelayUpdateSuggestions; @@ -102,7 +104,8 @@ public class Settings extends PreferenceActivity // From preferences: public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn) public final boolean mVibrateOn; - public final boolean mPopupOn; // Warning : this escapes through LatinIME#isPopupOn + public final boolean mKeyPreviewPopupOn; + public final int mKeyPreviewPopupDismissDelay; public final boolean mAutoCap; public final boolean mQuickFixes; public final boolean mAutoCorrectEnabled; @@ -117,15 +120,13 @@ public class Settings extends PreferenceActivity final Resources res = context.getResources(); final Locale savedLocale; if (null != localeStr) { - final Locale keyboardLocale = new Locale(localeStr); + final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); savedLocale = Utils.setSystemLocale(res, keyboardLocale); } else { savedLocale = null; } // Get the resources - mEnableShowSubtypeSettings = res.getBoolean( - R.bool.config_enable_show_subtype_settings); mSwipeDownDismissKeyboardEnabled = res.getBoolean( R.bool.config_swipe_down_dismiss_keyboard_enabled); mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger( @@ -161,7 +162,8 @@ public class Settings extends PreferenceActivity mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); - mPopupOn = isPopupEnabled(prefs, res); + mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); + mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res); mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); mQuickFixes = isQuickFixesEnabled(prefs, res); @@ -172,6 +174,8 @@ public class Settings extends PreferenceActivity && isBigramPredictionEnabled(prefs, res); mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res); + + Utils.setSystemLocale(res, savedLocale); } public boolean isSuggestedPunctuation(int code) { @@ -200,6 +204,7 @@ public class Settings extends PreferenceActivity return sp.getBoolean(Settings.PREF_QUICK_FIXES, resources.getBoolean( R.bool.config_default_quick_fixes)); } + private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) { final String currentAutoCorrectionSetting = sp.getString( Settings.PREF_AUTO_CORRECTION_THRESHOLD, @@ -208,13 +213,24 @@ public class Settings extends PreferenceActivity R.string.auto_correction_threshold_mode_index_off); return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } - private static boolean isPopupEnabled(SharedPreferences sp, Resources resources) { + + // Public to access from KeyboardSwitcher. Should it have access to some + // process-global instance instead? + public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) { final boolean showPopupOption = resources.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview); - return sp.getBoolean(Settings.PREF_POPUP_ON, + return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON, resources.getBoolean(R.bool.config_default_popup_preview)); } + + // Likewise + public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp, + Resources resources) { + return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(resources.getInteger(R.integer.config_delay_after_preview)))); + } + private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources, boolean autoCorrectEnabled) { final boolean showBigramSuggestionsOption = resources.getBoolean( @@ -225,11 +241,13 @@ public class Settings extends PreferenceActivity return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean( R.bool.config_default_bigram_suggestions)); } + private static boolean isBigramPredictionEnabled(SharedPreferences sp, Resources resources) { return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean( R.bool.config_default_bigram_prediction)); } + private static double getAutoCorrectionThreshold(SharedPreferences sp, Resources resources) { final String currentAutoCorrectionSetting = sp.getString( @@ -255,6 +273,7 @@ public class Settings extends PreferenceActivity } return autoCorrectionThreshold; } + private static SuggestedWords createSuggestPuncList(final String puncs) { SuggestedWords.Builder builder = new SuggestedWords.Builder(); if (puncs != null) { @@ -272,6 +291,7 @@ public class Settings extends PreferenceActivity private ListPreference mSettingsKeyPreference; private ListPreference mShowCorrectionSuggestionsPreference; private ListPreference mAutoCorrectionThreshold; + private ListPreference mKeyPreviewPopupDismissDelay; // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary private CheckBoxPreference mBigramSuggestion; // Prediction: use bigrams to predict the next word when there is no input for it yet @@ -297,6 +317,8 @@ public class Settings extends PreferenceActivity @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); + final Resources res = getResources(); + addPreferencesFromResource(R.xml.prefs); mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES); mInputLanguageSelection.setOnPreferenceClickListener(this); @@ -329,16 +351,14 @@ public class Settings extends PreferenceActivity (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY); final PreferenceGroup textCorrectionGroup = (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS_KEY); - final PreferenceGroup bigramGroup = - (PreferenceGroup) findPreference(PREF_NGRAM_SETTINGS_KEY); - final boolean showSettingsKeyOption = getResources().getBoolean( + final boolean showSettingsKeyOption = res.getBoolean( R.bool.config_enable_show_settings_key_option); if (!showSettingsKeyOption) { generalSettings.removePreference(mSettingsKeyPreference); } - final boolean showVoiceKeyOption = getResources().getBoolean( + final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); if (!showVoiceKeyOption) { generalSettings.removePreference(mVoicePreference); @@ -348,43 +368,57 @@ public class Settings extends PreferenceActivity generalSettings.removePreference(findPreference(PREF_VIBRATE_ON)); } - final boolean showSubtypeSettings = getResources().getBoolean( - R.bool.config_enable_show_subtype_settings); - if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED - && !showSubtypeSettings) { + if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { generalSettings.removePreference(findPreference(PREF_SUBTYPES)); } - final boolean showPopupOption = getResources().getBoolean( + final boolean showPopupOption = res.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); if (!showPopupOption) { - generalSettings.removePreference(findPreference(PREF_POPUP_ON)); + generalSettings.removePreference(findPreference(PREF_KEY_PREVIEW_POPUP_ON)); } - final boolean showRecorrectionOption = getResources().getBoolean( + final boolean showRecorrectionOption = res.getBoolean( R.bool.config_enable_show_recorrection_option); if (!showRecorrectionOption) { generalSettings.removePreference(findPreference(PREF_RECORRECTION_ENABLED)); } - final boolean showQuickFixesOption = getResources().getBoolean( + final boolean showQuickFixesOption = res.getBoolean( R.bool.config_enable_quick_fixes_option); if (!showQuickFixesOption) { textCorrectionGroup.removePreference(findPreference(PREF_QUICK_FIXES)); } - final boolean showBigramSuggestionsOption = getResources().getBoolean( + final boolean showBigramSuggestionsOption = res.getBoolean( R.bool.config_enable_bigram_suggestions_option); if (!showBigramSuggestionsOption) { textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_SUGGESTIONS)); textCorrectionGroup.removePreference(findPreference(PREF_BIGRAM_PREDICTIONS)); } - final boolean showUsabilityModeStudyOption = getResources().getBoolean( + final boolean showUsabilityModeStudyOption = res.getBoolean( R.bool.config_enable_usability_study_mode_option); if (!showUsabilityModeStudyOption) { getPreferenceScreen().removePreference(findPreference(PREF_USABILITY_STUDY_MODE)); } + + mKeyPreviewPopupDismissDelay = + (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + final String[] entries = new String[] { + res.getString(R.string.key_preview_popup_dismiss_no_delay), + res.getString(R.string.key_preview_popup_dismiss_default_delay), + }; + final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( + R.integer.config_delay_after_preview)); + mKeyPreviewPopupDismissDelay.setEntries(entries); + mKeyPreviewPopupDismissDelay.setEntryValues( + new String[] { "0", popupDismissDelayDefaultValue }); + if (null == mKeyPreviewPopupDismissDelay.getValue()) { + mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); + } + mKeyPreviewPopupDismissDelay.setEnabled( + Settings.Values.isKeyPreviewPopupEnabled(prefs, res)); } @Override @@ -403,6 +437,7 @@ public class Settings extends PreferenceActivity } updateSettingsKeySummary(); updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); } @Override @@ -421,6 +456,12 @@ public class Settings extends PreferenceActivity .equals(mVoiceModeOff)) { showVoiceConfirmation(); } + } else if (key.equals(PREF_KEY_PREVIEW_POPUP_ON)) { + final ListPreference popupDismissDelay = + (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + if (null != popupDismissDelay) { + popupDismissDelay.setEnabled(prefs.getBoolean(PREF_KEY_PREVIEW_POPUP_ON, true)); + } } ensureConsistencyOfAutoCorrectionSettings(); mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff) @@ -428,6 +469,7 @@ public class Settings extends PreferenceActivity updateVoiceModeSummary(); updateSettingsKeySummary(); updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); } @Override @@ -454,6 +496,11 @@ public class Settings extends PreferenceActivity [mSettingsKeyPreference.findIndexOfValue(mSettingsKeyPreference.getValue())]); } + private void updateKeyPreviewPopupDelaySummary() { + final ListPreference lp = mKeyPreviewPopupDismissDelay; + lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]); + } + private void showVoiceConfirmation() { mOkClicked = false; showDialog(VOICE_INPUT_CONFIRM_DIALOG); diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index d8012087b..8b51af880 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -92,10 +92,9 @@ public class SubtypeSwitcher { } public static void init(LatinIME service, SharedPreferences prefs) { + SubtypeLocale.init(service); sInstance.initialize(service, prefs); sInstance.updateAllParameters(); - - SubtypeLocale.init(service); } private SubtypeSwitcher() { @@ -281,14 +280,8 @@ public class SubtypeSwitcher { // "en_US" --> language: en & country: US // "en" --> language: en // "" --> the system locale - mLocaleSplitter.setString(inputLocaleStr); - if (mLocaleSplitter.hasNext()) { - String language = mLocaleSplitter.next(); - if (mLocaleSplitter.hasNext()) { - mInputLocale = new Locale(language, mLocaleSplitter.next()); - } else { - mInputLocale = new Locale(language); - } + if (!TextUtils.isEmpty(inputLocaleStr)) { + mInputLocale = Utils.constructLocaleFromString(inputLocaleStr); mInputLocaleStr = inputLocaleStr; } else { mInputLocale = mSystemLocale; @@ -420,7 +413,7 @@ public class SubtypeSwitcher { final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance(); final LatinKeyboard keyboard = switcher.getLatinKeyboard(); if (keyboard != null) { - keyboard.updateShortcutKey(isShortcutImeReady(), switcher.getInputView()); + keyboard.updateShortcutKey(isShortcutImeReady(), switcher.getKeyboardView()); } } @@ -510,7 +503,7 @@ public class SubtypeSwitcher { private void triggerVoiceIME() { if (!mService.isInputViewShown()) return; VoiceProxy.getInstance().startListening(false, - KeyboardSwitcher.getInstance().getInputView().getWindowToken()); + KeyboardSwitcher.getInstance().getKeyboardView().getWindowToken()); } ////////////////////////////////////// @@ -549,12 +542,12 @@ public class SubtypeSwitcher { || mEnabledKeyboardSubtypesOfCurrentInputMethod.size() == 0) return; mCurrentKeyboardSubtypeIndex = getCurrentIndex(); mNextKeyboardSubtype = getNextKeyboardSubtypeInternal(mCurrentKeyboardSubtypeIndex); - Locale locale = new Locale(mNextKeyboardSubtype.getLocale()); - mNextLanguage = getDisplayLanguage(locale); + Locale locale = Utils.constructLocaleFromString(mNextKeyboardSubtype.getLocale()); + mNextLanguage = getFullDisplayName(locale, true); mPreviousKeyboardSubtype = getPreviousKeyboardSubtypeInternal( mCurrentKeyboardSubtypeIndex); - locale = new Locale(mPreviousKeyboardSubtype.getLocale()); - mPreviousLanguage = getDisplayLanguage(locale); + locale = Utils.constructLocaleFromString(mPreviousKeyboardSubtype.getLocale()); + mPreviousLanguage = getFullDisplayName(locale, true); } private int normalize(int index) { @@ -591,11 +584,12 @@ public class SubtypeSwitcher { } public static String getDisplayLanguage(Locale locale) { - return toTitleCase(locale.getDisplayLanguage(locale)); + return toTitleCase(SubtypeLocale.getFullDisplayName(locale)); } public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase((new Locale(locale.getLanguage()).getDisplayLanguage(locale))); + return toTitleCase((Utils.constructLocaleFromString( + locale.getLanguage()).getDisplayLanguage(locale))); } public static String getShortDisplayLanguage(Locale locale) { diff --git a/java/src/com/android/inputmethod/latin/SuggestionSpanPickedNotificationReceiver.java b/java/src/com/android/inputmethod/latin/SuggestionSpanPickedNotificationReceiver.java new file mode 100644 index 000000000..4a3f42d5d --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SuggestionSpanPickedNotificationReceiver.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 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.latin; + +import com.android.inputmethod.compat.SuggestionSpanUtils; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +public class SuggestionSpanPickedNotificationReceiver extends BroadcastReceiver { + private static final boolean DBG = LatinImeLogger.sDBG; + private static final String TAG = + SuggestionSpanPickedNotificationReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + if (SuggestionSpanUtils.ACTION_SUGGESTION_PICKED.equals(intent.getAction())) { + if (DBG) { + final String before = intent.getStringExtra( + SuggestionSpanUtils.SUGGESTION_SPAN_PICKED_BEFORE); + final String after = intent.getStringExtra( + SuggestionSpanUtils.SUGGESTION_SPAN_PICKED_AFTER); + Log.d(TAG, "Received notification picked: " + before + "," + after); + } + } + } +} diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index a32a6461a..5b615ca29 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google Inc. + * Copyright (C) 2010 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 @@ -158,7 +158,7 @@ public class UserBigramDictionary extends ExpandableDictionary { * Pair will be added to the userbigram database. */ public int addBigrams(String word1, String word2) { - // remove caps + // remove caps if second word is autocapitalized if (mIme != null && mIme.getCurrentWord().isAutoCapitalized()) { word2 = Character.toLowerCase(word2.charAt(0)) + word2.substring(1); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index d165de32d..6bdc0a857 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; @@ -43,7 +44,10 @@ import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; +import java.util.List; import java.util.Locale; public class Utils { @@ -108,7 +112,34 @@ public class Utils { } public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm) { - return imm.getEnabledInputMethodList().size() > 1 + final List<InputMethodInfoCompatWrapper> enabledImis = imm.getEnabledInputMethodList(); + + // Filters out IMEs that have auxiliary subtypes only (including either implicitly or + // explicitly enabled ones). + final ArrayList<InputMethodInfoCompatWrapper> filteredImis = + new ArrayList<InputMethodInfoCompatWrapper>(); + + outerloop: + for (InputMethodInfoCompatWrapper imi : enabledImis) { + // We can return true immediately after we find two or more filtered IMEs. + if (filteredImis.size() > 1) return true; + final List<InputMethodSubtypeCompatWrapper> subtypes = + imm.getEnabledInputMethodSubtypeList(imi, true); + // IMEs that have no subtypes should be included. + if (subtypes.isEmpty()) { + filteredImis.add(imi); + continue; + } + // IMEs that have one or more non-auxiliary subtypes should be included. + for (InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (!subtype.isAuxiliary()) { + filteredImis.add(imi); + continue outerloop; + } + } + } + + return filteredImis.size() > 1 // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled // input method subtype (The current IME should be LatinIME.) || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; @@ -537,8 +568,6 @@ public class Utils { return KeyboardId.MODE_IM; } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) { return KeyboardId.MODE_TEXT; - } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) { - return KeyboardId.MODE_WEB; } else { return KeyboardId.MODE_TEXT; } @@ -662,4 +691,28 @@ public class Utils { res.updateConfiguration(conf, res.getDisplayMetrics()); return saveLocale; } + + private static final HashMap<String, Locale> sLocaleCache = new HashMap<String, Locale>(); + + public static Locale constructLocaleFromString(String localeStr) { + if (localeStr == null) + return null; + synchronized (sLocaleCache) { + if (sLocaleCache.containsKey(localeStr)) + return sLocaleCache.get(localeStr); + Locale retval = null; + String[] localeParams = localeStr.split("_", 3); + if (localeParams.length == 1) { + retval = new Locale(localeParams[0]); + } else if (localeParams.length == 2) { + retval = new Locale(localeParams[0], localeParams[1]); + } else if (localeParams.length == 3) { + retval = new Locale(localeParams[0], localeParams[1], localeParams[2]); + } + if (retval != null) { + sLocaleCache.put(localeStr, retval); + } + return retval; + } + } } diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java index 2389d4e3c..4377373d2 100644 --- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java +++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java @@ -39,6 +39,7 @@ public class WhitelistDictionary extends Dictionary { public static WhitelistDictionary init(Context context) { synchronized (sInstance) { if (context != null) { + // Wordlist is initialized by the proper language in Suggestion.java#init sInstance.initWordlist( context.getResources().getStringArray(R.array.wordlist_whitelist)); } else { diff --git a/java/src/com/android/inputmethod/latin/WordAlternatives.java b/java/src/com/android/inputmethod/latin/WordAlternatives.java deleted file mode 100644 index 0e9914400..000000000 --- a/java/src/com/android/inputmethod/latin/WordAlternatives.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2011 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.latin; - -import com.android.inputmethod.keyboard.KeyboardSwitcher; - -import android.text.TextUtils; - -public class WordAlternatives { - public final CharSequence mChosenWord; - public final WordComposer mWordComposer; - - public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) { - mChosenWord = chosenWord; - mWordComposer = wordComposer; - } - - public CharSequence getChosenWord() { - return mChosenWord; - } - - public CharSequence getOriginalWord() { - return mWordComposer.getTypedWord(); - } - - public SuggestedWords.Builder getAlternatives( - Suggest suggest, KeyboardSwitcher keyboardSwitcher) { - return getTypedSuggestions(suggest, keyboardSwitcher, mWordComposer); - } - - @Override - public int hashCode() { - return mChosenWord.hashCode(); - } - - @Override - public boolean equals(Object o) { - return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o); - } - - private static SuggestedWords.Builder getTypedSuggestions( - Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word) { - return suggest.getSuggestedWordBuilder(keyboardSwitcher.getInputView(), word, null); - } -}
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cf0592920..af5e4b179 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -62,7 +62,7 @@ public class WordComposer { mYCoordinates = new int[N]; } - WordComposer(WordComposer source) { + public WordComposer(WordComposer source) { init(source); } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellChecker.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellChecker.java new file mode 100644 index 000000000..e3407a269 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellChecker.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 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.latin.spellcheck; + +import android.content.Context; +import android.content.res.Resources; + +import com.android.inputmethod.latin.Dictionary; +import com.android.inputmethod.latin.Dictionary.DataType; +import com.android.inputmethod.latin.Dictionary.WordCallback; +import com.android.inputmethod.latin.DictionaryFactory; +import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.WordComposer; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +/** + * Implements spell checking methods. + */ +public class SpellChecker { + + public final Dictionary mDictionary; + + public SpellChecker(final Context context, final Locale locale) { + final Resources resources = context.getResources(); + final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources); + mDictionary = DictionaryFactory.createDictionaryFromManager(context, locale, + fallbackResourceId); + } + + // Note : this must be reentrant + /** + * Finds out whether a word is in the dictionary or not. + * + * @param text the sequence containing the word to check for. + * @param start the index of the first character of the word in text. + * @param end the index of the next-to-last character in text. + * @return true if the word is in the dictionary, false otherwise. + */ + public boolean isCorrect(final CharSequence text, final int start, final int end) { + return mDictionary.isValidWord(text.subSequence(start, end)); + } + + private static class SuggestionsGatherer implements WordCallback { + private final int DEFAULT_SUGGESTION_LENGTH = 16; + private final List<String> mSuggestions = new LinkedList<String>(); + private int[] mScores = new int[DEFAULT_SUGGESTION_LENGTH]; + private int mLength = 0; + + synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, + int dicTypeId, DataType dataType) { + if (mLength >= mScores.length) { + final int newLength = mScores.length * 2; + mScores = new int[newLength]; + } + final int positionIndex = Arrays.binarySearch(mScores, 0, mLength, score); + // binarySearch returns the index if the element exists, and -<insertion index> - 1 + // if it doesn't. See documentation for binarySearch. + final int insertionIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + System.arraycopy(mScores, insertionIndex, mScores, insertionIndex + 1, + mLength - insertionIndex); + mLength += 1; + mScores[insertionIndex] = score; + mSuggestions.add(insertionIndex, new String(word, wordOffset, wordLength)); + return true; + } + + public List<String> getGatheredSuggestions() { + return mSuggestions; + } + } + + // Note : this must be reentrant + /** + * Gets a list of suggestions for a specific string. + * + * This returns a list of possible corrections for the text passed as an + * arguments. It may split or group words, and even perform grammatical + * analysis. + * + * @param text the sequence containing the word to check for. + * @param start the index of the first character of the word in text. + * @param end the index of the next-to-last character in text. + * @return a list of possible suggestions to replace the text. + */ + public List<String> getSuggestions(final CharSequence text, final int start, final int end) { + final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(); + final WordComposer composer = new WordComposer(); + for (int i = start; i < end; ++i) { + int character = text.charAt(i); + composer.add(character, new int[] { character }, + WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + } + mDictionary.getWords(composer, suggestionsGatherer); + return suggestionsGatherer.getGatheredSuggestions(); + } +} |