diff options
Diffstat (limited to 'java/src/com/android')
22 files changed, 551 insertions, 227 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java index b84d402fb..94a1ee6eb 100644 --- a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java +++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java @@ -121,7 +121,7 @@ public final class MainKeyboardAccessibilityDelegate */ private void announceKeyboardLanguage(final Keyboard keyboard) { final String languageText = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale( - keyboard.mId.mSubtype); + keyboard.mId.mSubtype.getRawSubtype()); sendWindowStateChanged(languageText); } diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java index 365867257..b9a536721 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java @@ -21,6 +21,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; +import com.android.inputmethod.latin.RichInputMethodSubtype; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -64,6 +65,10 @@ public final class InputMethodSubtypeCompatUtils { overridesImplicitlyEnabledSubtype, id); } + public static boolean isAsciiCapable(final RichInputMethodSubtype subtype) { + return isAsciiCapable(subtype.getRawSubtype()); + } + public static boolean isAsciiCapable(final InputMethodSubtype subtype) { return isAsciiCapableWithAPI(subtype) || subtype.containsExtraValueKey(Constants.Subtype.ExtraValue.ASCII_CAPABLE); diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index 3c1167538..538e515bc 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -21,9 +21,9 @@ import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOAR import android.text.InputType; import android.text.TextUtils; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.utils.InputTypeUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -62,7 +62,7 @@ public final class KeyboardId { public static final int ELEMENT_EMOJI_CATEGORY5 = 15; public static final int ELEMENT_EMOJI_CATEGORY6 = 16; - public final InputMethodSubtype mSubtype; + public final RichInputMethodSubtype mSubtype; public final Locale mLocale; public final int mWidth; public final int mHeight; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java index d6d0b2120..0804cebc4 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java @@ -28,7 +28,6 @@ import android.util.Log; import android.util.SparseArray; import android.util.Xml; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; @@ -37,6 +36,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.keyboard.internal.KeysCache; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.InputTypeUtils; @@ -109,7 +109,7 @@ public final class KeyboardLayoutSet { boolean mVoiceInputKeyEnabled; boolean mNoSettingsKey; boolean mLanguageSwitchKeyEnabled; - InputMethodSubtype mSubtype; + RichInputMethodSubtype mSubtype; boolean mIsSpellChecker; int mKeyboardWidth; int mKeyboardHeight; @@ -245,7 +245,7 @@ public final class KeyboardLayoutSet { return this; } - public Builder setSubtype(final InputMethodSubtype subtype) { + public Builder setSubtype(final RichInputMethodSubtype subtype) { final boolean asciiCapable = InputMethodSubtypeCompatUtils.isAsciiCapable(subtype); // TODO: Consolidate with {@link InputAttributes}. @SuppressWarnings("deprecation") @@ -254,7 +254,7 @@ public final class KeyboardLayoutSet { final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( mParams.mEditorInfo.imeOptions) || deprecatedForceAscii; - final InputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable) + final RichInputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable) ? SubtypeSwitcher.getInstance().getNoLanguageSubtype() : subtype; mParams.mSubtype = keyboardSubtype; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 140e76879..77cdf49fb 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -261,6 +261,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } public void onToggleEmojiKeyboard() { + if (mKeyboardLayoutSet == null) { + return; + } if (isShowingEmojiPalettes()) { setAlphabetKeyboard(); } else { diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 1ef53a65d..847d90711 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -34,7 +34,6 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.MainKeyboardAccessibilityDelegate; @@ -54,10 +53,10 @@ import com.android.inputmethod.keyboard.internal.SlidingKeyInputDrawingPreview; import com.android.inputmethod.keyboard.internal.TimerHandler; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.settings.DebugSettings; import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.SpacebarLanguageUtils; import com.android.inputmethod.latin.utils.TypefaceUtils; import java.util.WeakHashMap; @@ -849,16 +848,16 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // Layout language name on spacebar. private String layoutLanguageOnSpacebar(final Paint paint, - final InputMethodSubtype subtype, final int width) { + final RichInputMethodSubtype subtype, final int width) { // Choose appropriate language name to fit into the width. if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) { - final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype); + final String fullText = subtype.getFullDisplayName(); if (fitsTextIntoWidth(width, fullText, paint)) { return fullText; } } - final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype); + final String middleText = subtype.getMiddleDisplayName(); if (fitsTextIntoWidth(width, middleText, paint)) { return middleText; } @@ -872,7 +871,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack paint.setTextAlign(Align.CENTER); paint.setTypeface(Typeface.DEFAULT); paint.setTextSize(mLanguageOnSpacebarTextSize); - final InputMethodSubtype subtype = getKeyboard().mId.mSubtype; + final RichInputMethodSubtype subtype = getKeyboard().mId.mSubtype; final String language = layoutLanguageOnSpacebar(paint, subtype, width); // Draw language text with shadow final float descent = paint.descent(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java index 6400a2440..72ad2bd97 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java +++ b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard.internal; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Collections; @@ -34,8 +35,8 @@ public final class LanguageOnSpacebarHelper { private List<InputMethodSubtype> mEnabledSubtypes = Collections.emptyList(); private boolean mIsSystemLanguageSameAsInputLanguage; - public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) { - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { + public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) { + if (subtype.isNoLanguage()) { return FORMAT_TYPE_FULL_LOCALE; } // Only this subtype is enabled and equals to the system locale. diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index e1d809907..87b34a99c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -51,6 +51,7 @@ import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.accessibility.AccessibilityUtils; @@ -192,8 +193,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final int ARG1_FALSE = 0; private static final int ARG1_TRUE = 1; - private int mDelayUpdateSuggestions; - private int mDelayUpdateShiftState; + private int mDelayInMillisecondsToUpdateSuggestions; + private int mDelayInMillisecondsToUpdateShiftState; public UIHandler(final LatinIME ownerInstance) { super(ownerInstance); @@ -205,8 +206,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return; } final Resources res = latinIme.getResources(); - mDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions); - mDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state); + mDelayInMillisecondsToUpdateSuggestions = + res.getInteger(R.integer.config_delay_in_milliseconds_to_update_suggestions); + mDelayInMillisecondsToUpdateShiftState = + res.getInteger(R.integer.config_delay_in_milliseconds_to_update_shift_state); } @Override @@ -272,7 +275,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void postUpdateSuggestionStrip(final int inputStyle) { sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP, inputStyle, - 0 /* ignored */), mDelayUpdateSuggestions); + 0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions); } public void postReopenDictionaries() { @@ -285,16 +288,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (latinIme == null) { return; } - if (!latinIme.mSettings.getCurrent() - .isSuggestionsEnabledPerUserSettings()) { + if (!latinIme.mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()) { return; } removeMessages(MSG_RESUME_SUGGESTIONS); if (shouldDelay) { sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS, - shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE, - 0 /* ignored */), - mDelayUpdateSuggestions); + shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE, + 0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions); } else { sendMessage(obtainMessage(MSG_RESUME_SUGGESTIONS, shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE, @@ -335,7 +336,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void postUpdateShiftState() { removeMessages(MSG_UPDATE_SHIFT_STATE); - sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); + sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), + mDelayInMillisecondsToUpdateShiftState); } @UsedForTesting @@ -747,7 +749,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) { // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() // is not guaranteed. It may even be called at the same time on a different thread. - mSubtypeSwitcher.onSubtypeChanged(subtype); + final RichInputMethodSubtype richSubtype = new RichInputMethodSubtype(subtype); + mSubtypeSwitcher.onSubtypeChanged(richSubtype); mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype)); loadKeyboard(); } @@ -1138,6 +1141,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override + public boolean onShowInputRequested(final int flags, final boolean configChange) { + if ((flags & InputMethod.SHOW_EXPLICIT) == 0 && mKeyboardSwitcher.hasHardwareKeyboard()) { + // Even when IME is implicitly shown and physical keyboard is connected, we should + // show {@link InputView}. + // See {@link InputMethodService#onShowInputRequested(int,boolean)}. + return true; + } + return super.onShowInputRequested(flags, configChange); + } + + @Override public boolean onEvaluateFullscreenMode() { if (mKeyboardSwitcher.hasHardwareKeyboard()) { // If there is a hardware keyboard, disable full screen mode. @@ -1258,10 +1272,26 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSubtypeState.switchSubtype(token, mRichImm); } + // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for + // alphabetic shift and shift while in symbol layout and get rid of this method. + private int getCodePointForKeyboard(final int codePoint) { + if (Constants.CODE_SHIFT == codePoint) { + final Keyboard currentKeyboard = mKeyboardSwitcher.getKeyboard(); + if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) { + return codePoint; + } else { + return Constants.CODE_SYMBOL_SHIFT; + } + } else { + return codePoint; + } + } + // Implementation of {@link KeyboardActionListener}. @Override public void onCodeInput(final int codePoint, final int x, final int y, final boolean isKeyRepeat) { + // TODO: this processing does not belong inside LatinIME, the caller should be doing this. final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); // x and y include some padding, but everything down the line (especially native // code) needs the coordinates in the keyboard frame. @@ -1270,36 +1300,30 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // this transformation, it should be done already before calling onCodeInput. final int keyX = mainKeyboardView.getKeyX(x); final int keyY = mainKeyboardView.getKeyY(y); - final int codeToSend; - if (Constants.CODE_SHIFT == codePoint) { - // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for - // alphabetic shift and shift while in symbol layout. - final Keyboard currentKeyboard = mKeyboardSwitcher.getKeyboard(); - if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) { - codeToSend = codePoint; - } else { - codeToSend = Constants.CODE_SYMBOL_SHIFT; - } - } else { - codeToSend = codePoint; - } - if (Constants.CODE_SHORTCUT == codePoint) { + final Event event = createSoftwareKeypressEvent(getCodePointForKeyboard(codePoint), + keyX, keyY, isKeyRepeat); + onEvent(event); + } + + // This method is public for testability of LatinIME, but also in the future it should + // completely replace #onCodeInput. + public void onEvent(final Event event) { + if (Constants.CODE_SHORTCUT == event.mCodePoint) { mSubtypeSwitcher.switchToShortcutIME(this); - // Still call the *#onCodeInput methods for readability. } - final Event event = createSoftwareKeypressEvent(codeToSend, keyX, keyY, isKeyRepeat); final InputTransaction completeInputTransaction = mInputLogic.onCodeInput(mSettings.getCurrent(), event, mKeyboardSwitcher.getKeyboardShiftMode(), mKeyboardSwitcher.getCurrentKeyboardScriptId(), mHandler); updateStateAfterInputTransaction(completeInputTransaction); - mKeyboardSwitcher.onCodeInput(codePoint, getCurrentAutoCapsState(), + mKeyboardSwitcher.onCodeInput(event.mCodePoint, getCurrentAutoCapsState(), getCurrentRecapitalizeState()); } // A helper method to split the code point and the key code. Ultimately, they should not be // squashed into the same variable, and this method should be removed. - private static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX, + // public for testing, as we don't want to copy the same logic into test code + public static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX, final int keyY, final boolean isKeyRepeat) { final int keyCode; final int codePoint; diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index ea63cef02..035557610 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -16,9 +16,13 @@ package com.android.inputmethod.latin; +import android.graphics.Color; import android.inputmethodservice.InputMethodService; import android.os.Build; +import android.text.SpannableStringBuilder; +import android.text.Spanned; import android.text.TextUtils; +import android.text.style.BackgroundColorSpan; import android.util.Log; import android.view.KeyEvent; import android.view.inputmethod.CompletionInfo; @@ -81,6 +85,18 @@ public final class RichInputConnection { */ private final StringBuilder mComposingText = new StringBuilder(); + /** + * This variable is a temporary object used in + * {@link #commitTextWithBackgroundColor(CharSequence, int, int)} to avoid object creation. + */ + private SpannableStringBuilder mTempObjectForCommitText = new SpannableStringBuilder(); + /** + * This variable is used to track whether the last committed text had the background color or + * not. + * TODO: Omit this flag if possible. + */ + private boolean mLastCommittedTextHasBackgroundColor = false; + private final InputMethodService mParent; InputConnection mIC; int mNestLevel; @@ -219,12 +235,37 @@ public final class RichInputConnection { // it works, but it's wrong and should be fixed. mCommittedTextBeforeComposingText.append(mComposingText); mComposingText.setLength(0); + // TODO: Clear this flag in setComposingRegion() and setComposingText() as well if needed. + mLastCommittedTextHasBackgroundColor = false; if (null != mIC) { mIC.finishComposingText(); } } - public void commitText(final CharSequence text, final int i) { + /** + * Synonym of {@code commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT}. + * @param text The text to commit. This may include styles. + * See {@link InputConnection#commitText(CharSequence, int)}. + * @param newCursorPosition The new cursor position around the text. + * See {@link InputConnection#commitText(CharSequence, int)}. + */ + public void commitText(final CharSequence text, final int newCursorPosition) { + commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT); + } + + /** + * Calls {@link InputConnection#commitText(CharSequence, int)} with the given background color. + * @param text The text to commit. This may include styles. + * See {@link InputConnection#commitText(CharSequence, int)}. + * @param newCursorPosition The new cursor position around the text. + * See {@link InputConnection#commitText(CharSequence, int)}. + * @param color The background color to be attached. Set {@link Color#TRANSPARENT} to disable + * the background color. Note that this method specifies {@link BackgroundColorSpan} with + * {@link Spanned#SPAN_COMPOSING} flag, meaning that the background color persists until + * {@link #finishComposingText()} is called. + */ + public void commitTextWithBackgroundColor(final CharSequence text, final int newCursorPosition, + final int color) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); mCommittedTextBeforeComposingText.append(text); @@ -234,11 +275,43 @@ public final class RichInputConnection { mExpectedSelStart += text.length() - mComposingText.length(); mExpectedSelEnd = mExpectedSelStart; mComposingText.setLength(0); + mLastCommittedTextHasBackgroundColor = false; if (null != mIC) { - mIC.commitText(text, i); + if (color == Color.TRANSPARENT) { + mIC.commitText(text, newCursorPosition); + } else { + mTempObjectForCommitText.clear(); + mTempObjectForCommitText.append(text); + final BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(color); + mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, text.length(), + Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + mIC.commitText(mTempObjectForCommitText, newCursorPosition); + mLastCommittedTextHasBackgroundColor = true; + } } } + /** + * Removes the background color from the highlighted text if necessary. Should be called while + * there is no on-going composing text. + * + * <p>CAVEAT: This method internally calls {@link InputConnection#finishComposingText()}. + * Be careful of any unexpected side effects.</p> + */ + public void removeBackgroundColorFromHighlightedTextIfNecessary() { + // TODO: We haven't yet full tested if we really need to check this flag or not. Omit this + // flag if everything works fine without this condition. + if (!mLastCommittedTextHasBackgroundColor) { + return; + } + if (mComposingText.length() > 0) { + Log.e(TAG, "clearSpansWithComposingFlags should be called when composing text is " + + "empty. mComposingText=" + mComposingText); + return; + } + finishComposingText(); + } + public CharSequence getSelectedText(final int flags) { return (null == mIC) ? null : mIC.getSelectedText(flags); } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index e43c18255..0d5ce7d6d 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -298,10 +298,14 @@ public class RichInputMethodManager { return INDEX_NOT_FOUND; } - public InputMethodSubtype getCurrentInputMethodSubtype( - final InputMethodSubtype defaultSubtype) { + public RichInputMethodSubtype getCurrentInputMethodSubtype( + final RichInputMethodSubtype defaultSubtype) { final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype(); - return (currentSubtype != null) ? currentSubtype : defaultSubtype; + if (currentSubtype == null) { + return defaultSubtype; + } + // TODO: Determine locales to use for multi-lingual use. + return new RichInputMethodSubtype(currentSubtype); } public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) { diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java new file mode 100644 index 000000000..0b08c48e5 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin; + +import android.view.inputmethod.InputMethodSubtype; + +import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; + +import java.util.Arrays; +import java.util.Locale; + +/** + * Enrichment class for InputMethodSubtype to enable concurrent multi-lingual input. + * + * Right now, this returns the extra value of its primary subtype. + */ +public final class RichInputMethodSubtype { + private final InputMethodSubtype mSubtype; + private final Locale[] mLocales; + + public RichInputMethodSubtype(final InputMethodSubtype subtype, final Locale... locales) { + mSubtype = subtype; + mLocales = new Locale[locales.length+1]; + mLocales[0] = LocaleUtils.constructLocaleFromString(mSubtype.getLocale()); + System.arraycopy(locales, 0, mLocales, 1, locales.length); + } + + // Extra values are determined by the primary subtype. This is probably right, but + // we may have to revisit this later. + public String getExtraValueOf(final String key) { + return mSubtype.getExtraValueOf(key); + } + + // The mode is also determined by the primary subtype. + public String getMode() { + return mSubtype.getMode(); + } + + public boolean isNoLanguage() { + if (mLocales.length > 1) { + return false; + } + return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale()); + } + + public String getNameForLogging() { + return toString(); + } + + // InputMethodSubtype's display name for spacebar text in its locale. + // isAdditionalSubtype (T=true, F=false) + // locale layout | Middle Full + // ------ ------- - --------- ---------------------- + // en_US qwerty F English English (US) exception + // en_GB qwerty F English English (UK) exception + // es_US spanish F Español Español (EE.UU.) exception + // fr azerty F Français Français + // fr_CA qwerty F Français Français (Canada) + // fr_CH swiss F Français Français (Suisse) + // de qwertz F Deutsch Deutsch + // de_CH swiss T Deutsch Deutsch (Schweiz) + // zz qwerty F QWERTY QWERTY + // fr qwertz T Français Français + // de qwerty T Deutsch Deutsch + // en_US azerty T English English (US) + // zz azerty T AZERTY AZERTY + // Get the RichInputMethodSubtype's full display name in its locale. + public String getFullDisplayName() { + if (isNoLanguage()) { + return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype); + } + return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(mSubtype.getLocale()); + } + + // Get the RichInputMethodSubtype's middle display name in its locale. + public String getMiddleDisplayName() { + if (isNoLanguage()) { + return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype); + } + return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(mSubtype.getLocale()); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RichInputMethodSubtype)) { + return false; + } + final RichInputMethodSubtype other = (RichInputMethodSubtype)o; + return mSubtype.equals(other.mSubtype) && Arrays.equals(mLocales, other.mLocales); + } + + @Override + public int hashCode() { + return mSubtype.hashCode() + Arrays.hashCode(mLocales); + } + + @Override + public String toString() { + return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales); + } + + // TODO: remove this method! We can always have several locales. Multi-lingual input will only + // be done when this method is gone. + public String getLocale() { + return mSubtype.getLocale(); + } + + // TODO: remove this method + public InputMethodSubtype getRawSubtype() { return mSubtype; } +} diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index a725e1611..45d67ff88 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -58,8 +58,8 @@ public final class SubtypeSwitcher { new LanguageOnSpacebarHelper(); private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; - private InputMethodSubtype mNoLanguageSubtype; - private InputMethodSubtype mEmojiSubtype; + private RichInputMethodSubtype mNoLanguageSubtype; + private RichInputMethodSubtype mEmojiSubtype; private boolean mIsNetworkConnected; private static final String KEYBOARD_MODE = "keyboard"; @@ -70,26 +70,26 @@ public final class SubtypeSwitcher { + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; - private static final InputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE = - InputMethodSubtypeCompatUtils.newInputMethodSubtype( + private static final RichInputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE = + new RichInputMethodSubtype(InputMethodSubtypeCompatUtils.newInputMethodSubtype( R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark, SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE, EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE, false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */, - SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE); + SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE)); // Caveat: We probably should remove this when we add an Emoji subtype in {@link R.xml.method}. // Dummy Emoji subtype. See {@link R.xml.method}. private static final int SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE = 0xd78b2ed0; private static final String EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE = "KeyboardLayoutSet=" + SubtypeLocaleUtils.EMOJI + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; - private static final InputMethodSubtype DUMMY_EMOJI_SUBTYPE = + private static final RichInputMethodSubtype DUMMY_EMOJI_SUBTYPE = new RichInputMethodSubtype( InputMethodSubtypeCompatUtils.newInputMethodSubtype( R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark, SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE, EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE, false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */, - SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE); + SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE)); public static SubtypeSwitcher getInstance() { return sInstance; @@ -165,18 +165,17 @@ public final class SubtypeSwitcher { } // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. - public void onSubtypeChanged(final InputMethodSubtype newSubtype) { + public void onSubtypeChanged(final RichInputMethodSubtype newSubtype) { if (DBG) { - Log.w(TAG, "onSubtypeChanged: " - + SubtypeLocaleUtils.getSubtypeNameForLogging(newSubtype)); + Log.w(TAG, "onSubtypeChanged: " + newSubtype.getNameForLogging()); } final Locale newLocale = SubtypeLocaleUtils.getSubtypeLocale(newSubtype); final Locale systemLocale = mResources.getConfiguration().locale; final boolean sameLocale = systemLocale.equals(newLocale); final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage()); - final boolean implicitlyEnabled = - mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype); + final boolean implicitlyEnabled = mRichImm + .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype.getRawSubtype()); mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage( sameLocale || (sameLanguage && implicitlyEnabled)); @@ -250,7 +249,7 @@ public final class SubtypeSwitcher { // Subtype Switching functions // ////////////////////////////////// - public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) { + public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) { return mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(subtype); } @@ -279,10 +278,10 @@ public final class SubtypeSwitcher { return true; } - private static InputMethodSubtype sForcedSubtypeForTesting = null; + private static RichInputMethodSubtype sForcedSubtypeForTesting = null; @UsedForTesting void forceSubtype(final InputMethodSubtype subtype) { - sForcedSubtypeForTesting = subtype; + sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype); } public Locale getCurrentSubtypeLocale() { @@ -292,17 +291,18 @@ public final class SubtypeSwitcher { return SubtypeLocaleUtils.getSubtypeLocale(getCurrentSubtype()); } - public InputMethodSubtype getCurrentSubtype() { + public RichInputMethodSubtype getCurrentSubtype() { if (null != sForcedSubtypeForTesting) { return sForcedSubtypeForTesting; } return mRichImm.getCurrentInputMethodSubtype(getNoLanguageSubtype()); } - public InputMethodSubtype getNoLanguageSubtype() { + public RichInputMethodSubtype getNoLanguageSubtype() { if (mNoLanguageSubtype == null) { - mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY); + mNoLanguageSubtype = new RichInputMethodSubtype( + mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY)); } if (mNoLanguageSubtype != null) { return mNoLanguageSubtype; @@ -313,10 +313,14 @@ public final class SubtypeSwitcher { return DUMMY_NO_LANGUAGE_SUBTYPE; } - public InputMethodSubtype getEmojiSubtype() { + public RichInputMethodSubtype getEmojiSubtype() { if (mEmojiSubtype == null) { - mEmojiSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI); + final InputMethodSubtype rawEmojiSubtype = + mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI); + if (null != rawEmojiSubtype) { + mEmojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype); + } } if (mEmojiSubtype != null) { return mEmojiSubtype; @@ -328,6 +332,6 @@ public final class SubtypeSwitcher { } public String getCombiningRulesExtraValueOfCurrentSubtype() { - return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype()); + return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype()); } } diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index d7693af41..38fcb683d 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -19,6 +19,7 @@ package com.android.inputmethod.latin; import android.text.TextUtils; import android.view.inputmethod.CompletionInfo; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.StringUtils; @@ -420,4 +421,18 @@ public class SuggestedWords { mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction, INPUT_STYLE_TAIL_BATCH); } + + /** + * @return the {@link SuggestedWordInfo} which corresponds to the word that is originally + * typed by the user. Otherwise returns {@code null}. Note that gesture input is not + * considered to be a typed word. + */ + @UsedForTesting + public SuggestedWordInfo getTypedWordInfoOrNull() { + if (this == EMPTY) { + return null; + } + final SuggestedWordInfo info = getInfo(SuggestedWords.INDEX_OF_TYPED_WORD); + return (info.getKind() == SuggestedWordInfo.KIND_TYPED) ? info : null; + } } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 348bae63a..616828efe 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin.inputlogic; +import android.graphics.Color; import android.os.SystemClock; import android.text.SpannableString; import android.text.TextUtils; @@ -232,6 +233,20 @@ public final class InputLogic { } /** + * Determines whether "Touch again to save" should be shown or not. + * @param suggestionInfo the suggested word chosen by the user. + * @return {@code true} if we should show the "Touch again to save" hint. + */ + private boolean shouldShowAddToDictionaryHint(final SuggestedWordInfo suggestionInfo) { + // We should show the "Touch again to save" hint if the user pressed the first entry + // AND it's in none of our current dictionaries (main, user or otherwise). + return (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED) + || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION)) + && !mDictionaryFacilitator.isValidWord(suggestionInfo.mWord, true /* ignoreCase */) + && mDictionaryFacilitator.isUserDictionaryEnabled(); + } + + /** * A suggestion was picked from the suggestion strip. * @param settingsValues the current values of the settings. * @param suggestionInfo the suggestion info. @@ -297,14 +312,7 @@ public final class InputLogic { mSpaceState = SpaceState.PHANTOM; inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); - // We should show the "Touch again to save" hint if the user pressed the first entry - // AND it's in none of our current dictionaries (main, user or otherwise). - final boolean showingAddToDictionaryHint = - (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED) - || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION)) - && !mDictionaryFacilitator.isValidWord(suggestion, true /* ignoreCase */); - - if (showingAddToDictionaryHint && mDictionaryFacilitator.isUserDictionaryEnabled()) { + if (shouldShowAddToDictionaryHint(suggestionInfo)) { mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion); } else { // If we're not showing the "Touch again to save", then update the suggestion strip. @@ -743,6 +751,13 @@ public final class InputLogic { final InputTransaction inputTransaction, // TODO: remove this argument final LatinIME.UIHandler handler) { + // In case the "add to dictionary" hint was still displayed. + // TODO: Do we really need to check if we have composing text here? + if (!mWordComposer.isComposingWord() && + mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) { + mSuggestionStripViewAccessor.dismissAddToDictionaryHint(); + } + final int codePoint = event.mCodePoint; mSpaceState = SpaceState.NONE; if (inputTransaction.mSettingsValues.isWordSeparator(codePoint) @@ -838,8 +853,6 @@ public final class InputLogic { } else { sendKeyCodePoint(settingsValues, codePoint); } - // In case the "add to dictionary" hint was still displayed. - mSuggestionStripViewAccessor.dismissAddToDictionaryHint(); } inputTransaction.setRequiresUpdateSuggestions(); } @@ -1994,7 +2007,9 @@ public final class InputLogic { } /** - * Commits the chosen word to the text field and saves it for later retrieval. + * Commits the chosen word to the text field and saves it for later retrieval. This is a + * synonym of {@code commitChosenWordWithBackgroundColor(settingsValues, chosenWord, + * commitType, separatorString, Color.TRANSPARENT}. * * @param settingsValues the current values of the settings. * @param chosenWord the word we want to commit. @@ -2003,6 +2018,23 @@ public final class InputLogic { */ private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord, final int commitType, final String separatorString) { + commitChosenWordWithBackgroundColor(settingsValues, chosenWord, commitType, separatorString, + Color.TRANSPARENT); + } + + /** + * Commits the chosen word to the text field and saves it for later retrieval. + * + * @param settingsValues the current values of the settings. + * @param chosenWord the word we want to commit. + * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_* + * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none. + * @param backgroundColor the background color to be specified with the committed text. Pass + * {@link Color#TRANSPARENT} to not specify the background color. + */ + private void commitChosenWordWithBackgroundColor(final SettingsValues settingsValues, + final String chosenWord, final int commitType, final String separatorString, + final int backgroundColor) { final SuggestedWords suggestedWords = mSuggestedWords; final CharSequence chosenWordWithSuggestions = SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord, @@ -2012,7 +2044,7 @@ public final class InputLogic { // information from the 1st previous word. final PrevWordsInfo prevWordsInfo = mConnection.getPrevWordsInfoFromNthPreviousWord( settingsValues.mSpacingAndPunctuations, mWordComposer.isComposingWord() ? 2 : 1); - mConnection.commitText(chosenWordWithSuggestions, 1); + mConnection.commitTextWithBackgroundColor(chosenWordWithSuggestions, 1, backgroundColor); // Add the word to the user history dictionary performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWordsInfo); // TODO: figure out here if this is an auto-correct or if the best word is actually diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index c12474b3d..a9789d888 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -51,7 +51,7 @@ public class SettingsValues { // From resources: public final SpacingAndPunctuations mSpacingAndPunctuations; - public final int mDelayUpdateOldSuggestions; + public final int mDelayInMillisecondsToUpdateOldSuggestions; public final long mDoubleSpacePeriodTimeout; // From preferences, in the same order as xml/prefs.xml: @@ -107,7 +107,8 @@ public class SettingsValues { final InputAttributes inputAttributes) { mLocale = res.getConfiguration().locale; // Get the resources - mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); + mDelayInMillisecondsToUpdateOldSuggestions = + res.getInteger(R.integer.config_delay_in_milliseconds_to_update_old_suggestions); mSpacingAndPunctuations = new SpacingAndPunctuations(res); // Store the input attributes @@ -337,8 +338,8 @@ public class SettingsValues { final StringBuilder sb = new StringBuilder("Current settings :"); sb.append("\n mSpacingAndPunctuations = "); sb.append("" + mSpacingAndPunctuations.dump()); - sb.append("\n mDelayUpdateOldSuggestions = "); - sb.append("" + mDelayUpdateOldSuggestions); + sb.append("\n mDelayInMillisecondsToUpdateOldSuggestions = "); + sb.append("" + mDelayInMillisecondsToUpdateOldSuggestions); sb.append("\n mAutoCap = "); sb.append("" + mAutoCap); sb.append("\n mVibrateOn = "); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 90398deb2..47bff3ebb 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -39,6 +39,7 @@ import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.PrevWordsInfo; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.UserBinaryDictionary; @@ -334,7 +335,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(this, editorInfo); builder.setKeyboardGeometry( SPELLCHECKER_DUMMY_KEYBOARD_WIDTH, SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT); - builder.setSubtype(subtype); + builder.setSubtype(new RichInputMethodSubtype(subtype)); builder.setIsSpellChecker(true /* isSpellChecker */); builder.disableTouchPositionCorrectionData(); return builder.build(); diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index 346aea34a..9d186d44d 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -125,9 +125,9 @@ public final class MoreSuggestions extends Keyboard { } private static final int[][] COLUMN_ORDER_TO_NUMBER = { - { 0, }, - { 1, 0, }, - { 2, 0, 1}, + { 0 }, // center + { 1, 0 }, // right-left + { 1, 0, 2 }, // center-left-right }; public int getNumColumnInRow(final int index) { diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 7307ca1ba..1e8df8986 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -45,11 +45,14 @@ import android.widget.LinearLayout; import android.widget.TextView; import com.android.inputmethod.accessibility.AccessibilityUtils; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.define.DebugFlags; +import com.android.inputmethod.latin.settings.Settings; +import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.utils.AutoCorrectionUtils; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; @@ -72,7 +75,7 @@ final class SuggestionStripLayoutHelper { private int mMaxMoreSuggestionsRow; public final float mMinMoreSuggestionsWidth; public final int mMoreSuggestionsBottomGap; - public boolean mMoreSuggestionsAvailable; + private boolean mMoreSuggestionsAvailable; // The index of these {@link ArrayList} is the position in the suggestion strip. The indices // increase towards the right for LTR scripts and the left for RTL scripts, starting with 0. @@ -223,11 +226,59 @@ final class SuggestionStripLayoutHelper { return spannedWord; } + /** + * Convert an index of {@link SuggestedWords} to position in the suggestion strip. + * @param indexInSuggestedWords the index of {@link SuggestedWords}. + * @param suggestedWords the suggested words list + * @return Non-negative integer of the position in the suggestion strip. + * Negative integer if the word of the index shouldn't be shown on the suggestion strip. + */ private int getPositionInSuggestionStrip(final int indexInSuggestedWords, final SuggestedWords suggestedWords) { + final SettingsValues settingsValues = Settings.getInstance().getCurrent(); + final boolean shouldOmitTypedWord = shouldOmitTypedWord(suggestedWords.mInputStyle, + settingsValues.mGestureFloatingPreviewTextEnabled, + settingsValues.mShouldShowUiToAcceptTypedWord); + return getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords.mWillAutoCorrect, + settingsValues.mShouldShowUiToAcceptTypedWord && shouldOmitTypedWord, + mCenterPositionInStrip, mTypedWordPositionWhenAutocorrect); + } + + @UsedForTesting + static boolean shouldOmitTypedWord(final int inputStyle, + final boolean gestureFloatingPreviewTextEnabled, + final boolean shouldShowUiToAcceptTypedWord) { + final boolean omitTypedWord = (inputStyle == SuggestedWords.INPUT_STYLE_TYPING) + || (inputStyle == SuggestedWords.INPUT_STYLE_TAIL_BATCH) + || (inputStyle == SuggestedWords.INPUT_STYLE_UPDATE_BATCH + && gestureFloatingPreviewTextEnabled); + return shouldShowUiToAcceptTypedWord && omitTypedWord; + } + + @UsedForTesting + static int getPositionInSuggestionStrip(final int indexInSuggestedWords, + final boolean willAutoCorrect, final boolean omitTypedWord, + final int centerPositionInStrip, final int typedWordPositionWhenAutoCorrect) { + if (omitTypedWord) { + if (indexInSuggestedWords == SuggestedWords.INDEX_OF_TYPED_WORD) { + // Ignore. + return -1; + } + if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION) { + // Center in the suggestion strip. + return centerPositionInStrip; + } + // If neither of those, the order in the suggestion strip is left of the center first + // then right of the center, to both edges of the suggestion strip. + // For example, center-1, center+1, center-2, center+2, and so on. + final int n = indexInSuggestedWords; + final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2); + final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter; + return positionInSuggestionStrip; + } final int indexToDisplayMostImportantSuggestion; final int indexToDisplaySecondMostImportantSuggestion; - if (suggestedWords.mWillAutoCorrect) { + if (willAutoCorrect) { indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION; indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD; } else { @@ -235,25 +286,31 @@ final class SuggestionStripLayoutHelper { indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION; } if (indexInSuggestedWords == indexToDisplayMostImportantSuggestion) { - return mCenterPositionInStrip; + // Center in the suggestion strip. + return centerPositionInStrip; } if (indexInSuggestedWords == indexToDisplaySecondMostImportantSuggestion) { - return mTypedWordPositionWhenAutocorrect; + // Center-1. + return typedWordPositionWhenAutoCorrect; } - // If neither of those, the order in the suggestion strip is the same as in SuggestedWords. - return indexInSuggestedWords; + // If neither of those, the order in the suggestion strip is right of the center first + // then left of the center, to both edges of the suggestion strip. + // For example, Center+1, center-2, center+2, center-3, and so on. + final int n = indexInSuggestedWords + 1; + final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2); + final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter; + return positionInSuggestionStrip; } private int getSuggestionTextColor(final SuggestedWords suggestedWords, final int indexInSuggestedWords) { - final int positionInStrip = - getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords); // Use identity for strings, not #equals : it's the typed word if it's the same object final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf( SuggestedWordInfo.KIND_TYPED); final int color; - if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) { + if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION + && suggestedWords.mWillAutoCorrect) { color = mColorAutoCorrect; } else if (isTypedWord && suggestedWords.mTypedWordValid) { color = mColorValidTypedWord; @@ -265,7 +322,8 @@ final class SuggestionStripLayoutHelper { if (DebugFlags.DEBUG_ENABLED && suggestedWords.size() > 1) { // If we auto-correct, then the autocorrection is in slot 0 and the typed word // is in slot 1. - if (positionInStrip == mCenterPositionInStrip + if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION + && suggestedWords.mWillAutoCorrect && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet( suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION), suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) { @@ -292,31 +350,31 @@ final class SuggestionStripLayoutHelper { } /** - * Layout suggestions to the suggestions strip. And returns the number of suggestions displayed - * in the suggestions strip. + * Layout suggestions to the suggestions strip. And returns the start index of more + * suggestions. * * @param suggestedWords suggestions to be shown in the suggestions strip. * @param stripView the suggestions strip view. * @param placerView the view where the debug info will be placed. - * @return the number of suggestions displayed in the suggestions strip + * @return the start index of more suggestions. */ - public int layoutAndReturnSuggestionCountInStrip(final SuggestedWords suggestedWords, + public int layoutAndReturnStartIndexOfMoreSuggestions(final SuggestedWords suggestedWords, final ViewGroup stripView, final ViewGroup placerView) { if (suggestedWords.isPunctuationSuggestions()) { - return layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip( + return layoutPunctuationsAndReturnStartIndexOfMoreSuggestions( (PunctuationSuggestions)suggestedWords, stripView); } - setupWordViewsTextAndColor(suggestedWords, mSuggestionsCountInStrip); + final int startIndexOfMoreSuggestions = setupWordViewsAndReturnStartIndexOfMoreSuggestions( + suggestedWords, mSuggestionsCountInStrip); final TextView centerWordView = mWordViews.get(mCenterPositionInStrip); final int stripWidth = stripView.getWidth(); final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, stripWidth); - final int countInStrip; if (suggestedWords.size() == 1 || getTextScaleX(centerWordView.getText(), centerWidth, centerWordView.getPaint()) < MIN_TEXT_XSCALE) { // Layout only the most relevant suggested word at the center of the suggestion strip // by consolidating all slots in the strip. - countInStrip = 1; + final int countInStrip = 1; mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); layoutWord(mCenterPositionInStrip, stripWidth - mPadding); stripView.addView(centerWordView); @@ -324,31 +382,33 @@ final class SuggestionStripLayoutHelper { if (SuggestionStripView.DBG) { layoutDebugInfo(mCenterPositionInStrip, placerView, stripWidth); } - } else { - countInStrip = mSuggestionsCountInStrip; - mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); - int x = 0; - for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { - if (positionInStrip != 0) { - final View divider = mDividerViews.get(positionInStrip); - // Add divider if this isn't the left most suggestion in suggestions strip. - addDivider(stripView, divider); - x += divider.getMeasuredWidth(); - } - - final int width = getSuggestionWidth(positionInStrip, stripWidth); - final TextView wordView = layoutWord(positionInStrip, width); - stripView.addView(wordView); - setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), - ViewGroup.LayoutParams.MATCH_PARENT); - x += wordView.getMeasuredWidth(); - - if (SuggestionStripView.DBG) { - layoutDebugInfo(positionInStrip, placerView, x); - } + final Integer lastIndex = (Integer)centerWordView.getTag(); + return (lastIndex == null ? 0 : lastIndex) + 1; + } + + final int countInStrip = mSuggestionsCountInStrip; + mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); + int x = 0; + for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { + if (positionInStrip != 0) { + final View divider = mDividerViews.get(positionInStrip); + // Add divider if this isn't the left most suggestion in suggestions strip. + addDivider(stripView, divider); + x += divider.getMeasuredWidth(); + } + + final int width = getSuggestionWidth(positionInStrip, stripWidth); + final TextView wordView = layoutWord(positionInStrip, width); + stripView.addView(wordView); + setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), + ViewGroup.LayoutParams.MATCH_PARENT); + x += wordView.getMeasuredWidth(); + + if (SuggestionStripView.DBG) { + layoutDebugInfo(positionInStrip, placerView, x); } } - return countInStrip; + return startIndexOfMoreSuggestions; } /** @@ -426,10 +486,10 @@ final class SuggestionStripLayoutHelper { return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1); } - private void setupWordViewsTextAndColor(final SuggestedWords suggestedWords, - final int countInStrip) { + private int setupWordViewsAndReturnStartIndexOfMoreSuggestions( + final SuggestedWords suggestedWords, final int maxSuggestionInStrip) { // Clear all suggestions first - for (int positionInStrip = 0; positionInStrip < countInStrip; ++positionInStrip) { + for (int positionInStrip = 0; positionInStrip < maxSuggestionInStrip; ++positionInStrip) { final TextView wordView = mWordViews.get(positionInStrip); wordView.setText(null); wordView.setTag(null); @@ -438,11 +498,15 @@ final class SuggestionStripLayoutHelper { mDebugInfoViews.get(positionInStrip).setText(null); } } - final int count = Math.min(suggestedWords.size(), countInStrip); - for (int indexInSuggestedWords = 0; indexInSuggestedWords < count; - indexInSuggestedWords++) { + int count = 0; + int indexInSuggestedWords; + for (indexInSuggestedWords = 0; indexInSuggestedWords < suggestedWords.size() + && count < maxSuggestionInStrip; indexInSuggestedWords++) { final int positionInStrip = getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords); + if (positionInStrip < 0) { + continue; + } final TextView wordView = mWordViews.get(positionInStrip); // {@link TextView#getTag()} is used to get the index in suggestedWords at // {@link SuggestionStripView#onClick(View)}. @@ -453,10 +517,12 @@ final class SuggestionStripLayoutHelper { mDebugInfoViews.get(positionInStrip).setText( suggestedWords.getDebugString(indexInSuggestedWords)); } + count++; } + return indexInSuggestedWords; } - private int layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip( + private int layoutPunctuationsAndReturnStartIndexOfMoreSuggestions( final PunctuationSuggestions punctuationSuggestions, final ViewGroup stripView) { final int countInStrip = Math.min(punctuationSuggestions.size(), PUNCTUATIONS_IN_STRIP); for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) { @@ -483,8 +549,11 @@ final class SuggestionStripLayoutHelper { } public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip) { + final boolean shouldShowUiToAcceptTypedWord = Settings.getInstance().getCurrent() + .mShouldShowUiToAcceptTypedWord; final int stripWidth = addToDictionaryStrip.getWidth(); - final int width = stripWidth - mDividerWidth - mPadding * 2; + final int width = shouldShowUiToAcceptTypedWord ? stripWidth + : stripWidth - mDividerWidth - mPadding * 2; final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save); wordView.setTextColor(mColorTypedWord); @@ -494,25 +563,38 @@ final class SuggestionStripLayoutHelper { wordView.setText(wordToSave); wordView.setTextScaleX(wordScaleX); setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); + final int wordVisibility = shouldShowUiToAcceptTypedWord ? View.GONE : View.VISIBLE; + wordView.setVisibility(wordVisibility); + addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility); + final Resources res = addToDictionaryStrip.getResources(); + final CharSequence hintText; + final int hintWidth; + final float hintWeight; final TextView hintView = (TextView)addToDictionaryStrip.findViewById( R.id.hint_add_to_dictionary); + if (shouldShowUiToAcceptTypedWord) { + hintText = res.getText(R.string.hint_add_to_dictionary_without_word); + hintWidth = width; + hintWeight = 1.0f; + hintView.setGravity(Gravity.CENTER); + } else { + final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) + == ViewCompat.LAYOUT_DIRECTION_RTL); + final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; + final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage( + res.getConfiguration().locale); + final CharSequence hint = res.getText(R.string.hint_add_to_dictionary); + hintText = (isRtlLanguage == isRtlSystem) ? (arrow + hint) : (hint + arrow); + hintWidth = width - wordWidth; + hintWeight = 1.0f - mCenterSuggestionWeight; + hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START); + } hintView.setTextColor(mColorAutoCorrect); - final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) - == ViewCompat.LAYOUT_DIRECTION_RTL); - final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; - final Resources res = addToDictionaryStrip.getResources(); - final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale); - final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary); - final String hintWithArrow = (isRtlLanguage == isRtlSystem) - ? (arrow + hintText) : (hintText + arrow); - final int hintWidth = width - wordWidth; - hintView.setTextScaleX(1.0f); // Reset textScaleX. - final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint()); - hintView.setText(hintWithArrow); + final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); + hintView.setText(hintText); hintView.setTextScaleX(hintScaleX); - setLayoutWeight( - hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); + setLayoutWeight(hintView, hintWeight, ViewGroup.LayoutParams.MATCH_PARENT); } public void layoutImportantNotice(final View importantNoticeStrip, diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index 9b8c38a2d..33745a846 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -83,7 +83,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick Listener mListener; private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; - private int mSuggestionsCountInStrip; + private int mStartIndexOfMoreSuggestions; private final SuggestionStripLayoutHelper mLayoutHelper; private final StripVisibilityGroup mStripVisibilityGroup; @@ -214,7 +214,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick clear(); mStripVisibilityGroup.setLayoutDirection(isRtlLanguage); mSuggestedWords = suggestedWords; - mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip( + mStartIndexOfMoreSuggestions = mLayoutHelper.layoutAndReturnStartIndexOfMoreSuggestions( mSuggestedWords, mSuggestionsStrip, this); mStripVisibilityGroup.showSuggestionsStrip(); } @@ -337,7 +337,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick return false; } final SuggestionStripLayoutHelper layoutHelper = mLayoutHelper; - if (!layoutHelper.mMoreSuggestionsAvailable) { + if (mSuggestedWords.size() <= mStartIndexOfMoreSuggestions) { return false; } // Dismiss another {@link MoreKeysPanel} that may be being showed, for example @@ -350,7 +350,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final View container = mMoreSuggestionsContainer; final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; - builder.layout(mSuggestedWords, mSuggestionsCountInStrip, maxWidth, + builder.layout(mSuggestedWords, mStartIndexOfMoreSuggestions, maxWidth, (int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth), layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard); mMoreSuggestionsView.setKeyboard(builder.build()); @@ -363,7 +363,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mMoreSuggestionsListener); mOriginX = mLastX; mOriginY = mLastY; - for (int i = 0; i < mSuggestionsCountInStrip; i++) { + for (int i = 0; i < mStartIndexOfMoreSuggestions; i++) { mWordViews.get(i).setPressed(false); } return true; diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java index 27973287d..2207ffea9 100644 --- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java @@ -35,6 +35,7 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardLayoutSet; import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.PrevWordsInfo; +import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; @@ -131,7 +132,7 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res); final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res); builder.setKeyboardGeometry(keyboardWidth, keyboardHeight); - builder.setSubtype(subtype); + builder.setSubtype(new RichInputMethodSubtype(subtype)); builder.setIsSpellChecker(false /* isSpellChecker */); final KeyboardLayoutSet layoutSet = builder.build(); mKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET); diff --git a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java deleted file mode 100644 index 1ca895fdb..000000000 --- a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.utils; - -import android.view.inputmethod.InputMethodSubtype; - -public final class SpacebarLanguageUtils { - private SpacebarLanguageUtils() { - // Intentional empty constructor for utility class. - } - - // InputMethodSubtype's display name for spacebar text in its locale. - // isAdditionalSubtype (T=true, F=false) - // locale layout | Middle Full - // ------ ------- - --------- ---------------------- - // en_US qwerty F English English (US) exception - // en_GB qwerty F English English (UK) exception - // es_US spanish F Español Español (EE.UU.) exception - // fr azerty F Français Français - // fr_CA qwerty F Français Français (Canada) - // fr_CH swiss F Français Français (Suisse) - // de qwertz F Deutsch Deutsch - // de_CH swiss T Deutsch Deutsch (Schweiz) - // zz qwerty F QWERTY QWERTY - // fr qwertz T Français Français - // de qwerty T Deutsch Deutsch - // en_US azerty T English English (US) - // zz azerty T AZERTY AZERTY - // Get InputMethodSubtype's full display name in its locale. - public static String getFullDisplayName(final InputMethodSubtype subtype) { - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); - } - return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale()); - } - - // Get InputMethodSubtype's middle display name in its locale. - public static String getMiddleDisplayName(final InputMethodSubtype subtype) { - if (SubtypeLocaleUtils.isNoLanguage(subtype)) { - return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); - } - return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(subtype.getLocale()); - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 0db4106c5..96a6510fc 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -27,12 +27,17 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.RichInputMethodSubtype; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; +/** + * A helper class to deal with subtype locales. + */ +// TODO: consolidate this into RichInputMethodSubtype public final class SubtypeLocaleUtils { private static final String TAG = SubtypeLocaleUtils.class.getSimpleName(); @@ -109,10 +114,10 @@ public final class SubtypeLocaleUtils { sKeyboardLayoutToNameIdsMap.put(key, noLanguageResId); } - final String[] excetionalLocaleInRootLocale = res.getStringArray( + final String[] exceptionalLocaleInRootLocale = res.getStringArray( R.array.subtype_locale_displayed_in_root_locale); - for (int i = 0; i < excetionalLocaleInRootLocale.length; i++) { - sExceptionalLocaleDisplayedInRootLocale.add(excetionalLocaleInRootLocale[i]); + for (int i = 0; i < exceptionalLocaleInRootLocale.length; i++) { + sExceptionalLocaleDisplayedInRootLocale.add(exceptionalLocaleInRootLocale[i]); } final String[] exceptionalLocales = res.getStringArray( @@ -260,6 +265,7 @@ public final class SubtypeLocaleUtils { private static String getSubtypeDisplayNameInternal(final InputMethodSubtype subtype, final Locale displayLocale) { final String replacementString = getReplacementString(subtype, displayLocale); + // TODO: rework this for multi-lingual subtypes final int nameResId = subtype.getNameResId(); final RunInLocale<String> getSubtypeName = new RunInLocale<String>() { @Override @@ -282,12 +288,14 @@ public final class SubtypeLocaleUtils { getSubtypeName.runInLocale(sResources, displayLocale), displayLocale); } - public static boolean isNoLanguage(final InputMethodSubtype subtype) { + public static Locale getSubtypeLocale(final InputMethodSubtype subtype) { final String localeString = subtype.getLocale(); - return NO_LANGUAGE.equals(localeString); + return LocaleUtils.constructLocaleFromString(localeString); } - public static Locale getSubtypeLocale(final InputMethodSubtype subtype) { + // TODO: remove this. When RichInputMethodSubtype#getLocale is removed we can do away with this + // method at the same time. + public static Locale getSubtypeLocale(final RichInputMethodSubtype subtype) { final String localeString = subtype.getLocale(); return LocaleUtils.constructLocaleFromString(localeString); } @@ -301,6 +309,10 @@ public final class SubtypeLocaleUtils { return sKeyboardLayoutToDisplayNameMap.get(layoutName); } + public static String getKeyboardLayoutSetName(final RichInputMethodSubtype subtype) { + return getKeyboardLayoutSetName(subtype.getRawSubtype()); + } + public static String getKeyboardLayoutSetName(final InputMethodSubtype subtype) { String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET); if (keyboardLayoutSet == null) { @@ -336,7 +348,7 @@ public final class SubtypeLocaleUtils { return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0; } - public static boolean isRtlLanguage(final InputMethodSubtype subtype) { + public static boolean isRtlLanguage(final RichInputMethodSubtype subtype) { return isRtlLanguage(getSubtypeLocale(subtype)); } |