diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
27 files changed, 355 insertions, 800 deletions
diff --git a/java/src/com/android/inputmethod/latin/AssetFileAddress.java b/java/src/com/android/inputmethod/latin/AssetFileAddress.java index fd6c24dfe..923f43cbe 100644 --- a/java/src/com/android/inputmethod/latin/AssetFileAddress.java +++ b/java/src/com/android/inputmethod/latin/AssetFileAddress.java @@ -16,7 +16,7 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.common.FileUtils; import java.io.File; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index b5d0b446f..46cd3b8b2 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -24,6 +24,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.ComposedData; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.FileUtils; import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; @@ -33,7 +34,6 @@ import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; -import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.WordInputEventForPersonalization; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 1570bdae0..46c8d5562 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -21,11 +21,11 @@ import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.util.Log; +import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; import com.android.inputmethod.latin.utils.DictionaryInfoUtils; -import com.android.inputmethod.latin.utils.LocaleUtils; import java.io.File; import java.io.IOException; diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java index 95390aa9f..aefefd305 100644 --- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java +++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java @@ -17,7 +17,8 @@ package com.android.inputmethod.latin; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.settings.NativeSuggestOptions; +import com.android.inputmethod.latin.common.NativeSuggestOptions; +import com.android.inputmethod.latin.settings.AdditionalFeaturesSettingUtils; import com.android.inputmethod.latin.utils.JniUtils; import java.util.Locale; @@ -43,7 +44,8 @@ public final class DicTraverseSession { public final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; public final float[] mInputOutputWeightOfLangModelVsSpatialModel = new float[1]; - public final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions(); + public final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions( + AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE); private static native long setDicTraverseSessionNative(String locale, long dictSize); private static native void initDicTraverseSessionNative(long nativeDicTraverseSession, diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index b47eaa9bb..d9d22e0fc 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -23,6 +23,7 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.ComposedData; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.FileUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; @@ -32,7 +33,6 @@ import com.android.inputmethod.latin.utils.AsyncResultHolder; import com.android.inputmethod.latin.utils.CombinedFormatUtils; import com.android.inputmethod.latin.utils.DistracterFilter; import com.android.inputmethod.latin.utils.ExecutorUtils; -import com.android.inputmethod.latin.utils.FileUtils; import com.android.inputmethod.latin.utils.WordInputEventForPersonalization; import java.io.File; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index cd09bf6c7..719656b07 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -77,6 +77,7 @@ import com.android.inputmethod.keyboard.TextDecoratorUi; import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.CoordinateUtils; import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.define.ProductionFlags; @@ -93,7 +94,6 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; import com.android.inputmethod.latin.touchinputconsumer.GestureConsumer; import com.android.inputmethod.latin.utils.ApplicationUtils; import com.android.inputmethod.latin.utils.CapsModeUtils; -import com.android.inputmethod.latin.utils.CoordinateUtils; import com.android.inputmethod.latin.utils.CursorAnchorInfoUtils; import com.android.inputmethod.latin.utils.DialogUtils; import com.android.inputmethod.latin.utils.ImportantNoticeUtils; @@ -603,7 +603,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Has to be package-visible for unit tests @UsedForTesting void loadSettings() { - final Locale[] locales = mSubtypeSwitcher.getCurrentSubtypeLocales(); + final Locale[] locales = mRichImm.getCurrentSubtypeLocales(); final EditorInfo editorInfo = getCurrentInputEditorInfo(); final InputAttributes inputAttributes = new InputAttributes( editorInfo, isFullscreenMode(), getPackageName()); @@ -626,7 +626,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void refreshPersonalizationDictionarySession( final SettingsValues currentSettingsValues) { mDictionaryFacilitator.setIsMonolingualUser( - mSubtypeSwitcher.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes()); + mRichImm.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes()); mPersonalizationDictionaryUpdater.onLoadSettings( currentSettingsValues.mUsePersonalizedDicts); mContextualDictionaryUpdater.onLoadSettings(currentSettingsValues.mUsePersonalizedDicts); @@ -657,7 +657,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } void resetDictionaryFacilitatorIfNecessary() { - final Locale[] subtypeSwitcherLocales = mSubtypeSwitcher.getCurrentSubtypeLocales(); + final Locale[] subtypeSwitcherLocales = mRichImm.getCurrentSubtypeLocales(); if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales)) { return; } @@ -863,7 +863,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // also wouldn't be consuming gesture data. mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER; mRichImm.clearSubtypeCaches(); - mSubtypeSwitcher.refreshSubtypeInfo(); + mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentRawSubtype()); final KeyboardSwitcher switcher = mKeyboardSwitcher; switcher.updateKeyboardTheme(); final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView(); @@ -909,7 +909,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Update to a gesture consumer with the current editor and IME state. mGestureConsumer = GestureConsumer.newInstance(editorInfo, mInputLogic.getPrivateCommandPerformer(), - Arrays.asList(mSubtypeSwitcher.getCurrentSubtypeLocales()), + Arrays.asList(mRichImm.getCurrentSubtypeLocales()), switcher.getKeyboard()); // Forward this event to the accessibility utilities, if enabled. @@ -947,7 +947,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // span, so we should reset our state unconditionally, even if restarting is true. // We also tell the input logic about the combining rules for the current subtype, so // it can adjust its combiners if needed. - mInputLogic.startInput(mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype(), + mInputLogic.startInput(mRichImm.getCombiningRulesExtraValueOfCurrentSubtype(), currentSettingsValues); resetDictionaryFacilitatorIfNecessary(); @@ -1077,11 +1077,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd); } - // This call happens when we have a hardware keyboard as well as when we don't. While we - // don't support hardware keyboards yet we should avoid doing the processing associated - // with cursor movement when we have a hardware keyboard since we are not in charge. + // This call happens whether our view is displayed or not, but if it's not then we should + // not attempt recorrection. This is true even with a hardware keyboard connected: if the + // view is not displayed we have no means of showing suggestions anyway, and if it is then + // we want to show suggestions anyway. final SettingsValues settingsValues = mSettings.getCurrent(); - if ((!settingsValues.mHasHardwareKeyboard || ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) + if (isInputViewShown() && mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, settingsValues)) { mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(), @@ -1194,7 +1195,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (hasHardwareKeyboard && visibleKeyboardView.getVisibility() == View.GONE) { // If there is a hardware keyboard and a visible software keyboard view has been hidden, // no visual element will be shown on the screen. - outInsets.touchableInsets = inputHeight; + outInsets.contentTopInsets = inputHeight; outInsets.visibleTopInsets = inputHeight; mInsetsUpdater.setInsets(outInsets); return; @@ -1204,7 +1205,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ? mSuggestionStripView.getHeight() : 0; final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - suggestionsHeight; mSuggestionStripView.setMoreSuggestionsHeight(visibleTopY); - // Need to set touchable region only if a keyboard view is being shown. + // Need to set expanded touchable region only if a keyboard view is being shown. if (visibleKeyboardView.isShown()) { final int touchLeft = 0; final int touchTop = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY; @@ -1423,7 +1424,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // completely replace #onCodeInput. public void onEvent(@Nonnull final Event event) { if (Constants.CODE_SHORTCUT == event.mKeyCode) { - mSubtypeSwitcher.switchToShortcutIME(this); + mRichImm.switchToShortcutIME(this); } final InputTransaction completeInputTransaction = mInputLogic.onCodeInput(mSettings.getCurrent(), event, @@ -1467,7 +1468,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onStartBatchInput() { mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); mGestureConsumer.onGestureStarted( - Arrays.asList(mSubtypeSwitcher.getCurrentSubtypeLocales()), + Arrays.asList(mRichImm.getCurrentSubtypeLocales()), mKeyboardSwitcher.getKeyboard()); } @@ -1589,7 +1590,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // We should clear the contextual strip if there is no suggestion from dictionaries. || noSuggestionsFromDictionaries) { mSuggestionStripView.setSuggestions(suggestedWords, - mSubtypeSwitcher.getCurrentSubtype().isRtlSubtype()); + mRichImm.getCurrentSubtype().isRtlSubtype()); } } @@ -1810,7 +1811,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - mSubtypeSwitcher.onNetworkStateChanged(intent); + mRichImm.onNetworkStateChanged(intent); } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { AudioAndHapticFeedbackManager.getInstance().onRingerModeChanged(); } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index 8d8e7ac38..a1ac55a20 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -17,9 +17,15 @@ package com.android.inputmethod.latin; import static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE; +import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.REQ_NETWORK_CONNECTIVITY; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.inputmethodservice.InputMethodService; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.AsyncTask; import android.os.Build; import android.os.IBinder; import android.preference.PreferenceManager; @@ -28,7 +34,9 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.latin.settings.AdditionalFeaturesSettingUtils; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; @@ -36,7 +44,11 @@ import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; import javax.annotation.Nonnull; @@ -46,6 +58,7 @@ import javax.annotation.Nonnull; // non final for easy mocking. public class RichInputMethodManager { private static final String TAG = RichInputMethodManager.class.getSimpleName(); + private static final boolean DEBUG = false; private RichInputMethodManager() { // This utility class is not publicly instantiable. @@ -56,6 +69,10 @@ public class RichInputMethodManager { private Context mContext; private InputMethodManagerCompatWrapper mImmWrapper; private InputMethodInfoCache mInputMethodInfoCache; + private RichInputMethodSubtype mCurrentRichInputMethodSubtype; + private InputMethodInfo mShortcutInputMethodInfo; + private InputMethodSubtype mShortcutSubtype; + private boolean mIsNetworkConnected; final HashMap<InputMethodInfo, List<InputMethodSubtype>> mSubtypeListCacheWithImplicitlySelectedSubtypes = new HashMap<>(); final HashMap<InputMethodInfo, List<InputMethodSubtype>> @@ -95,6 +112,11 @@ public class RichInputMethodManager { SubtypeLocaleUtils.init(context); final InputMethodSubtype[] additionalSubtypes = getAdditionalSubtypes(context); setAdditionalInputMethodSubtypes(additionalSubtypes); + + final ConnectivityManager connectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkInfo info = connectivityManager.getActiveNetworkInfo(); + mIsNetworkConnected = (info != null && info.isConnected()); } public InputMethodSubtype[] getAdditionalSubtypes(final Context context) { @@ -304,10 +326,47 @@ public class RichInputMethodManager { } @Nonnull + public RichInputMethodSubtype onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) { + final RichInputMethodSubtype richSubtype = createCurrentRichInputMethodSubtype(newSubtype); + if (DEBUG) { + Log.w(TAG, "onSubtypeChanged: " + richSubtype.getNameForLogging()); + } + mCurrentRichInputMethodSubtype = richSubtype; + return richSubtype; + } + + private static RichInputMethodSubtype sForcedSubtypeForTesting = null; + + @UsedForTesting + static void forceSubtype(final InputMethodSubtype subtype) { + sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype); + } + + public Locale[] getCurrentSubtypeLocales() { + if (null != sForcedSubtypeForTesting) { + return sForcedSubtypeForTesting.getLocales(); + } + return getCurrentSubtype().getLocales(); + } + + public RichInputMethodSubtype getCurrentSubtype() { + if (null != sForcedSubtypeForTesting) { + return sForcedSubtypeForTesting; + } + return mCurrentRichInputMethodSubtype; + } + + + public String getCombiningRulesExtraValueOfCurrentSubtype() { + return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype()); + } + + @Nonnull public InputMethodSubtype getCurrentRawSubtype() { return mImmWrapper.mImm.getCurrentInputMethodSubtype(); } + @Nonnull public RichInputMethodSubtype createCurrentRichInputMethodSubtype( @Nonnull final InputMethodSubtype rawSubtype) { return AdditionalFeaturesSettingUtils.createRichInputMethodSubtype(this, rawSubtype, @@ -432,4 +491,121 @@ public class RichInputMethodManager { } return mImmWrapper.shouldOfferSwitchingToNextInputMethod(binder); } + + public boolean isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes() { + final Locale systemLocale = mContext.getResources().getConfiguration().locale; + final Set<InputMethodSubtype> enabledSubtypesOfEnabledImes = new HashSet<>(); + final InputMethodManager inputMethodManager = getInputMethodManager(); + final List<InputMethodInfo> enabledInputMethodInfoList = + inputMethodManager.getEnabledInputMethodList(); + for (final InputMethodInfo info : enabledInputMethodInfoList) { + final List<InputMethodSubtype> enabledSubtypes = + inputMethodManager.getEnabledInputMethodSubtypeList( + info, true /* allowsImplicitlySelectedSubtypes */); + if (enabledSubtypes.isEmpty()) { + // An IME with no subtypes is found. + return false; + } + enabledSubtypesOfEnabledImes.addAll(enabledSubtypes); + } + for (final InputMethodSubtype subtype : enabledSubtypesOfEnabledImes) { + if (!subtype.isAuxiliary() && !subtype.getLocale().isEmpty() + && !systemLocale.equals(SubtypeLocaleUtils.getSubtypeLocale(subtype))) { + return false; + } + } + return true; + } + + // TODO: Make this private + void updateShortcutIME() { + if (DEBUG) { + Log.d(TAG, "Update shortcut IME from : " + + (mShortcutInputMethodInfo == null + ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " + + (mShortcutSubtype == null ? "<null>" : ( + mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); + } + // TODO: Update an icon for shortcut IME + final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts = + getInputMethodManager().getShortcutInputMethodsAndSubtypes(); + mShortcutInputMethodInfo = null; + mShortcutSubtype = null; + for (final InputMethodInfo imi : shortcuts.keySet()) { + final List<InputMethodSubtype> subtypes = shortcuts.get(imi); + // TODO: Returns the first found IMI for now. Should handle all shortcuts as + // appropriate. + mShortcutInputMethodInfo = imi; + // TODO: Pick up the first found subtype for now. Should handle all subtypes + // as appropriate. + mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null; + break; + } + if (DEBUG) { + Log.d(TAG, "Update shortcut IME to : " + + (mShortcutInputMethodInfo == null + ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " + + (mShortcutSubtype == null ? "<null>" : ( + mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); + } + } + + public void switchToShortcutIME(final InputMethodService context) { + if (mShortcutInputMethodInfo == null) { + return; + } + + final String imiId = mShortcutInputMethodInfo.getId(); + switchToTargetIME(imiId, mShortcutSubtype, context); + } + + private void switchToTargetIME(final String imiId, final InputMethodSubtype subtype, + final InputMethodService context) { + final IBinder token = context.getWindow().getWindow().getAttributes().token; + if (token == null) { + return; + } + final InputMethodManager imm = getInputMethodManager(); + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + imm.setInputMethodAndSubtype(token, imiId, subtype); + return null; + } + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + public boolean isShortcutImeEnabled() { + updateShortcutIME(); + if (mShortcutInputMethodInfo == null) { + return false; + } + if (mShortcutSubtype == null) { + return true; + } + return checkIfSubtypeBelongsToImeAndEnabled( + mShortcutInputMethodInfo, mShortcutSubtype); + } + + public boolean isShortcutImeReady() { + updateShortcutIME(); + if (mShortcutInputMethodInfo == null) { + return false; + } + if (mShortcutSubtype == null) { + return true; + } + if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) { + return mIsNetworkConnected; + } + return true; + } + + public void onNetworkStateChanged(final Intent intent) { + final boolean noConnection = intent.getBooleanExtra( + ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + mIsNetworkConnected = !noConnection; + + KeyboardSwitcher.getInstance().onNetworkStateChanged(); + } } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java index 8d055531c..03f6d60ab 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java @@ -16,33 +16,45 @@ package com.android.inputmethod.latin; +import static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE; + +import android.util.Log; import android.view.inputmethod.InputMethodSubtype; -import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; +import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Arrays; import java.util.Locale; +import javax.annotation.Nonnull; + /** * 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 static final String TAG = RichInputMethodSubtype.class.getSimpleName(); + + @Nonnull private final InputMethodSubtype mSubtype; + @Nonnull private final Locale[] mLocales; - public RichInputMethodSubtype(final InputMethodSubtype subtype, final Locale... locales) { + public RichInputMethodSubtype(@Nonnull final InputMethodSubtype subtype, + @Nonnull final Locale... locales) { mSubtype = subtype; - mLocales = new Locale[locales.length+1]; + 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) { + public String getExtraValueOf(@Nonnull final String key) { return mSubtype.getExtraValueOf(key); } @@ -80,6 +92,7 @@ public final class RichInputMethodSubtype { // en_US azerty T English English (US) // zz azerty T AZERTY AZERTY // Get the RichInputMethodSubtype's full display name in its locale. + @Nonnull public String getFullDisplayName() { if (isNoLanguage()) { return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype); @@ -88,6 +101,7 @@ public final class RichInputMethodSubtype { } // Get the RichInputMethodSubtype's middle display name in its locale. + @Nonnull public String getMiddleDisplayName() { if (isNoLanguage()) { return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype); @@ -96,7 +110,7 @@ public final class RichInputMethodSubtype { } @Override - public boolean equals(Object o) { + public boolean equals(final Object o) { if (!(o instanceof RichInputMethodSubtype)) { return false; } @@ -114,6 +128,7 @@ public final class RichInputMethodSubtype { return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales); } + @Nonnull public Locale[] getLocales() { return mLocales; } @@ -124,5 +139,80 @@ public final class RichInputMethodSubtype { } // TODO: remove this method + @Nonnull public InputMethodSubtype getRawSubtype() { return mSubtype; } + + // Dummy no language QWERTY subtype. See {@link R.xml.method}. + private static final int SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE = 0xdde0bfd3; + private static final String EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE = + "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY + + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE + + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; + @Nonnull + 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)); + // 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; + @Nonnull + 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)); + private static RichInputMethodSubtype sNoLanguageSubtype; + private static RichInputMethodSubtype sEmojiSubtype; + + @Nonnull + public static RichInputMethodSubtype getNoLanguageSubtype() { + RichInputMethodSubtype noLanguageSubtype = sNoLanguageSubtype; + if (noLanguageSubtype == null) { + final InputMethodSubtype rawNoLanguageSubtype = RichInputMethodManager.getInstance() + .findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY); + if (rawNoLanguageSubtype != null) { + noLanguageSubtype = new RichInputMethodSubtype(rawNoLanguageSubtype); + } + } + if (noLanguageSubtype != null) { + sNoLanguageSubtype = noLanguageSubtype; + return noLanguageSubtype; + } + Log.w(TAG, "Can't find any language with QWERTY subtype"); + Log.w(TAG, "No input method subtype found; returning dummy subtype: " + + DUMMY_NO_LANGUAGE_SUBTYPE); + return DUMMY_NO_LANGUAGE_SUBTYPE; + } + + @Nonnull + public static RichInputMethodSubtype getEmojiSubtype() { + RichInputMethodSubtype emojiSubtype = sEmojiSubtype; + if (emojiSubtype == null) { + final InputMethodSubtype rawEmojiSubtype = RichInputMethodManager.getInstance() + .findSubtypeByLocaleAndKeyboardLayoutSet( + SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI); + if (rawEmojiSubtype != null) { + emojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype); + } + } + if (emojiSubtype != null) { + sEmojiSubtype = emojiSubtype; + return emojiSubtype; + } + Log.w(TAG, "Can't find emoji subtype"); + Log.w(TAG, "No input method subtype found; returning dummy subtype: " + + DUMMY_EMOJI_SUBTYPE); + return DUMMY_EMOJI_SUBTYPE; + } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 98bce95bd..b2766e27a 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -16,40 +16,19 @@ package com.android.inputmethod.latin; -import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.REQ_NETWORK_CONNECTIVITY; import android.content.Context; -import android.content.Intent; import android.content.res.Resources; -import android.inputmethodservice.InputMethodService; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.AsyncTask; -import android.os.IBinder; -import android.util.Log; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; -import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; -import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; -import java.util.HashSet; import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Set; import javax.annotation.Nonnull; public final class SubtypeSwitcher { - private static boolean DBG = DebugFlags.DEBUG_ENABLED; - private static final String TAG = SubtypeSwitcher.class.getSimpleName(); - private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); private /* final */ RichInputMethodManager mRichImm; @@ -57,41 +36,6 @@ public final class SubtypeSwitcher { private final LanguageOnSpacebarHelper mLanguageOnSpacebarHelper = new LanguageOnSpacebarHelper(); - private InputMethodInfo mShortcutInputMethodInfo; - private InputMethodSubtype mShortcutSubtype; - private RichInputMethodSubtype mCurrentRichInputMethodSubtype; - private RichInputMethodSubtype mNoLanguageSubtype; - private RichInputMethodSubtype mEmojiSubtype; - private boolean mIsNetworkConnected; - - private static final String KEYBOARD_MODE = "keyboard"; - // Dummy no language QWERTY subtype. See {@link R.xml.method}. - private static final int SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE = 0xdde0bfd3; - private static final String EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE = - "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY - + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE - + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE - + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE; - 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)); - // 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 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)); public static SubtypeSwitcher getInstance() { return sInstance; @@ -113,18 +57,9 @@ public final class SubtypeSwitcher { } mResources = context.getResources(); mRichImm = RichInputMethodManager.getInstance(); - ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( - Context.CONNECTIVITY_SERVICE); - - final NetworkInfo info = connectivityManager.getActiveNetworkInfo(); - mIsNetworkConnected = (info != null && info.isConnected()); - - refreshSubtypeInfo(); - updateParametersOnStartInputView(); - } - public void refreshSubtypeInfo() { onSubtypeChanged(mRichImm.getCurrentRawSubtype()); + updateParametersOnStartInputView(); } /** @@ -135,49 +70,12 @@ public final class SubtypeSwitcher { final List<InputMethodSubtype> enabledSubtypesOfThisIme = mRichImm.getMyEnabledInputMethodSubtypeList(true); mLanguageOnSpacebarHelper.updateEnabledSubtypes(enabledSubtypesOfThisIme); - updateShortcutIME(); - } - - private void updateShortcutIME() { - if (DBG) { - Log.d(TAG, "Update shortcut IME from : " - + (mShortcutInputMethodInfo == null - ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " - + (mShortcutSubtype == null ? "<null>" : ( - mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); - } - // TODO: Update an icon for shortcut IME - final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts = - mRichImm.getInputMethodManager().getShortcutInputMethodsAndSubtypes(); - mShortcutInputMethodInfo = null; - mShortcutSubtype = null; - for (final InputMethodInfo imi : shortcuts.keySet()) { - final List<InputMethodSubtype> subtypes = shortcuts.get(imi); - // TODO: Returns the first found IMI for now. Should handle all shortcuts as - // appropriate. - mShortcutInputMethodInfo = imi; - // TODO: Pick up the first found subtype for now. Should handle all subtypes - // as appropriate. - mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null; - break; - } - if (DBG) { - Log.d(TAG, "Update shortcut IME to : " - + (mShortcutInputMethodInfo == null - ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " - + (mShortcutSubtype == null ? "<null>" : ( - mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); - } + mRichImm.updateShortcutIME(); } // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. public void onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) { - final RichInputMethodSubtype richSubtype = - mRichImm.createCurrentRichInputMethodSubtype(newSubtype); - if (DBG) { - Log.w(TAG, "onSubtypeChanged: " + richSubtype.getNameForLogging()); - } - mCurrentRichInputMethodSubtype = richSubtype; + final RichInputMethodSubtype richSubtype = mRichImm.onSubtypeChanged(newSubtype); final Locale[] newLocales = richSubtype.getLocales(); if (newLocales.length > 1) { // In multi-locales mode, the system language is never the same as the input language @@ -193,160 +91,10 @@ public final class SubtypeSwitcher { mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage( sameLocale || (sameLanguage && implicitlyEnabled)); } - updateShortcutIME(); - } - - //////////////////////////// - // Shortcut IME functions // - //////////////////////////// - - public void switchToShortcutIME(final InputMethodService context) { - if (mShortcutInputMethodInfo == null) { - return; - } - - final String imiId = mShortcutInputMethodInfo.getId(); - switchToTargetIME(imiId, mShortcutSubtype, context); - } - - private void switchToTargetIME(final String imiId, final InputMethodSubtype subtype, - final InputMethodService context) { - final IBinder token = context.getWindow().getWindow().getAttributes().token; - if (token == null) { - return; - } - final InputMethodManager imm = mRichImm.getInputMethodManager(); - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - imm.setInputMethodAndSubtype(token, imiId, subtype); - return null; - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + mRichImm.updateShortcutIME(); } - public boolean isShortcutImeEnabled() { - updateShortcutIME(); - if (mShortcutInputMethodInfo == null) { - return false; - } - if (mShortcutSubtype == null) { - return true; - } - return mRichImm.checkIfSubtypeBelongsToImeAndEnabled( - mShortcutInputMethodInfo, mShortcutSubtype); - } - - public boolean isShortcutImeReady() { - updateShortcutIME(); - if (mShortcutInputMethodInfo == null) { - return false; - } - if (mShortcutSubtype == null) { - return true; - } - if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) { - return mIsNetworkConnected; - } - return true; - } - - public void onNetworkStateChanged(final Intent intent) { - final boolean noConnection = intent.getBooleanExtra( - ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - mIsNetworkConnected = !noConnection; - - KeyboardSwitcher.getInstance().onNetworkStateChanged(); - } - - ////////////////////////////////// - // Subtype Switching functions // - ////////////////////////////////// - public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) { return mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(subtype); } - - public boolean isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes() { - final Locale systemLocale = mResources.getConfiguration().locale; - final Set<InputMethodSubtype> enabledSubtypesOfEnabledImes = new HashSet<>(); - final InputMethodManager inputMethodManager = mRichImm.getInputMethodManager(); - final List<InputMethodInfo> enabledInputMethodInfoList = - inputMethodManager.getEnabledInputMethodList(); - for (final InputMethodInfo info : enabledInputMethodInfoList) { - final List<InputMethodSubtype> enabledSubtypes = - inputMethodManager.getEnabledInputMethodSubtypeList( - info, true /* allowsImplicitlySelectedSubtypes */); - if (enabledSubtypes.isEmpty()) { - // An IME with no subtypes is found. - return false; - } - enabledSubtypesOfEnabledImes.addAll(enabledSubtypes); - } - for (final InputMethodSubtype subtype : enabledSubtypesOfEnabledImes) { - if (!subtype.isAuxiliary() && !subtype.getLocale().isEmpty() - && !systemLocale.equals(SubtypeLocaleUtils.getSubtypeLocale(subtype))) { - return false; - } - } - return true; - } - - private static RichInputMethodSubtype sForcedSubtypeForTesting = null; - - @UsedForTesting - static void forceSubtype(final InputMethodSubtype subtype) { - sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype); - } - - public Locale[] getCurrentSubtypeLocales() { - if (null != sForcedSubtypeForTesting) { - return sForcedSubtypeForTesting.getLocales(); - } - return getCurrentSubtype().getLocales(); - } - - public RichInputMethodSubtype getCurrentSubtype() { - if (null != sForcedSubtypeForTesting) { - return sForcedSubtypeForTesting; - } - return mCurrentRichInputMethodSubtype; - } - - public RichInputMethodSubtype getNoLanguageSubtype() { - if (mNoLanguageSubtype == null) { - mNoLanguageSubtype = new RichInputMethodSubtype( - mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY)); - } - if (mNoLanguageSubtype != null) { - return mNoLanguageSubtype; - } - Log.w(TAG, "Can't find any language with QWERTY subtype"); - Log.w(TAG, "No input method subtype found; returning dummy subtype: " - + DUMMY_NO_LANGUAGE_SUBTYPE); - return DUMMY_NO_LANGUAGE_SUBTYPE; - } - - public RichInputMethodSubtype getEmojiSubtype() { - if (mEmojiSubtype == null) { - final InputMethodSubtype rawEmojiSubtype = - mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI); - if (null != rawEmojiSubtype) { - mEmojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype); - } - } - if (mEmojiSubtype != null) { - return mEmojiSubtype; - } - Log.w(TAG, "Can't find emoji subtype"); - Log.w(TAG, "No input method subtype found; returning dummy subtype: " - + DUMMY_EMOJI_SUBTYPE); - return DUMMY_EMOJI_SUBTYPE; - } - - public String getCombiningRulesExtraValueOfCurrentSubtype() { - return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype()); - } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 9b4619d35..ee8d3f8cb 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -230,7 +230,7 @@ public final class Suggest { inputStyle = inputStyleIfNotPrediction; } callback.onGetSuggestedWords(new SuggestedWords(suggestionsList, - suggestionResults.mRawSuggestions, + suggestionResults.mRawSuggestions, typedWord, // TODO: this first argument is lying. If this is a whitelisted word which is an // actual word, it says typedWordValid = false, which looks wrong. We should either // rename the attribute or change the value. @@ -286,8 +286,12 @@ public final class Suggest { // (typedWordValid=true), not as an "auto correct word" (willAutoCorrect=false). // Note that because this method is never used to get predictions, there is no need to // modify inputType such in getSuggestedWordsForNonBatchInput. + final String pseudoTypedWord = suggestionsContainer.isEmpty() ? null + : suggestionsContainer.get(0).mWord; + callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer, suggestionResults.mRawSuggestions, + pseudoTypedWord, true /* typedWordValid */, false /* willAutoCorrect */, false /* isObsoleteSuggestions */, diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index c51e20f21..bddeac495 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -73,21 +73,11 @@ public class SuggestedWords { final boolean willAutoCorrect, final boolean isObsoleteSuggestions, final int inputStyle) { - this(suggestedWordInfoList, rawSuggestions, typedWordValid, willAutoCorrect, - isObsoleteSuggestions, inputStyle, NOT_A_SEQUENCE_NUMBER); - } - - public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, - final ArrayList<SuggestedWordInfo> rawSuggestions, - final boolean typedWordValid, - final boolean willAutoCorrect, - final boolean isObsoleteSuggestions, - final int inputStyle, - final int sequenceNumber) { this(suggestedWordInfoList, rawSuggestions, (suggestedWordInfoList.isEmpty() || isPrediction(inputStyle)) ? null : suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord, - typedWordValid, willAutoCorrect, isObsoleteSuggestions, inputStyle, sequenceNumber); + typedWordValid, willAutoCorrect, + isObsoleteSuggestions, inputStyle, NOT_A_SEQUENCE_NUMBER); } public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index fa55319d2..78860d87d 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -21,10 +21,10 @@ import com.android.inputmethod.event.Event; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.ComposedData; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.CoordinateUtils; import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; -import com.android.inputmethod.latin.utils.CoordinateUtils; import java.util.ArrayList; import java.util.Collections; diff --git a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java index d4be0e397..78bfd2b52 100644 --- a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java +++ b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java @@ -26,10 +26,10 @@ import android.os.Environment; import com.android.inputmethod.latin.BinaryDictionaryFileDumper; import com.android.inputmethod.latin.BinaryDictionaryGetter; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.utils.DialogUtils; import com.android.inputmethod.latin.utils.DictionaryInfoUtils; -import com.android.inputmethod.latin.utils.LocaleUtils; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index 331f85e0e..ac2fc07c2 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -19,7 +19,7 @@ package com.android.inputmethod.latin.personalization; import android.content.Context; import android.util.Log; -import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.common.FileUtils; import java.io.File; import java.io.FilenameFilter; diff --git a/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java b/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java deleted file mode 100644 index 7603dbba5..000000000 --- a/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2013 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.settings; - -public class NativeSuggestOptions { - // Need to update suggest_options.h when you add, remove or reorder options. - private static final int IS_GESTURE = 0; - private static final int USE_FULL_EDIT_DISTANCE = 1; - private static final int BLOCK_OFFENSIVE_WORDS = 2; - private static final int SPACE_AWARE_GESTURE_ENABLED = 3; - private static final int WEIGHT_FOR_LOCALE_IN_THOUSANDS = 4; - private static final int OPTIONS_SIZE = 5; - - private final int[] mOptions = new int[OPTIONS_SIZE - + AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE]; - - public void setIsGesture(final boolean value) { - setBooleanOption(IS_GESTURE, value); - } - - public void setUseFullEditDistance(final boolean value) { - setBooleanOption(USE_FULL_EDIT_DISTANCE, value); - } - - public void setBlockOffensiveWords(final boolean value) { - setBooleanOption(BLOCK_OFFENSIVE_WORDS, value); - } - - public void setSpaceAwareGestureEnabled(final boolean value) { - setBooleanOption(SPACE_AWARE_GESTURE_ENABLED, value); - } - - public void setWeightForLocale(final float value) { - // We're passing this option as a fixed point value, in thousands. This is decoded in - // native code by SuggestOptions#weightForLocale(). - setIntegerOption(WEIGHT_FOR_LOCALE_IN_THOUSANDS, (int) (value * 1000)); - } - - public void setAdditionalFeaturesOptions(final int[] additionalOptions) { - if (additionalOptions == null) { - return; - } - for (int i = 0; i < additionalOptions.length; i++) { - setIntegerOption(OPTIONS_SIZE + i, additionalOptions[i]); - } - } - - public int[] getOptions() { - return mOptions; - } - - private void setBooleanOption(final int key, final boolean value) { - mOptions[key] = value ? 1 : 0; - } - - private void setIntegerOption(final int key, final int value) { - mOptions[key] = value; - } -} diff --git a/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java index 49db2bdc0..c0ceb8857 100644 --- a/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java @@ -24,7 +24,7 @@ import android.preference.Preference; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.RichInputMethodManager; /** * "Preferences" settings sub screen. @@ -49,7 +49,7 @@ public final class PreferencesSettingsFragment extends SubScreenFragment { // When we are called from the Settings application but we are not already running, some // singleton and utility classes may not have been initialized. We have to call // initialization method of these classes here. See {@link LatinIME#onCreate()}. - SubtypeSwitcher.init(context); + RichInputMethodManager.init(context); final boolean showVoiceKeyOption = res.getBoolean( R.bool.config_enable_show_voice_key_option); @@ -71,7 +71,7 @@ public final class PreferencesSettingsFragment extends SubScreenFragment { super.onResume(); final Preference voiceInputKeyOption = findPreference(Settings.PREF_VOICE_INPUT_KEY); if (voiceInputKeyOption != null) { - final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance() + final boolean isShortcutImeEnabled = RichInputMethodManager.getInstance() .isShortcutImeEnabled(); voiceInputKeyOption.setEnabled(isShortcutImeEnabled); voiceInputKeyOption.setSummary( diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 509b41fd3..26415e7d4 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -28,7 +28,6 @@ import com.android.inputmethod.compat.AppWorkaroundsUtils; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodManager; -import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.utils.AsyncResultHolder; import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; @@ -140,7 +139,7 @@ public class SettingsValues { DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true); mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res) && mInputAttributes.mShouldShowVoiceInputKey - && SubtypeSwitcher.getInstance().isShortcutImeEnabled(); + && RichInputMethodManager.getInstance().isShortcutImeEnabled(); final String autoCorrectionThresholdRawValue = prefs.getString( Settings.PREF_AUTO_CORRECTION_THRESHOLD, res.getString(R.string.auto_correction_threshold_mode_index_modest)); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 3ad8fb910..c90e8a3cf 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -34,10 +34,10 @@ import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.CoordinateUtils; +import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; -import com.android.inputmethod.latin.utils.CoordinateUtils; -import com.android.inputmethod.latin.utils.LocaleUtils; import com.android.inputmethod.latin.utils.ScriptUtils; import com.android.inputmethod.latin.utils.SuggestionResults; diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java index eda81940f..22fc35a42 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java @@ -28,7 +28,7 @@ import android.widget.EditText; import com.android.inputmethod.compat.UserDictionaryCompatUtils; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.latin.common.LocaleUtils; import java.util.ArrayList; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java index 90e4faafd..b9ed35375 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java @@ -31,7 +31,7 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.latin.common.LocaleUtils; import java.util.List; import java.util.Locale; diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettingsUtils.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettingsUtils.java index e58727ec4..c0a946e42 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettingsUtils.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettingsUtils.java @@ -17,7 +17,7 @@ package com.android.inputmethod.latin.userdictionary; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.utils.LocaleUtils; +import com.android.inputmethod.latin.common.LocaleUtils; import android.content.Context; import android.text.TextUtils; diff --git a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java deleted file mode 100644 index 01f5e1079..000000000 --- a/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 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 java.util.ArrayList; -import java.util.Collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * Utility methods for working with collections. - */ -public final class CollectionUtils { - private CollectionUtils() { - // This utility class is not publicly instantiable. - } - - /** - * Converts a sub-range of the given array to an ArrayList of the appropriate type. - * @param array Array to be converted. - * @param start First index inclusive to be converted. - * @param end Last index exclusive to be converted. - * @throws IllegalArgumentException if start or end are out of range or start > end. - */ - @Nonnull - public static <E> ArrayList<E> arrayAsList(@Nonnull final E[] array, final int start, - final int end) { - if (start < 0 || start > end || end > array.length) { - throw new IllegalArgumentException("Invalid start: " + start + " end: " + end - + " with array.length: " + array.length); - } - - final ArrayList<E> list = new ArrayList<>(end - start); - for (int i = start; i < end; i++) { - list.add(array[i]); - } - return list; - } - - /** - * Tests whether c contains no elements, true if c is null or c is empty. - * @param c Collection to test. - * @return Whether c contains no elements. - */ - public static boolean isNullOrEmpty(@Nullable final Collection<?> c) { - return c == null || c.isEmpty(); - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java deleted file mode 100644 index 3a9705904..000000000 --- a/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2012 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 javax.annotation.Nonnull; - -public final class CoordinateUtils { - private static final int INDEX_X = 0; - private static final int INDEX_Y = 1; - private static final int ELEMENT_SIZE = INDEX_Y + 1; - - private CoordinateUtils() { - // This utility class is not publicly instantiable. - } - - @Nonnull - public static int[] newInstance() { - return new int[ELEMENT_SIZE]; - } - - public static int x(@Nonnull final int[] coords) { - return coords[INDEX_X]; - } - - public static int y(@Nonnull final int[] coords) { - return coords[INDEX_Y]; - } - - public static void set(@Nonnull final int[] coords, final int x, final int y) { - coords[INDEX_X] = x; - coords[INDEX_Y] = y; - } - - public static void copy(@Nonnull final int[] destination, @Nonnull final int[] source) { - destination[INDEX_X] = source[INDEX_X]; - destination[INDEX_Y] = source[INDEX_Y]; - } - - @Nonnull - public static int[] newCoordinateArray(final int arraySize) { - return new int[ELEMENT_SIZE * arraySize]; - } - - @Nonnull - public static int[] newCoordinateArray(final int arraySize, - final int defaultX, final int defaultY) { - final int[] result = new int[ELEMENT_SIZE * arraySize]; - for (int i = 0; i < arraySize; ++i) { - setXYInArray(result, i, defaultX, defaultY); - } - return result; - } - - public static int xFromArray(@Nonnull final int[] coordsArray, final int index) { - return coordsArray[ELEMENT_SIZE * index + INDEX_X]; - } - - public static int yFromArray(@Nonnull final int[] coordsArray, final int index) { - return coordsArray[ELEMENT_SIZE * index + INDEX_Y]; - } - - @Nonnull - public static int[] coordinateFromArray(@Nonnull final int[] coordsArray, final int index) { - final int[] coords = newInstance(); - set(coords, xFromArray(coordsArray, index), yFromArray(coordsArray, index)); - return coords; - } - - public static void setXYInArray(@Nonnull final int[] coordsArray, final int index, - final int x, final int y) { - final int baseIndex = ELEMENT_SIZE * index; - coordsArray[baseIndex + INDEX_X] = x; - coordsArray[baseIndex + INDEX_Y] = y; - } - - public static void setCoordinateInArray(@Nonnull final int[] coordsArray, final int index, - @Nonnull final int[] coords) { - setXYInArray(coordsArray, index, x(coords), y(coords)); - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java index 24025b272..81c3e3c61 100644 --- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java @@ -28,6 +28,7 @@ import com.android.inputmethod.latin.AssetFileAddress; import com.android.inputmethod.latin.BinaryDictionaryGetter; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; diff --git a/java/src/com/android/inputmethod/latin/utils/FileUtils.java b/java/src/com/android/inputmethod/latin/utils/FileUtils.java deleted file mode 100644 index f1106a6c6..000000000 --- a/java/src/com/android/inputmethod/latin/utils/FileUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2013 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 java.io.File; -import java.io.FilenameFilter; - -/** - * A simple class to help with removing directories recursively. - */ -public class FileUtils { - public static boolean deleteRecursively(final File path) { - if (path.isDirectory()) { - final File[] files = path.listFiles(); - if (files != null) { - for (final File child : files) { - deleteRecursively(child); - } - } - } - return path.delete(); - } - - public static boolean deleteFilteredFiles(final File dir, final FilenameFilter fileNameFilter) { - if (!dir.isDirectory()) { - return false; - } - final File[] files = dir.listFiles(fileNameFilter); - if (files == null) { - return false; - } - boolean hasDeletedAllFiles = true; - for (final File file : files) { - if (!deleteRecursively(file)) { - hasDeletedAllFiles = false; - } - } - return hasDeletedAllFiles; - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java deleted file mode 100644 index c519a0de6..000000000 --- a/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.inputmethod.latin.utils; - -import android.text.TextUtils; - -import java.util.HashMap; -import java.util.Locale; - -/** - * A class to help with handling Locales in string form. - * - * This file has the same meaning and features (and shares all of its code) with - * the one in the dictionary pack. They need to be kept synchronized; for any - * update/bugfix to this file, consider also updating/fixing the version in the - * dictionary pack. - */ -public final class LocaleUtils { - private LocaleUtils() { - // Intentional empty constructor for utility class. - } - - // Locale match level constants. - // A higher level of match is guaranteed to have a higher numerical value. - // Some room is left within constants to add match cases that may arise necessary - // in the future, for example differentiating between the case where the countries - // are both present and different, and the case where one of the locales does not - // specify the countries. This difference is not needed now. - - // Nothing matches. - public static final int LOCALE_NO_MATCH = 0; - // The languages matches, but the country are different. Or, the reference locale requires a - // country and the tested locale does not have one. - public static final int LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER = 3; - // The languages and country match, but the variants are different. Or, the reference locale - // requires a variant and the tested locale does not have one. - public static final int LOCALE_LANGUAGE_AND_COUNTRY_MATCH_VARIANT_DIFFER = 6; - // The required locale is null or empty so it will accept anything, and the tested locale - // is non-null and non-empty. - public static final int LOCALE_ANY_MATCH = 10; - // The language matches, and the tested locale specifies a country but the reference locale - // does not require one. - public static final int LOCALE_LANGUAGE_MATCH = 15; - // The language and the country match, and the tested locale specifies a variant but the - // reference locale does not require one. - public static final int LOCALE_LANGUAGE_AND_COUNTRY_MATCH = 20; - // The compared locales are fully identical. This is the best match level. - public static final int LOCALE_FULL_MATCH = 30; - - // The level at which a match is "normally" considered a locale match with standard algorithms. - // Don't use this directly, use #isMatch to test. - private static final int LOCALE_MATCH = LOCALE_ANY_MATCH; - - // Make this match the maximum match level. If this evolves to have more than 2 digits - // when written in base 10, also adjust the getMatchLevelSortedString method. - private static final int MATCH_LEVEL_MAX = 30; - - /** - * Return how well a tested locale matches a reference locale. - * - * This will check the tested locale against the reference locale and return a measure of how - * a well it matches the reference. The general idea is that the tested locale has to match - * every specified part of the required locale. A full match occur when they are equal, a - * partial match when the tested locale agrees with the reference locale but is more specific, - * and a difference when the tested locale does not comply with all requirements from the - * reference locale. - * In more detail, if the reference locale specifies at least a language and the testedLocale - * does not specify one, or specifies a different one, LOCALE_NO_MATCH is returned. If the - * reference locale is empty or null, it will match anything - in the form of LOCALE_FULL_MATCH - * if the tested locale is empty or null, and LOCALE_ANY_MATCH otherwise. If the reference and - * tested locale agree on the language, but not on the country, - * LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER is returned if the reference locale specifies a country, - * and LOCALE_LANGUAGE_MATCH otherwise. - * If they agree on both the language and the country, but not on the variant, - * LOCALE_LANGUAGE_AND_COUNTRY_MATCH_VARIANT_DIFFER is returned if the reference locale - * specifies a variant, and LOCALE_LANGUAGE_AND_COUNTRY_MATCH otherwise. If everything matches, - * LOCALE_FULL_MATCH is returned. - * Examples: - * en <=> en_US => LOCALE_LANGUAGE_MATCH - * en_US <=> en => LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER - * en_US_POSIX <=> en_US_Android => LOCALE_LANGUAGE_AND_COUNTRY_MATCH_VARIANT_DIFFER - * en_US <=> en_US_Android => LOCALE_LANGUAGE_AND_COUNTRY_MATCH - * sp_US <=> en_US => LOCALE_NO_MATCH - * de <=> de => LOCALE_FULL_MATCH - * en_US <=> en_US => LOCALE_FULL_MATCH - * "" <=> en_US => LOCALE_ANY_MATCH - * - * @param referenceLocale the reference locale to test against. - * @param testedLocale the locale to test. - * @return a constant that measures how well the tested locale matches the reference locale. - */ - public static int getMatchLevel(String referenceLocale, String testedLocale) { - if (TextUtils.isEmpty(referenceLocale)) { - return TextUtils.isEmpty(testedLocale) ? LOCALE_FULL_MATCH : LOCALE_ANY_MATCH; - } - if (null == testedLocale) return LOCALE_NO_MATCH; - String[] referenceParams = referenceLocale.split("_", 3); - String[] testedParams = testedLocale.split("_", 3); - // By spec of String#split, [0] cannot be null and length cannot be 0. - if (!referenceParams[0].equals(testedParams[0])) return LOCALE_NO_MATCH; - switch (referenceParams.length) { - case 1: - return 1 == testedParams.length ? LOCALE_FULL_MATCH : LOCALE_LANGUAGE_MATCH; - case 2: - if (1 == testedParams.length) return LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER; - if (!referenceParams[1].equals(testedParams[1])) - return LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER; - if (3 == testedParams.length) return LOCALE_LANGUAGE_AND_COUNTRY_MATCH; - return LOCALE_FULL_MATCH; - case 3: - if (1 == testedParams.length) return LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER; - if (!referenceParams[1].equals(testedParams[1])) - return LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER; - if (2 == testedParams.length) return LOCALE_LANGUAGE_AND_COUNTRY_MATCH_VARIANT_DIFFER; - if (!referenceParams[2].equals(testedParams[2])) - return LOCALE_LANGUAGE_AND_COUNTRY_MATCH_VARIANT_DIFFER; - return LOCALE_FULL_MATCH; - } - // It should be impossible to come here - return LOCALE_NO_MATCH; - } - - /** - * Return a string that represents this match level, with better matches first. - * - * The strings are sorted in lexicographic order: a better match will always be less than - * a worse match when compared together. - */ - public static String getMatchLevelSortedString(int matchLevel) { - // This works because the match levels are 0~99 (actually 0~30) - // Ideally this should use a number of digits equals to the 1og10 of the greater matchLevel - return String.format(Locale.ROOT, "%02d", MATCH_LEVEL_MAX - matchLevel); - } - - /** - * Find out whether a match level should be considered a match. - * - * This method takes a match level as returned by the #getMatchLevel method, and returns whether - * it should be considered a match in the usual sense with standard Locale functions. - * - * @param level the match level, as returned by getMatchLevel. - * @return whether this is a match or not. - */ - public static boolean isMatch(int level) { - return LOCALE_MATCH <= level; - } - - private static final HashMap<String, Locale> sLocaleCache = new HashMap<>(); - - /** - * Creates a locale from a string specification. - */ - public static Locale constructLocaleFromString(final String localeStr) { - if (localeStr == null) { - return null; - } - synchronized (sLocaleCache) { - Locale retval = sLocaleCache.get(localeStr); - if (retval != null) { - return retval; - } - String[] localeParams = localeStr.split("_", 3); - if (localeParams.length == 1) { - retval = new Locale(localeParams[0]); - } else if (localeParams.length == 2) { - retval = new Locale(localeParams[0], localeParams[1]); - } else if (localeParams.length == 3) { - retval = new Locale(localeParams[0], localeParams[1], localeParams[2]); - } - if (retval != null) { - sLocaleCache.put(localeStr, retval); - } - return retval; - } - } -} diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 55c1dc9e5..b36168b6c 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -28,12 +28,15 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodSubtype; +import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.common.StringUtils; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; +import javax.annotation.Nonnull; + /** * A helper class to deal with subtype locales. */ @@ -173,7 +176,8 @@ public final class SubtypeLocaleUtils { return nameId == null ? UNKNOWN_KEYBOARD_LAYOUT : nameId; } - public static Locale getDisplayLocaleOfSubtypeLocale(final String localeString) { + @Nonnull + public static Locale getDisplayLocaleOfSubtypeLocale(@Nonnull final String localeString) { if (NO_LANGUAGE.equals(localeString)) { return sResources.getConfiguration().locale; } @@ -183,17 +187,20 @@ public final class SubtypeLocaleUtils { return LocaleUtils.constructLocaleFromString(localeString); } - public static String getSubtypeLocaleDisplayNameInSystemLocale(final String localeString) { + public static String getSubtypeLocaleDisplayNameInSystemLocale( + @Nonnull final String localeString) { final Locale displayLocale = sResources.getConfiguration().locale; return getSubtypeLocaleDisplayNameInternal(localeString, displayLocale); } - public static String getSubtypeLocaleDisplayName(final String localeString) { + @Nonnull + public static String getSubtypeLocaleDisplayName(@Nonnull final String localeString) { final Locale displayLocale = getDisplayLocaleOfSubtypeLocale(localeString); return getSubtypeLocaleDisplayNameInternal(localeString, displayLocale); } - public static String getSubtypeLanguageDisplayName(final String localeString) { + @Nonnull + public static String getSubtypeLanguageDisplayName(@Nonnull final String localeString) { final Locale displayLocale = getDisplayLocaleOfSubtypeLocale(localeString); final String languageString; if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) { @@ -205,8 +212,9 @@ public final class SubtypeLocaleUtils { return getSubtypeLocaleDisplayNameInternal(languageString, displayLocale); } - private static String getSubtypeLocaleDisplayNameInternal(final String localeString, - final Locale displayLocale) { + @Nonnull + private static String getSubtypeLocaleDisplayNameInternal(@Nonnull final String localeString, + @Nonnull final Locale displayLocale) { if (NO_LANGUAGE.equals(localeString)) { // No language subtype should be displayed in system locale. return sResources.getString(R.string.subtype_no_language); @@ -255,8 +263,9 @@ public final class SubtypeLocaleUtils { // en_US azerty T English (US) (AZERTY) exception // zz azerty T Alphabet (AZERTY) in system locale - private static String getReplacementString(final InputMethodSubtype subtype, - final Locale displayLocale) { + @Nonnull + private static String getReplacementString(@Nonnull final InputMethodSubtype subtype, + @Nonnull final Locale displayLocale) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) { return subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME); @@ -264,20 +273,24 @@ public final class SubtypeLocaleUtils { return getSubtypeLocaleDisplayNameInternal(subtype.getLocale(), displayLocale); } - public static String getSubtypeDisplayNameInSystemLocale(final InputMethodSubtype subtype) { + @Nonnull + public static String getSubtypeDisplayNameInSystemLocale( + @Nonnull final InputMethodSubtype subtype) { final Locale displayLocale = sResources.getConfiguration().locale; return getSubtypeDisplayNameInternal(subtype, displayLocale); } - public static String getSubtypeNameForLogging(final InputMethodSubtype subtype) { + @Nonnull + public static String getSubtypeNameForLogging(@Nonnull final InputMethodSubtype subtype) { if (subtype == null) { return "<null subtype>"; } return getSubtypeLocale(subtype) + "/" + getKeyboardLayoutSetName(subtype); } - private static String getSubtypeDisplayNameInternal(final InputMethodSubtype subtype, - final Locale displayLocale) { + @Nonnull + private static String getSubtypeDisplayNameInternal(@Nonnull final InputMethodSubtype subtype, + @Nonnull final Locale displayLocale) { final String replacementString = getReplacementString(subtype, displayLocale); // TODO: rework this for multi-lingual subtypes final int nameResId = subtype.getNameResId(); @@ -302,21 +315,26 @@ public final class SubtypeLocaleUtils { getSubtypeName.runInLocale(sResources, displayLocale), displayLocale); } - public static Locale getSubtypeLocale(final InputMethodSubtype subtype) { + @Nonnull + public static Locale getSubtypeLocale(@Nonnull final InputMethodSubtype subtype) { final String localeString = subtype.getLocale(); return LocaleUtils.constructLocaleFromString(localeString); } - public static String getKeyboardLayoutSetDisplayName(final InputMethodSubtype subtype) { + @Nonnull + public static String getKeyboardLayoutSetDisplayName( + @Nonnull final InputMethodSubtype subtype) { final String layoutName = getKeyboardLayoutSetName(subtype); return getKeyboardLayoutSetDisplayName(layoutName); } - public static String getKeyboardLayoutSetDisplayName(final String layoutName) { + @Nonnull + public static String getKeyboardLayoutSetDisplayName(@Nonnull final String layoutName) { return sKeyboardLayoutToDisplayNameMap.get(layoutName); } - public static String getKeyboardLayoutSetName(final RichInputMethodSubtype subtype) { + @Nonnull + public static String getKeyboardLayoutSetName(@Nonnull final RichInputMethodSubtype subtype) { return getKeyboardLayoutSetName(subtype.getRawSubtype()); } |