diff options
Diffstat (limited to 'java/src')
7 files changed, 84 insertions, 146 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index d0a2f864c..2e4988fb0 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -113,14 +113,6 @@ public class KeyboardId { false, F2KEY_MODE_NONE, false, false, false); } - public KeyboardId cloneWithNewGeometry(int orientation, int width) { - if (mWidth == width) - return this; - return new KeyboardId(mXmlName, mXmlId, mLocale, orientation, width, mMode, mAttribute, - mHasSettingsKey, mF2KeyMode, mClobberSettingsKey, mShortcutKeyEnabled, - mHasShortcutKey); - } - public int getXmlId() { return mXmlId; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 9937937ff..8bf82807a 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; -import android.inputmethodservice.InputMethodService; +import android.util.DisplayMetrics; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.InflateException; @@ -39,7 +39,6 @@ import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.Utils; import java.lang.ref.SoftReference; -import java.util.Arrays; import java.util.HashMap; import java.util.Locale; @@ -78,9 +77,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private KeyboardId mCurrentId; private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache = new HashMap<KeyboardId, SoftReference<LatinKeyboard>>(); - // TODO: Remove this cache object when {@link DisplayMetrics} has actual window width excluding - // system navigation bar. - private WindowWidthCache mWindowWidthCache; private KeyboardLayoutState mSavedKeyboardState = new KeyboardLayoutState(); @@ -105,77 +101,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); - private static class WindowWidthCache { - private final InputMethodService mService; - private final Resources mResources; - private final boolean mIsRegistered[] = new boolean[Configuration.ORIENTATION_SQUARE + 1]; - private final int mWidth[] = new int[Configuration.ORIENTATION_SQUARE + 1]; - - public WindowWidthCache(InputMethodService service) { - mService = service; - mResources = service.getResources(); - - Arrays.fill(mIsRegistered, false); - Arrays.fill(mWidth, 0); - } - - private int getCurrentWindowWidth() { - return mService.getWindow().getWindow().getDecorView().getWidth(); - } - - public int getWidth(Configuration conf) { - final int orientation = conf.orientation; - try { - final int width = mWidth[orientation]; - if (mIsRegistered[orientation] || width > 0) { - // Return registered or cached window width for this orientation. - return width; - } - // Fall through - } catch (IndexOutOfBoundsException e) { - Log.w(TAG, "unknwon orientation value " + orientation); - // Fall through - } - - // Return screen width as default window width. - return mResources.getDisplayMetrics().widthPixels; - } - - public int getWidthOnSizeChanged(Configuration conf) { - final int orientation = conf.orientation; - try { - if (mIsRegistered[orientation]) { - // Return registered window width for this orientation. - return mWidth[orientation]; - } - - // Cache the current window width without registering. - final int width = getCurrentWindowWidth(); - mWidth[orientation] = width; - return width; - } catch (IndexOutOfBoundsException e) { - Log.w(TAG, "unknwon orientation value " + orientation); - return 0; - } - } - - public void registerWidth() { - final int orientation = mResources.getConfiguration().orientation; - try { - if (!mIsRegistered[orientation]) { - final int width = getCurrentWindowWidth(); - if (width > 0) { - // Register current window width. - mWidth[orientation] = width; - mIsRegistered[orientation] = true; - } - } - } catch (IndexOutOfBoundsException e) { - Log.w(TAG, "unknwon orientation value " + orientation); - } - } - } - public class KeyboardLayoutState { private boolean mIsValid; private boolean mIsAlphabetMode; @@ -247,7 +172,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mResources = ims.getResources(); mPrefs = prefs; mSubtypeSwitcher = SubtypeSwitcher.getInstance(); - mWindowWidthCache = new WindowWidthCache(ims); setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs)); prefs.registerOnSharedPreferenceChangeListener(this); } @@ -298,26 +222,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha mIsAutoCorrectionActive = false; } - public void registerWindowWidth() { - mWindowWidthCache.registerWidth(); - } - - @SuppressWarnings("unused") - public void onSizeChanged(int w, int h, int oldw, int oldh) { - // TODO: This hack should be removed when display metric returns a proper width. - // Until then, the behavior of KeyboardSwitcher is suboptimal on a device that has a - // vertical system navigation bar in landscape screen orientation, for instance. - final Configuration conf = mResources.getConfiguration(); - final int width = mWindowWidthCache.getWidthOnSizeChanged(conf); - // If the window width hasn't fixed yet or keyboard doesn't exist, nothing to do with. - if (width == 0 || mCurrentId == null) - return; - // Reload keyboard with new width. - final KeyboardId newId = mCurrentId.cloneWithNewGeometry(conf.orientation, width); - mInputMethodService.mHandler.postRestoreKeyboardLayout(); - setKeyboard(getKeyboard(newId)); - } - private void setKeyboard(final Keyboard keyboard) { final Keyboard oldKeyboard = mKeyboardView.getKeyboard(); mKeyboardView.setKeyboard(keyboard); @@ -402,7 +306,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha break; } - final boolean settingsKeyEnabled = settingsValues.isSettingsKeyEnabled(editorInfo); + final boolean settingsKeyEnabled = settingsValues.isSettingsKeyEnabled(); final boolean noMicrophone = Utils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo) || Utils.inPrivateImeOptions( @@ -416,10 +320,11 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha final int f2KeyMode = getF2KeyMode(settingsKeyEnabled, noSettingsKey); final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != voiceKeyOnMain); final Configuration conf = mResources.getConfiguration(); + final DisplayMetrics dm = mResources.getDisplayMetrics(); return new KeyboardId( mResources.getResourceEntryName(xmlId), xmlId, mSubtypeSwitcher.getInputLocale(), - conf.orientation, mWindowWidthCache.getWidth(conf), mode, editorInfo, + conf.orientation, dm.widthPixels, mode, editorInfo, hasSettingsKey, f2KeyMode, noSettingsKey, voiceKeyEnabled, hasShortcutKey); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java index 12aadcb5c..e0c6bbbb2 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java @@ -266,12 +266,6 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke return mKeyTimerHandler; } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - // TODO: Should notify InputMethodService instead? - KeyboardSwitcher.getInstance().onSizeChanged(w, h, oldw, oldh); - } - /** * Attaches a keyboard to this view. The keyboard can be switched at any time and the * view will re-layout itself to accommodate the keyboard. diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index f499bc0bb..d46b4b5b5 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -272,9 +272,10 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private static final int AUTO_CORRECT_BOLD = 0x01; private static final int AUTO_CORRECT_UNDERLINE = 0x02; private static final int AUTO_CORRECT_INVERT = 0x04; + private static final int VALID_TYPED_WORD_BOLD = 0x08; private final TextPaint mPaint; - private final int mAutoCorrectHighlight; + private final int mSuggestionStripOption; private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); @@ -285,7 +286,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo super(words, dividers, infos); final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); - mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); + mSuggestionStripOption = a.getInt(R.styleable.CandidateView_suggestionStripOption, 0); mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); @@ -313,15 +314,23 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo return mColorTypedWord; } - private CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect) { - if (!isAutoCorrect) + private CharSequence getStyledCandidateWord(SuggestedWords suggestions, int pos) { + final CharSequence word = suggestions.getWord(pos); + final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); + final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid; + if (!isAutoCorrect && !isTypedWordValid) return word; + final int len = word.length(); final Spannable spannedWord = new SpannableString(word); - if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0) + final int option = mSuggestionStripOption; + if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) + || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0) + } + if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } return spannedWord; } @@ -370,7 +379,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } public CharSequence getInvertedText(CharSequence text) { - if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0) + if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0) return null; final int len = text.length(); final Spannable word = new SpannableString(text); @@ -457,9 +466,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mTexts.clear(); final int count = Math.min(suggestions.size(), countInStrip); for (int pos = 0; pos < count; pos++) { - final CharSequence word = suggestions.getWord(pos); - final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); - final CharSequence styled = getStyledCandidateWord(word, isAutoCorrect); + final CharSequence styled = getStyledCandidateWord(suggestions, pos); mTexts.add(styled); } for (int pos = count; pos < countInStrip; pos++) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index a932f03ac..afbdd36a9 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2027,7 +2027,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onPress(int primaryCode, boolean withSliding) { final KeyboardSwitcher switcher = mKeyboardSwitcher; - switcher.registerWindowWidth(); if (switcher.isVibrateAndSoundFeedbackRequired()) { vibrate(); playKeyClick(primaryCode); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 4c2627be3..87a713f5c 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -53,7 +53,7 @@ import java.util.Locale; public class Settings extends InputMethodSettingsActivity implements SharedPreferences.OnSharedPreferenceChangeListener, DialogInterface.OnDismissListener, OnPreferenceClickListener { - private static final String TAG = "Settings"; + private static final String TAG = Settings.class.getSimpleName(); public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings"; public static final String PREF_VIBRATE_ON = "vibrate_on"; @@ -182,8 +182,9 @@ public class Settings extends InputMethodSettingsActivity mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); final boolean defaultShowSettingsKey = res.getBoolean( R.bool.config_default_show_settings_key); - mShowSettingsKey = prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, - defaultShowSettingsKey); + mShowSettingsKey = isShowSettingsKeyOption(res) + ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey) + : defaultShowSettingsKey; final String voiceModeMain = res.getString(R.string.voice_mode_main); final String voiceModeOff = res.getString(R.string.voice_mode_off); final String voiceMode = prefs.getString(PREF_VOICE_SETTINGS_KEY, voiceModeMain); @@ -292,7 +293,12 @@ public class Settings extends InputMethodSettingsActivity return builder.setIsPunctuationSuggestions().build(); } - public boolean isSettingsKeyEnabled(EditorInfo attribute) { + public static boolean isShowSettingsKeyOption(final Resources resources) { + return resources.getBoolean(R.bool.config_enable_show_settings_key_option); + + } + + public boolean isSettingsKeyEnabled() { return mShowSettingsKey; } @@ -386,9 +392,7 @@ public class Settings extends InputMethodSettingsActivity final PreferenceGroup textCorrectionGroup = (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS_KEY); - final boolean showSettingsKeyOption = res.getBoolean( - R.bool.config_enable_show_settings_key_option); - if (!showSettingsKeyOption) { + if (!Values.isShowSettingsKeyOption(res)) { generalSettings.removePreference(mShowSettingsKeyPreference); } @@ -445,8 +449,7 @@ public class Settings extends InputMethodSettingsActivity if (null == mKeyPreviewPopupDismissDelay.getValue()) { mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); } - mKeyPreviewPopupDismissDelay.setEnabled( - Settings.Values.isKeyPreviewPopupEnabled(prefs, res)); + mKeyPreviewPopupDismissDelay.setEnabled(Values.isKeyPreviewPopupEnabled(prefs, res)); final PreferenceScreen dictionaryLink = (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index ec82f9e80..502ebb52a 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -23,6 +23,7 @@ import android.service.textservice.SpellCheckerService.Session; import android.util.Log; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; +import android.text.TextUtils; import com.android.inputmethod.compat.ArraysCompatUtils; import com.android.inputmethod.keyboard.Key; @@ -36,6 +37,7 @@ import com.android.inputmethod.latin.UserDictionary; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.WordComposer; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Locale; @@ -50,7 +52,9 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private static final boolean DBG = false; private static final int POOL_SIZE = 2; - private final static String[] emptyArray = new String[0]; + private final static String[] EMPTY_STRING_ARRAY = new String[0]; + private final static SuggestionsInfo EMPTY_SUGGESTIONS_INFO = + new SuggestionsInfo(0, EMPTY_STRING_ARRAY); private Map<String, DictionaryPool> mDictionaryPools = Collections.synchronizedMap(new TreeMap<String, DictionaryPool>()); private Map<String, Dictionary> mUserDictionaries = @@ -63,14 +67,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private static class SuggestionsGatherer implements WordCallback { private final int DEFAULT_SUGGESTION_LENGTH = 16; - private final String[] mSuggestions; + private final ArrayList<CharSequence> mSuggestions; private final int[] mScores; private final int mMaxLength; private int mLength = 0; + private boolean mSeenSuggestions = false; SuggestionsGatherer(final int maxLength) { mMaxLength = maxLength; - mSuggestions = new String[mMaxLength]; + mSuggestions = new ArrayList<CharSequence>(maxLength + 1); mScores = new int[mMaxLength]; } @@ -82,30 +87,37 @@ public class AndroidSpellCheckerService extends SpellCheckerService { // if it doesn't. See documentation for binarySearch. final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; + mSeenSuggestions = true; if (mLength < mMaxLength) { final int copyLen = mLength - insertIndex; ++mLength; System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen); - System.arraycopy(mSuggestions, insertIndex, mSuggestions, insertIndex + 1, copyLen); + mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength)); } else { if (insertIndex == 0) return true; System.arraycopy(mScores, 1, mScores, 0, insertIndex); - System.arraycopy(mSuggestions, 1, mSuggestions, 0, insertIndex); + mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength)); + mSuggestions.remove(0); } mScores[insertIndex] = score; - mSuggestions[insertIndex] = new String(word, wordOffset, wordLength); return true; } public String[] getGatheredSuggestions() { - if (0 == mLength) return null; + if (!mSeenSuggestions) return null; + if (0 == mLength) return EMPTY_STRING_ARRAY; - final String[] results = new String[mLength]; - for (int i = mLength - 1; i >= 0; --i) { - results[mLength - i - 1] = mSuggestions[i]; + if (DBG) { + if (mLength != mSuggestions.size()) { + Log.e(TAG, "Suggestion size is not the same as stored mLength"); + } } - return results; + Collections.reverse(mSuggestions); + Utils.removeDupes(mSuggestions); + // This returns a String[], while toArray() returns an Object[] which cannot be cast + // into a String[]. + return mSuggestions.toArray(EMPTY_STRING_ARRAY); } } @@ -153,10 +165,14 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private class AndroidSpellCheckerSession extends Session { // Immutable, but need the locale which is not available in the constructor yet DictionaryPool mDictionaryPool; + // Likewise + Locale mLocale; @Override public void onCreate() { - mDictionaryPool = getDictionaryPool(getLocale()); + final String localeString = getLocale(); + mDictionaryPool = getDictionaryPool(localeString); + mLocale = Utils.constructLocaleFromString(localeString); } // Note : this must be reentrant @@ -170,6 +186,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { final int suggestionsLimit) { final String text = textInfo.getText(); + if (TextUtils.isEmpty(text)) return EMPTY_SUGGESTIONS_INFO; + final SuggestionsGatherer suggestionsGatherer = new SuggestionsGatherer(suggestionsLimit); final WordComposer composer = new WordComposer(); @@ -194,12 +212,32 @@ public class AndroidSpellCheckerService extends SpellCheckerService { dictInfo.mDictionary.getWords(composer, suggestionsGatherer, dictInfo.mProximityInfo); isInDict = dictInfo.mDictionary.isValidWord(text); + if (!isInDict && Character.isUpperCase(text.codePointAt(0))) { + // If the first char is not uppercase, then the word is either all lower case, + // in which case we already tested it, or mixed case, in which case we don't + // want to test a lower-case version of it. Hence the test above. + // Also note that by isEmpty() test at the top of the method codePointAt(0) is + // guaranteed to be there. + final int len = text.codePointCount(0, text.length()); + int capsCount = 1; + for (int i = 1; i < len; ++i) { + if (1 != capsCount && i != capsCount) break; + if (Character.isUpperCase(text.codePointAt(i))) ++capsCount; + } + // We know the first char is upper case. So we want to test if either everything + // else is lower case, or if everything else is upper case. If the string is + // exactly one char long, then we will arrive here with capsCount 0, and this is + // correct, too. + if (1 == capsCount || len == capsCount) { + isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); + } + } if (!mDictionaryPool.offer(dictInfo)) { Log.e(TAG, "Can't re-insert a dictionary into its pool"); } } catch (InterruptedException e) { // I don't think this can happen. - return new SuggestionsInfo(0, new String[0]); + return EMPTY_SUGGESTIONS_INFO; } final String[] suggestions = suggestionsGatherer.getGatheredSuggestions(); |