aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java3
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java51
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java91
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java21
-rw-r--r--java/src/com/android/inputmethod/latin/NgramContext.java2
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputMethodManager.java63
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java9
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java103
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java38
-rw-r--r--java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java2
-rw-r--r--java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java13
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java44
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java37
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java2
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java20
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettings.java3
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java12
-rw-r--r--java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java1
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java6
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java14
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java3
-rw-r--r--java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java6
-rw-r--r--java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java20
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java11
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java76
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ResourceUtils.java55
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java7
29 files changed, 439 insertions, 278 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 5afb62b69..9c70cad0a 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -263,7 +263,8 @@ final public class BinaryDictionaryGetter {
public static ArrayList<AssetFileAddress> getDictionaryFiles(final Locale locale,
final Context context) {
- final boolean hasDefaultWordList = DictionaryFactory.isDictionaryAvailable(context, locale);
+ final boolean hasDefaultWordList = DictionaryInfoUtils.isDictionaryAvailable(
+ context, locale);
BinaryDictionaryFileDumper.cacheWordListsFromContentProvider(locale, context,
hasDefaultWordList);
final File[] cachedWordLists = getCachedWordLists(locale.toString(), context);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index b24fdea55..acf9cf10c 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -63,6 +63,9 @@ public class DictionaryFacilitator {
// HACK: This threshold is being used when adding a capitalized entry in the User History
// dictionary.
private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140;
+ // How many words we need to type in a row ({@see mConfidenceInMostProbableLanguage}) to
+ // declare we are confident the user is typing in the most probable language.
+ private static final int CONFIDENCE_THRESHOLD = 3;
private DictionaryGroup[] mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() };
private DictionaryGroup mMostProbableDictionaryGroup = mDictionaryGroups[0];
@@ -138,6 +141,10 @@ public class DictionaryFacilitator {
public final Locale mLocale;
private Dictionary mMainDict;
+ // Confidence that the most probable language is actually the language the user is
+ // typing in. For now, this is simply the number of times a word from this language
+ // has been committed in a row.
+ private int mConfidence = 0;
public float mWeightForTypingInLocale = WEIGHT_FOR_MOST_PROBABLE_LANGUAGE;
public float mWeightForGesturingInLocale = WEIGHT_FOR_MOST_PROBABLE_LANGUAGE;
public final ConcurrentHashMap<String, ExpandableBinaryDictionary> mSubDictMap =
@@ -257,11 +264,12 @@ public class DictionaryFacilitator {
return mMostProbableDictionaryGroup;
}
- public void switchMostProbableLanguage(final Locale locale) {
+ public void switchMostProbableLanguage(@Nullable final Locale locale) {
if (null == locale) {
// In many cases, there is no locale to a committed word. For example, a typed word
- // that does not auto-correct has no locale. In this case we simply do not change
- // the most probable language.
+ // that is in none of the currently active dictionaries but still does not
+ // auto-correct to anything has no locale. In this case we simply do not change
+ // the most probable language and do not touch confidence.
return;
}
final DictionaryGroup newMostProbableDictionaryGroup =
@@ -272,15 +280,31 @@ public class DictionaryFacilitator {
// facilitator any more. In this case, just not changing things is fine.
return;
}
- mMostProbableDictionaryGroup.mWeightForTypingInLocale =
- DictionaryGroup.WEIGHT_FOR_TYPING_IN_NOT_MOST_PROBABLE_LANGUAGE;
- mMostProbableDictionaryGroup.mWeightForGesturingInLocale =
- DictionaryGroup.WEIGHT_FOR_GESTURING_IN_NOT_MOST_PROBABLE_LANGUAGE;
- newMostProbableDictionaryGroup.mWeightForTypingInLocale =
- DictionaryGroup.WEIGHT_FOR_MOST_PROBABLE_LANGUAGE;
- newMostProbableDictionaryGroup.mWeightForGesturingInLocale =
- DictionaryGroup.WEIGHT_FOR_MOST_PROBABLE_LANGUAGE;
- mMostProbableDictionaryGroup = newMostProbableDictionaryGroup;
+ if (newMostProbableDictionaryGroup == mMostProbableDictionaryGroup) {
+ ++newMostProbableDictionaryGroup.mConfidence;
+ } else {
+ mMostProbableDictionaryGroup.mWeightForTypingInLocale =
+ DictionaryGroup.WEIGHT_FOR_TYPING_IN_NOT_MOST_PROBABLE_LANGUAGE;
+ mMostProbableDictionaryGroup.mWeightForGesturingInLocale =
+ DictionaryGroup.WEIGHT_FOR_GESTURING_IN_NOT_MOST_PROBABLE_LANGUAGE;
+ mMostProbableDictionaryGroup.mConfidence = 0;
+ newMostProbableDictionaryGroup.mWeightForTypingInLocale =
+ DictionaryGroup.WEIGHT_FOR_MOST_PROBABLE_LANGUAGE;
+ newMostProbableDictionaryGroup.mWeightForGesturingInLocale =
+ DictionaryGroup.WEIGHT_FOR_MOST_PROBABLE_LANGUAGE;
+ mMostProbableDictionaryGroup = newMostProbableDictionaryGroup;
+ }
+ }
+
+ public boolean isConfidentAboutCurrentLanguageBeing(final Locale mLocale) {
+ final DictionaryGroup mostProbableDictionaryGroup = mMostProbableDictionaryGroup;
+ if (!mostProbableDictionaryGroup.mLocale.equals(mLocale)) {
+ return false;
+ }
+ if (mDictionaryGroups.length <= 1) {
+ return true;
+ }
+ return mostProbableDictionaryGroup.mConfidence >= CONFIDENCE_THRESHOLD;
}
@Nullable
@@ -624,7 +648,8 @@ public class DictionaryFacilitator {
final int timeStampInSeconds, final boolean blockPotentiallyOffensive) {
final ExpandableBinaryDictionary userHistoryDictionary =
dictionaryGroup.getSubDict(Dictionary.TYPE_USER_HISTORY);
- if (userHistoryDictionary == null) {
+ if (userHistoryDictionary == null
+ || !isConfidentAboutCurrentLanguageBeing(userHistoryDictionary.mLocale)) {
return;
}
final int maxFreq = getFrequency(word);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 3459b426d..781ab06c5 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -19,10 +19,8 @@ package com.android.inputmethod.latin;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources;
import android.util.Log;
-import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
import java.io.File;
@@ -43,11 +41,10 @@ public final class DictionaryFactory {
* locale. If none is found, it falls back to the built-in dictionary - if any.
* @param context application context for reading resources
* @param locale the locale for which to create the dictionary
- * @param useFullEditDistance whether to use the full edit distance in suggestions
* @return an initialized instance of DictionaryCollection
*/
public static DictionaryCollection createMainDictionaryFromManager(final Context context,
- final Locale locale, final boolean useFullEditDistance) {
+ final Locale locale) {
if (null == locale) {
Log.e(TAG, "No locale defined for dictionary");
return new DictionaryCollection(Dictionary.TYPE_MAIN, locale,
@@ -61,7 +58,7 @@ public final class DictionaryFactory {
for (final AssetFileAddress f : assetFileList) {
final ReadOnlyBinaryDictionary readOnlyBinaryDictionary =
new ReadOnlyBinaryDictionary(f.mFilename, f.mOffset, f.mLength,
- useFullEditDistance, locale, Dictionary.TYPE_MAIN);
+ false /* useFullEditDistance */, locale, Dictionary.TYPE_MAIN);
if (readOnlyBinaryDictionary.isValidDictionary()) {
dictList.add(readOnlyBinaryDictionary);
} else {
@@ -101,49 +98,33 @@ public final class DictionaryFactory {
}
final String wordlistId =
DictionaryInfoUtils.getWordListIdFromFileName(new File(f.mFilename).getName());
- if (null != wordlistId) {
- // TODO: this is a reasonable last resort, but it is suboptimal.
- // The following will remove the entry for this dictionary with the dictionary
- // provider. When the metadata is downloaded again, we will try downloading it
- // again.
- // However, in the practice that will mean the user will find themselves without
- // the new dictionary. That's fine for languages where it's included in the APK,
- // but for other languages it will leave the user without a dictionary at all until
- // the next update, which may be a few days away.
- // Ideally, we would trigger a new download right away, and use increasing retry
- // delays for this particular id/version combination.
- // Then again, this is expected to only ever happen in case of human mistake. If
- // the wrong file is on the server, the following is still doing the right thing.
- // If it's a file left over from the last version however, it's not great.
- BinaryDictionaryFileDumper.reportBrokenFileToDictionaryProvider(
- providerClient,
- context.getString(R.string.dictionary_pack_client_id),
- wordlistId);
- }
+ // TODO: this is a reasonable last resort, but it is suboptimal.
+ // The following will remove the entry for this dictionary with the dictionary
+ // provider. When the metadata is downloaded again, we will try downloading it
+ // again.
+ // However, in the practice that will mean the user will find themselves without
+ // the new dictionary. That's fine for languages where it's included in the APK,
+ // but for other languages it will leave the user without a dictionary at all until
+ // the next update, which may be a few days away.
+ // Ideally, we would trigger a new download right away, and use increasing retry
+ // delays for this particular id/version combination.
+ // Then again, this is expected to only ever happen in case of human mistake. If
+ // the wrong file is on the server, the following is still doing the right thing.
+ // If it's a file left over from the last version however, it's not great.
+ BinaryDictionaryFileDumper.reportBrokenFileToDictionaryProvider(
+ providerClient,
+ context.getString(R.string.dictionary_pack_client_id),
+ wordlistId);
}
}
/**
- * Initializes a main dictionary collection from a dictionary pack, with default flags.
- *
- * This searches for a content provider providing a dictionary pack for the specified
- * locale. If none is found, it falls back to the built-in dictionary, if any.
- * @param context application context for reading resources
- * @param locale the locale for which to create the dictionary
- * @return an initialized instance of DictionaryCollection
- */
- public static DictionaryCollection createMainDictionaryFromManager(final Context context,
- final Locale locale) {
- return createMainDictionaryFromManager(context, locale, false /* useFullEditDistance */);
- }
-
- /**
* Initializes a read-only binary dictionary from a raw resource file
* @param context application context for reading resources
* @param locale the locale to use for the resource
* @return an initialized instance of ReadOnlyBinaryDictionary
*/
- protected static ReadOnlyBinaryDictionary createReadOnlyBinaryDictionary(final Context context,
+ private static ReadOnlyBinaryDictionary createReadOnlyBinaryDictionary(final Context context,
final Locale locale) {
AssetFileDescriptor afd = null;
try {
@@ -177,36 +158,4 @@ public final class DictionaryFactory {
}
}
}
-
- /**
- * Create a dictionary from passed data. This is intended for unit tests only.
- * @param dictionaryList the list of files to read, with their offsets and lengths
- * @param useFullEditDistance whether to use the full edit distance in suggestions
- * @return the created dictionary, or null.
- */
- @UsedForTesting
- public static Dictionary createDictionaryForTest(final AssetFileAddress[] dictionaryList,
- final boolean useFullEditDistance, Locale locale) {
- final DictionaryCollection dictionaryCollection =
- new DictionaryCollection(Dictionary.TYPE_MAIN, locale);
- for (final AssetFileAddress address : dictionaryList) {
- final ReadOnlyBinaryDictionary readOnlyBinaryDictionary = new ReadOnlyBinaryDictionary(
- address.mFilename, address.mOffset, address.mLength, useFullEditDistance,
- locale, Dictionary.TYPE_MAIN);
- dictionaryCollection.addDictionary(readOnlyBinaryDictionary);
- }
- return dictionaryCollection;
- }
-
- /**
- * Find out whether a dictionary is available for this locale.
- * @param context the context on which to check resources.
- * @param locale the locale to check for.
- * @return whether a (non-placeholder) dictionary is available or not.
- */
- public static boolean isDictionaryAvailable(Context context, Locale locale) {
- final Resources res = context.getResources();
- return 0 != DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
- res, locale);
- }
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 7b7b6d35e..bd660c5f3 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -100,6 +100,7 @@ import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.JniUtils;
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
+import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.StatsUtils;
import com.android.inputmethod.latin.utils.StatsUtilsManager;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -590,7 +591,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: Resolve mutual dependencies of {@link #loadSettings()} and
// {@link #resetDictionaryFacilitatorIfNecessary()}.
loadSettings();
- mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentRawSubtype());
resetDictionaryFacilitatorIfNecessary();
// Register to receive ringer mode change and network state change.
@@ -708,6 +708,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mInputLogic.mSuggest.setAutoCorrectionThreshold(
settingsValues.mAutoCorrectionThreshold);
}
+ mInputLogic.mSuggest.setPlausibilityThreshold(settingsValues.mPlausibilityThreshold);
}
/**
@@ -730,6 +731,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
unregisterReceiver(mDictionaryPackInstallReceiver);
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
mStatsUtilsManager.onDestroy();
+ DictionaryDecayBroadcastReciever.cancelIntervalAlarmForDictionaryDecaying(this);
super.onDestroy();
}
@@ -864,7 +866,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);
+ mRichImm.onSubtypeChanged(subtype);
+ mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentSubtype());
mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
mSettings.getCurrent());
loadKeyboard();
@@ -880,8 +883,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Switch to the null consumer to handle cases leading to early exit below, for which we
// also wouldn't be consuming gesture data.
mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER;
- mRichImm.clearSubtypeCaches();
- mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentRawSubtype());
+ mRichImm.refreshSubtypeCaches();
+ mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentSubtype());
final KeyboardSwitcher switcher = mKeyboardSwitcher;
switcher.updateKeyboardTheme();
final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView();
@@ -1007,6 +1010,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
suggest.setAutoCorrectionThreshold(
currentSettingsValues.mAutoCorrectionThreshold);
}
+ suggest.setPlausibilityThreshold(currentSettingsValues.mPlausibilityThreshold);
switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
@@ -1208,6 +1212,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
final SettingsValues settingsValues = mSettings.getCurrent();
+ final Resources res = getResources();
final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
if (visibleKeyboardView == null || !hasSuggestionStripView()) {
return;
@@ -1225,13 +1230,15 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int suggestionsHeight = (!mKeyboardSwitcher.isShowingEmojiPalettes()
&& mSuggestionStripView.getVisibility() == View.VISIBLE)
? mSuggestionStripView.getHeight() : 0;
- final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - suggestionsHeight;
+ final int visibleTopY = inputHeight
+ - ResourceUtils.getKeyboardFrameHeight(res, settingsValues)
+ - suggestionsHeight;
mSuggestionStripView.setMoreSuggestionsHeight(visibleTopY);
// 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;
- final int touchRight = visibleKeyboardView.getWidth();
+ final int touchRight = ResourceUtils.getKeyboardFrameWidth(res);
final int touchBottom = inputHeight
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
@@ -1446,7 +1453,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// completely replace #onCodeInput.
public void onEvent(@Nonnull final Event event) {
if (Constants.CODE_SHORTCUT == event.mKeyCode) {
- mRichImm.switchToShortcutIME(this);
+ mRichImm.switchToShortcutIme(this);
}
final InputTransaction completeInputTransaction =
mInputLogic.onCodeInput(mSettings.getCurrent(), event,
diff --git a/java/src/com/android/inputmethod/latin/NgramContext.java b/java/src/com/android/inputmethod/latin/NgramContext.java
index 82a13274d..b47731229 100644
--- a/java/src/com/android/inputmethod/latin/NgramContext.java
+++ b/java/src/com/android/inputmethod/latin/NgramContext.java
@@ -133,7 +133,7 @@ public class NgramContext {
// n is 1-indexed.
@UsedForTesting
- public boolean isNthPrevWordBeginningOfSontence(final int n) {
+ public boolean isNthPrevWordBeginningOfSentence(final int n) {
if (n <= 0 || n > mPrevWordsCount) {
return false;
}
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index a1ac55a20..462121789 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -110,8 +110,12 @@ public class RichInputMethodManager {
// Initialize additional subtypes.
SubtypeLocaleUtils.init(context);
- final InputMethodSubtype[] additionalSubtypes = getAdditionalSubtypes(context);
- setAdditionalInputMethodSubtypes(additionalSubtypes);
+ final InputMethodSubtype[] additionalSubtypes = getAdditionalSubtypes();
+ mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
+ getInputMethodIdOfThisIme(), additionalSubtypes);
+
+ // Initialize the current input method subtype and the shortcut IME.
+ refreshSubtypeCaches();
final ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -119,11 +123,10 @@ public class RichInputMethodManager {
mIsNetworkConnected = (info != null && info.isConnected());
}
- public InputMethodSubtype[] getAdditionalSubtypes(final Context context) {
- SubtypeLocaleUtils.init(context);
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ public InputMethodSubtype[] getAdditionalSubtypes() {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(
- prefs, context.getResources());
+ prefs, mContext.getResources());
return AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefAdditionalSubtypes);
}
@@ -325,23 +328,22 @@ public class RichInputMethodManager {
return INDEX_NOT_FOUND;
}
- @Nonnull
- public RichInputMethodSubtype onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) {
- final RichInputMethodSubtype richSubtype = createCurrentRichInputMethodSubtype(newSubtype);
+ public void onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) {
+ updateCurrentSubtype(newSubtype);
+ updateShortcutIme();
if (DEBUG) {
- Log.w(TAG, "onSubtypeChanged: " + richSubtype.getNameForLogging());
+ Log.w(TAG, "onSubtypeChanged: " + mCurrentRichInputMethodSubtype.getNameForLogging());
}
- mCurrentRichInputMethodSubtype = richSubtype;
- return richSubtype;
}
private static RichInputMethodSubtype sForcedSubtypeForTesting = null;
@UsedForTesting
- static void forceSubtype(final InputMethodSubtype subtype) {
+ static void forceSubtype(@Nonnull final InputMethodSubtype subtype) {
sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype);
}
+ @Nonnull
public Locale[] getCurrentSubtypeLocales() {
if (null != sForcedSubtypeForTesting) {
return sForcedSubtypeForTesting.getLocales();
@@ -349,6 +351,7 @@ public class RichInputMethodManager {
return getCurrentSubtype().getLocales();
}
+ @Nonnull
public RichInputMethodSubtype getCurrentSubtype() {
if (null != sForcedSubtypeForTesting) {
return sForcedSubtypeForTesting;
@@ -361,18 +364,6 @@ public class RichInputMethodManager {
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,
- mContext);
- }
-
public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList();
return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
@@ -458,7 +449,7 @@ public class RichInputMethodManager {
getInputMethodIdOfThisIme(), subtypes);
// Clear the cache so that we go read the {@link InputMethodInfo} of this IME and list of
// subtypes again next time.
- clearSubtypeCaches();
+ refreshSubtypeCaches();
}
private List<InputMethodSubtype> getEnabledInputMethodSubtypeList(final InputMethodInfo imi,
@@ -475,10 +466,12 @@ public class RichInputMethodManager {
return result;
}
- public void clearSubtypeCaches() {
+ public void refreshSubtypeCaches() {
mSubtypeListCacheWithImplicitlySelectedSubtypes.clear();
mSubtypeListCacheWithoutImplicitlySelectedSubtypes.clear();
mInputMethodInfoCache.clear();
+ updateCurrentSubtype(mImmWrapper.mImm.getCurrentInputMethodSubtype());
+ updateShortcutIme();
}
public boolean shouldOfferSwitchingToNextInputMethod(final IBinder binder,
@@ -517,8 +510,13 @@ public class RichInputMethodManager {
return true;
}
- // TODO: Make this private
- void updateShortcutIME() {
+ private void updateCurrentSubtype(@Nonnull final InputMethodSubtype subtype) {
+ final RichInputMethodSubtype richSubtype = AdditionalFeaturesSettingUtils
+ .createRichInputMethodSubtype(this, subtype, mContext);
+ mCurrentRichInputMethodSubtype = richSubtype;
+ }
+
+ private void updateShortcutIme() {
if (DEBUG) {
Log.d(TAG, "Update shortcut IME from : "
+ (mShortcutInputMethodInfo == null
@@ -550,7 +548,7 @@ public class RichInputMethodManager {
}
}
- public void switchToShortcutIME(final InputMethodService context) {
+ public void switchToShortcutIme(final InputMethodService context) {
if (mShortcutInputMethodInfo == null) {
return;
}
@@ -576,19 +574,16 @@ public class RichInputMethodManager {
}
public boolean isShortcutImeEnabled() {
- updateShortcutIME();
if (mShortcutInputMethodInfo == null) {
return false;
}
if (mShortcutSubtype == null) {
return true;
}
- return checkIfSubtypeBelongsToImeAndEnabled(
- mShortcutInputMethodInfo, mShortcutSubtype);
+ return checkIfSubtypeBelongsToImeAndEnabled(mShortcutInputMethodInfo, mShortcutSubtype);
}
public boolean isShortcutImeReady() {
- updateShortcutIME();
if (mShortcutInputMethodInfo == null) {
return false;
}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 23e348bff..92ba6c2d9 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -57,7 +57,7 @@ public final class SubtypeSwitcher {
mResources = context.getResources();
mRichImm = RichInputMethodManager.getInstance();
- onSubtypeChanged(mRichImm.getCurrentRawSubtype());
+ onSubtypeChanged(mRichImm.getCurrentSubtype());
updateParametersOnStartInputView();
}
@@ -69,17 +69,14 @@ public final class SubtypeSwitcher {
final List<InputMethodSubtype> enabledSubtypesOfThisIme =
mRichImm.getMyEnabledInputMethodSubtypeList(true);
mLanguageOnSpacebarHelper.onUpdateEnabledSubtypes(enabledSubtypesOfThisIme);
- mRichImm.updateShortcutIME();
}
// Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
- public void onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) {
- final RichInputMethodSubtype richSubtype = mRichImm.onSubtypeChanged(newSubtype);
+ public void onSubtypeChanged(@Nonnull final RichInputMethodSubtype richSubtype) {
final boolean implicitlyEnabledSubtype = mRichImm
- .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype);
+ .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(richSubtype.getRawSubtype());
mLanguageOnSpacebarHelper.onSubtypeChanged(
richSubtype, implicitlyEnabledSubtype, mResources.getConfiguration().locale);
- mRichImm.updateShortcutIME();
}
public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) {
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 2d0ec42a6..0bf0f687a 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
@@ -64,15 +65,30 @@ public final class Suggest {
}
private float mAutoCorrectionThreshold;
+ private float mPlausibilityThreshold;
public Suggest(final DictionaryFacilitator dictionaryFacilitator) {
mDictionaryFacilitator = dictionaryFacilitator;
}
+ /**
+ * Set the normalized-score threshold for a suggestion to be considered strong enough that we
+ * will auto-correct to this.
+ * @param threshold the threshold
+ */
public void setAutoCorrectionThreshold(final float threshold) {
mAutoCorrectionThreshold = threshold;
}
+ /**
+ * Set the normalized-score threshold for what we consider a "plausible" suggestion, in
+ * the same dimension as the auto-correction threshold.
+ * @param threshold the threshold
+ */
+ public void setPlausibilityThreshold(final float threshold) {
+ mPlausibilityThreshold = threshold;
+ }
+
public interface OnGetSuggestedWordsCallback {
public void onGetSuggestedWords(final SuggestedWords suggestedWords);
}
@@ -117,7 +133,8 @@ public final class Suggest {
return suggestionsContainer;
}
- private static String getWhitelistedWordOrNull(final ArrayList<SuggestedWordInfo> suggestions) {
+ private static SuggestedWordInfo getWhitelistedWordInfoOrNull(
+ @Nonnull final ArrayList<SuggestedWordInfo> suggestions) {
if (suggestions.isEmpty()) {
return null;
}
@@ -125,9 +142,21 @@ public final class Suggest {
if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
return null;
}
- return firstSuggestedWordInfo.mWord;
+ return firstSuggestedWordInfo;
}
+ // Quality constants for dictionary match
+ // In increasing order of quality
+ // This source dictionary does not match the typed word.
+ private static final int QUALITY_NO_MATCH = 0;
+ // This source dictionary has a null locale, and the preferred locale is also null.
+ private static final int QUALITY_MATCH_NULL = 1;
+ // This source dictionary has a non-null locale different from the preferred locale. The
+ // preferred locale may be null : this is still better than MATCH_NULL.
+ private static final int QUALITY_MATCH_OTHER_LOCALE = 2;
+ // This source dictionary matches the preferred locale.
+ private static final int QUALITY_MATCH_PREFERRED_LOCALE = 3;
+
// Retrieves suggestions for non-batch input (typing, recorrection, predictions...)
// and calls the callback function with the suggestions.
private void getSuggestedWordsForNonBatchInput(final WordComposer wordComposer,
@@ -152,11 +181,54 @@ public final class Suggest {
// For transforming suggestions that don't come for any dictionary, we
// use the currently most probable locale as it's our best bet.
mostProbableLocale);
- @Nullable final Dictionary sourceDictionaryOfRemovedWord =
- SuggestedWordInfo.removeDupsAndReturnSourceOfTypedWord(wordComposer.getTypedWord(),
- mostProbableLocale /* preferredLocale */, suggestionsContainer);
- final String whitelistedWord = getWhitelistedWordOrNull(suggestionsContainer);
+ boolean typedWordExistsInAnotherLanguage = false;
+ int qualityOfFoundSourceDictionary = QUALITY_NO_MATCH;
+ @Nullable Dictionary sourceDictionaryOfRemovedWord = null;
+ for (final SuggestedWordInfo info : suggestionsContainer) {
+ // Search for the best dictionary, defined as the first one with the highest match
+ // quality we can find.
+ if (typedWordString.equals(info.mWord)) {
+ if (mostProbableLocale.equals(info.mSourceDict.mLocale)) {
+ if (qualityOfFoundSourceDictionary < QUALITY_MATCH_PREFERRED_LOCALE) {
+ // Use this source if the old match had lower quality than this match
+ sourceDictionaryOfRemovedWord = info.mSourceDict;
+ qualityOfFoundSourceDictionary = QUALITY_MATCH_PREFERRED_LOCALE;
+ }
+ } else {
+ final int matchQuality = (null == info.mSourceDict.mLocale)
+ ? QUALITY_MATCH_NULL : QUALITY_MATCH_OTHER_LOCALE;
+ if (qualityOfFoundSourceDictionary < matchQuality) {
+ // Use this source if the old match had lower quality than this match
+ sourceDictionaryOfRemovedWord = info.mSourceDict;
+ qualityOfFoundSourceDictionary = matchQuality;
+ }
+ typedWordExistsInAnotherLanguage = true;
+ }
+ }
+ }
+
+ SuggestedWordInfo.removeDups(typedWordString, suggestionsContainer);
+
+ final SuggestedWordInfo whitelistedWordInfo =
+ getWhitelistedWordInfoOrNull(suggestionsContainer);
+ final String whitelistedWord;
+ if (null != whitelistedWordInfo &&
+ (mDictionaryFacilitator.isConfidentAboutCurrentLanguageBeing(
+ whitelistedWordInfo.mSourceDict.mLocale)
+ || (!typedWordExistsInAnotherLanguage
+ && !hasPlausibleCandidateInAnyOtherLanguage(suggestionsContainer,
+ consideredWord, whitelistedWordInfo)))) {
+ // We'll use the whitelist candidate if we are confident the user is typing in the
+ // language of the dictionary it's coming from, or if there is no plausible candidate
+ // coming from another language.
+ whitelistedWord = whitelistedWordInfo.mWord;
+ } else {
+ // If on the contrary we are not confident in the current language and we have
+ // at least a plausible candidate in any other language, then we don't use this
+ // whitelist candidate.
+ whitelistedWord = null;
+ }
final boolean resultsArePredictions = !wordComposer.isComposingWord();
// We allow auto-correction if we have a whitelisted word, or if the word had more than
@@ -198,7 +270,7 @@ public final class Suggest {
hasAutoCorrection = false;
} else {
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
- if (!AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold(
+ if (!AutoCorrectionUtils.suggestionExceedsThreshold(
firstSuggestion, consideredWord, mAutoCorrectionThreshold)) {
// Score is too low for autocorrect
hasAutoCorrection = false;
@@ -247,6 +319,20 @@ public final class Suggest {
false /* isObsoleteSuggestions */, inputStyle, sequenceNumber));
}
+ private boolean hasPlausibleCandidateInAnyOtherLanguage(
+ final ArrayList<SuggestedWordInfo> suggestionsContainer, final String consideredWord,
+ final SuggestedWordInfo whitelistedWordInfo) {
+ for (final SuggestedWordInfo info : suggestionsContainer) {
+ if (whitelistedWordInfo.mSourceDict.mLocale.equals(info.mSourceDict.mLocale)) {
+ continue;
+ }
+ return AutoCorrectionUtils.suggestionExceedsThreshold(info, consideredWord,
+ mPlausibilityThreshold);
+ }
+ // No candidate in another language
+ return false;
+ }
+
// Retrieves suggestions for the batch input
// and calls the callback function with the suggestions.
private void getSuggestedWordsForBatchInput(final WordComposer wordComposer,
@@ -280,8 +366,7 @@ public final class Suggest {
final SuggestedWordInfo rejected = suggestionsContainer.remove(0);
suggestionsContainer.add(1, rejected);
}
- SuggestedWordInfo.removeDupsAndReturnSourceOfTypedWord(null /* typedWord */,
- null /* preferredLocale */, suggestionsContainer);
+ SuggestedWordInfo.removeDups(null /* typedWord */, suggestionsContainer);
// For some reason some suggestions with MIN_VALUE are making their way here.
// TODO: Find a more robust way to detect distracters.
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index cbf48f0c0..30dd51aed 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -27,7 +27,6 @@ import com.android.inputmethod.latin.define.DebugFlags;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
-import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -356,53 +355,30 @@ public class SuggestedWords {
}
// This will always remove the higher index if a duplicate is found.
- // Returns null if the typed word is not found. Always return the dictionary for the
- // highest suggestion matching the locale if found, otherwise return the dictionary for
- // the highest suggestion.
- @Nullable
- public static Dictionary removeDupsAndReturnSourceOfTypedWord(
- @Nullable final String typedWord,
- @Nullable final Locale preferredLocale,
+ public static void removeDups(@Nullable final String typedWord,
@Nonnull ArrayList<SuggestedWordInfo> candidates) {
if (candidates.isEmpty()) {
- return null;
+ return;
}
- final Dictionary sourceDictionaryOfTypedWord;
if (!TextUtils.isEmpty(typedWord)) {
- sourceDictionaryOfTypedWord =
- removeSuggestedWordInfoFromListAndReturnSourceDictionary(typedWord,
- preferredLocale, candidates, -1 /* startIndexExclusive */);
- } else {
- sourceDictionaryOfTypedWord = null;
+ removeSuggestedWordInfoFromList(typedWord, candidates, -1 /* startIndexExclusive */);
}
for (int i = 0; i < candidates.size(); ++i) {
- removeSuggestedWordInfoFromListAndReturnSourceDictionary(candidates.get(i).mWord,
- null /* preferredLocale */, candidates, i /* startIndexExclusive */);
+ removeSuggestedWordInfoFromList(candidates.get(i).mWord, candidates,
+ i /* startIndexExclusive */);
}
- return sourceDictionaryOfTypedWord;
}
- @Nullable
- private static Dictionary removeSuggestedWordInfoFromListAndReturnSourceDictionary(
- @Nonnull final String word, @Nullable final Locale preferredLocale,
- @Nonnull final ArrayList<SuggestedWordInfo> candidates,
+ private static void removeSuggestedWordInfoFromList(
+ @Nonnull final String word, @Nonnull final ArrayList<SuggestedWordInfo> candidates,
final int startIndexExclusive) {
- Dictionary sourceDictionaryOfTypedWord = null;
for (int i = startIndexExclusive + 1; i < candidates.size(); ++i) {
final SuggestedWordInfo previous = candidates.get(i);
if (word.equals(previous.mWord)) {
- if (null == sourceDictionaryOfTypedWord
- || (null != preferredLocale
- && preferredLocale.equals(previous.mSourceDict.mLocale))) {
- if (Dictionary.TYPE_USER_HISTORY != previous.mSourceDict.mDictType) {
- sourceDictionaryOfTypedWord = previous.mSourceDict;
- }
- }
candidates.remove(i);
--i;
}
}
- return sourceDictionaryOfTypedWord;
}
}
diff --git a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
index 123ab208c..982d4c690 100644
--- a/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
+++ b/java/src/com/android/inputmethod/latin/SystemBroadcastReceiver.java
@@ -69,7 +69,7 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver {
// subtypes when the package is replaced.
RichInputMethodManager.init(context);
final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
- final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes(context);
+ final InputMethodSubtype[] additionalSubtypes = richImm.getAdditionalSubtypes();
richImm.setAdditionalInputMethodSubtypes(additionalSubtypes);
LauncherIconVisibilityManager.updateSetupWizardIconVisibility(context);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(intentAction)) {
diff --git a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
index 78bfd2b52..8cc3552ed 100644
--- a/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
+++ b/java/src/com/android/inputmethod/latin/debug/ExternalDictionaryGetterForDebug.java
@@ -101,12 +101,12 @@ public class ExternalDictionaryGetterForDebug {
final File file = new File(dirPath, fileName.toString());
final DictionaryHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file);
final StringBuilder message = new StringBuilder();
- final String locale = header.getLocaleString();
- for (String key : header.mDictionaryOptions.mAttributes.keySet()) {
+ final String localeString = header.mLocaleString;
+ for (final String key : header.mDictionaryOptions.mAttributes.keySet()) {
message.append(key + " = " + header.mDictionaryOptions.mAttributes.get(key));
message.append("\n");
}
- final String languageName = LocaleUtils.constructLocaleFromString(locale)
+ final String languageName = LocaleUtils.constructLocaleFromString(localeString)
.getDisplayName(Locale.getDefault());
final String title = String.format(
context.getString(R.string.read_external_dictionary_confirm_install_message),
@@ -146,11 +146,12 @@ public class ExternalDictionaryGetterForDebug {
BufferedOutputStream outputStream = null;
File tempFile = null;
try {
- final String locale = header.getLocaleString();
+ final String localeString = header.mLocaleString;
// Create the id for a main dictionary for this locale
final String id = BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY
- + BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale;
- final String finalFileName = DictionaryInfoUtils.getCacheFileName(id, locale, context);
+ + BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + localeString;
+ final String finalFileName = DictionaryInfoUtils.getCacheFileName(
+ id, localeString, context);
final String tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
tempFile = new File(tempFileName);
tempFile.delete();
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java
index 644818ba6..4d253b0cb 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java
@@ -19,13 +19,24 @@ package com.android.inputmethod.latin.makedict;
import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* Class representing dictionary header.
*/
public final class DictionaryHeader {
public final int mBodyOffset;
+ @Nonnull
public final DictionaryOptions mDictionaryOptions;
+ @Nonnull
public final FormatOptions mFormatOptions;
+ @Nonnull
+ public final String mLocaleString;
+ @Nonnull
+ public final String mVersionString;
+ @Nonnull
+ public final String mIdString;
// Note that these are corresponding definitions in native code in latinime::HeaderPolicy
// and latinime::HeaderReadWriteUtils.
@@ -46,39 +57,32 @@ public final class DictionaryHeader {
public static final String ATTRIBUTE_VALUE_TRUE = "1";
public static final String CODE_POINT_TABLE_KEY = "codePointTable";
- public DictionaryHeader(final int headerSize, final DictionaryOptions dictionaryOptions,
- final FormatOptions formatOptions) throws UnsupportedFormatException {
+ public DictionaryHeader(final int headerSize,
+ @Nonnull final DictionaryOptions dictionaryOptions,
+ @Nonnull final FormatOptions formatOptions) throws UnsupportedFormatException {
mDictionaryOptions = dictionaryOptions;
mFormatOptions = formatOptions;
mBodyOffset = formatOptions.mVersion < FormatSpec.VERSION4 ? headerSize : 0;
- if (null == getLocaleString()) {
+ final String localeString = dictionaryOptions.mAttributes.get(DICTIONARY_LOCALE_KEY);
+ if (null == localeString) {
throw new UnsupportedFormatException("Cannot create a FileHeader without a locale");
}
- if (null == getVersion()) {
+ final String versionString = dictionaryOptions.mAttributes.get(DICTIONARY_VERSION_KEY);
+ if (null == versionString) {
throw new UnsupportedFormatException(
"Cannot create a FileHeader without a version");
}
- if (null == getId()) {
+ final String idString = dictionaryOptions.mAttributes.get(DICTIONARY_ID_KEY);
+ if (null == idString) {
throw new UnsupportedFormatException("Cannot create a FileHeader without an ID");
}
- }
-
- // Helper method to get the locale as a String
- public String getLocaleString() {
- return mDictionaryOptions.mAttributes.get(DICTIONARY_LOCALE_KEY);
- }
-
- // Helper method to get the version String
- public String getVersion() {
- return mDictionaryOptions.mAttributes.get(DICTIONARY_VERSION_KEY);
- }
-
- // Helper method to get the dictionary ID as a String
- public String getId() {
- return mDictionaryOptions.mAttributes.get(DICTIONARY_ID_KEY);
+ mLocaleString = localeString;
+ mVersionString = versionString;
+ mIdString = idString;
}
// Helper method to get the description
+ @Nullable
public String getDescription() {
// TODO: Right now each dictionary file comes with a description in its own language.
// It will display as is no matter the device's locale. It should be internationalized.
diff --git a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java
index 221bb9a8f..e974f3320 100644
--- a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java
+++ b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java
@@ -43,17 +43,40 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver {
/**
* Interval to update for decaying dictionaries.
*/
- /* package */ static final long DICTIONARY_DECAY_INTERVAL = TimeUnit.MINUTES.toMillis(60);
+ static final long DICTIONARY_DECAY_INTERVAL_IN_MILLIS = TimeUnit.MINUTES.toMillis(60);
- public static void setUpIntervalAlarmForDictionaryDecaying(Context context) {
- AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+ private static PendingIntent getPendingIntentForDictionaryDecay(final Context context) {
final Intent updateIntent = new Intent(DICTIONARY_DECAY_INTENT_ACTION);
updateIntent.setClass(context, DictionaryDecayBroadcastReciever.class);
- final long alarmTime = System.currentTimeMillis() + DICTIONARY_DECAY_INTERVAL;
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0 /* requestCode */,
+ return PendingIntent.getBroadcast(context, 0 /* requestCode */,
updateIntent, PendingIntent.FLAG_CANCEL_CURRENT);
- if (null != alarmManager) alarmManager.setInexactRepeating(AlarmManager.RTC,
- alarmTime, DICTIONARY_DECAY_INTERVAL, pendingIntent);
+ }
+
+ /**
+ * Set up interval alarm for dynamic dictionaries.
+ */
+ public static void setUpIntervalAlarmForDictionaryDecaying(final Context context) {
+ final AlarmManager alarmManager =
+ (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+ if (null == alarmManager) {
+ return;
+ }
+ final long alarmTriggerTimeInMillis =
+ System.currentTimeMillis() + DICTIONARY_DECAY_INTERVAL_IN_MILLIS;
+ alarmManager.setInexactRepeating(AlarmManager.RTC, alarmTriggerTimeInMillis,
+ DICTIONARY_DECAY_INTERVAL_IN_MILLIS, getPendingIntentForDictionaryDecay(context));
+ }
+
+ /**
+ * Cancel interval alarm that has been set up.
+ */
+ public static void cancelIntervalAlarmForDictionaryDecaying(final Context context) {
+ final AlarmManager alarmManager =
+ (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
+ if (null == alarmManager) {
+ return;
+ }
+ alarmManager.cancel(getPendingIntentForDictionaryDecay(context));
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
index cefb0ddd5..b595f3974 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -73,7 +73,7 @@ public class PersonalizationHelper {
private static int sCurrentTimestampForTesting = 0;
public static void currentTimeChangedForTesting(final int currentTimestamp) {
if (TimeUnit.MILLISECONDS.toSeconds(
- DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL)
+ DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL_IN_MILLIS)
< currentTimestamp - sCurrentTimestampForTesting) {
runGCOnAllOpenedUserHistoryDictionaries();
runGCOnAllOpenedPersonalizationDictionaries();
diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java
index b749aa51a..21ea8f859 100644
--- a/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java
+++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java
@@ -196,16 +196,6 @@ final class CustomInputStylePreference extends DialogPreference
}
}
- private static int getSpinnerPosition(final Spinner spinner) {
- if (spinner == null) return -1;
- return spinner.getSelectedItemPosition();
- }
-
- private static void setSpinnerPosition(final Spinner spinner, final int position) {
- if (spinner == null || position < 0) return;
- spinner.setSelection(position);
- }
-
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
@@ -216,8 +206,6 @@ final class CustomInputStylePreference extends DialogPreference
final SavedState myState = new SavedState(superState);
myState.mSubtype = mSubtype;
- myState.mSubtypeLocaleSelectedPos = getSpinnerPosition(mSubtypeLocaleSpinner);
- myState.mKeyboardLayoutSetSelectedPos = getSpinnerPosition(mKeyboardLayoutSetSpinner);
return myState;
}
@@ -230,15 +218,11 @@ final class CustomInputStylePreference extends DialogPreference
final SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
- setSpinnerPosition(mSubtypeLocaleSpinner, myState.mSubtypeLocaleSelectedPos);
- setSpinnerPosition(mKeyboardLayoutSetSpinner, myState.mKeyboardLayoutSetSelectedPos);
setSubtype(myState.mSubtype);
}
static final class SavedState extends Preference.BaseSavedState {
InputMethodSubtype mSubtype;
- int mSubtypeLocaleSelectedPos;
- int mKeyboardLayoutSetSelectedPos;
public SavedState(final Parcelable superState) {
super(superState);
@@ -247,15 +231,11 @@ final class CustomInputStylePreference extends DialogPreference
@Override
public void writeToParcel(final Parcel dest, final int flags) {
super.writeToParcel(dest, flags);
- dest.writeInt(mSubtypeLocaleSelectedPos);
- dest.writeInt(mKeyboardLayoutSetSelectedPos);
dest.writeParcelable(mSubtype, 0);
}
public SavedState(final Parcel source) {
super(source);
- mSubtypeLocaleSelectedPos = source.readInt();
- mKeyboardLayoutSetSelectedPos = source.readInt();
mSubtype = (InputMethodSubtype)source.readParcelable(null);
}
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index 6fffb8e9d..eff7bde5d 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -31,6 +31,9 @@ public final class DebugSettings {
"pref_has_custom_key_preview_animation_params";
public static final String PREF_RESIZE_KEYBOARD = "pref_resize_keyboard";
public static final String PREF_KEYBOARD_HEIGHT_SCALE = "pref_keyboard_height_scale";
+ public static final String PREF_KEYBOARD_BOTTOM_MARGIN = "pref_keyboard_bottom_margin";
+ public static final String PREF_KEYBOARD_LEFT_MARGIN = "pref_keyboard_left_margin";
+ public static final String PREF_KEYBOARD_RIGHT_MARGIN = "pref_keyboard_right_margin";
public static final String PREF_KEY_PREVIEW_DISMISS_DURATION =
"pref_key_preview_dismiss_duration";
public static final String PREF_KEY_PREVIEW_DISMISS_END_X_SCALE =
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
index 068f56df1..779bf47c9 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
@@ -89,8 +89,14 @@ public final class DebugSettingsFragment extends SubScreenFragment
defaultKeyPreviewDismissEndScale);
setupKeyPreviewAnimationScale(DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
defaultKeyPreviewDismissEndScale);
- setupKeyboardHeight(
+ setupKeyboardScale(
DebugSettings.PREF_KEYBOARD_HEIGHT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE);
+ setupKeyboardScale(
+ DebugSettings.PREF_KEYBOARD_BOTTOM_MARGIN, SettingsValues.DEFAULT_MARGIN_SCALE);
+ setupKeyboardScale(
+ DebugSettings.PREF_KEYBOARD_LEFT_MARGIN, SettingsValues.DEFAULT_MARGIN_SCALE);
+ setupKeyboardScale(
+ DebugSettings.PREF_KEYBOARD_RIGHT_MARGIN, SettingsValues.DEFAULT_MARGIN_SCALE);
mServiceNeedsRestart = false;
mDebugMode = (TwoStatePreference) findPreference(DebugSettings.PREF_DEBUG_MODE);
@@ -253,7 +259,7 @@ public final class DebugSettingsFragment extends SubScreenFragment
});
}
- private void setupKeyboardHeight(final String prefKey, final float defaultValue) {
+ private void setupKeyboardScale(final String prefKey, final float defaultValue) {
final SharedPreferences prefs = getSharedPreferences();
final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(prefKey);
if (pref == null) {
@@ -282,7 +288,7 @@ public final class DebugSettingsFragment extends SubScreenFragment
@Override
public int readValue(final String key) {
return getPercentageFromValue(
- Settings.readKeyboardHeight(prefs, key, defaultValue));
+ Settings.readKeyboardScale(prefs, key, defaultValue));
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java
index c0ceb8857..975396d2d 100644
--- a/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/PreferencesSettingsFragment.java
@@ -71,6 +71,7 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
super.onResume();
final Preference voiceInputKeyOption = findPreference(Settings.PREF_VOICE_INPUT_KEY);
if (voiceInputKeyOption != null) {
+ RichInputMethodManager.getInstance().refreshSubtypeCaches();
final boolean isShortcutImeEnabled = RichInputMethodManager.getInstance()
.isShortcutImeEnabled();
voiceInputKeyOption.setEnabled(isShortcutImeEnabled);
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 16c053474..196fef4cd 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -238,6 +238,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
}
+ public static float readPlausibilityThreshold(final Resources res) {
+ return Float.parseFloat(res.getString(R.string.plausibility_threshold));
+ }
+
public static boolean readBlockPotentiallyOffensive(final SharedPreferences prefs,
final Resources res) {
return prefs.getBoolean(PREF_BLOCK_POTENTIALLY_OFFENSIVE,
@@ -363,7 +367,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds : defaultValue;
}
- public static float readKeyboardHeight(final SharedPreferences prefs,
+ public static float readKeyboardScale(final SharedPreferences prefs,
final String prefKey, final float defaultValue) {
final float percentage = prefs.getFloat(prefKey, UNDEFINED_PREFERENCE_VALUE_FLOAT);
return (percentage != UNDEFINED_PREFERENCE_VALUE_FLOAT) ? percentage : defaultValue;
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 26415e7d4..99e0565ca 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -50,6 +50,7 @@ public class SettingsValues {
private static final String FLOAT_NEGATIVE_INFINITY_MARKER_STRING = "floatNegativeInfinity";
private static final int TIMEOUT_TO_GET_TARGET_PACKAGE = 5; // seconds
public static final float DEFAULT_SIZE_SCALE = 1.0f; // 100%
+ public static final float DEFAULT_MARGIN_SCALE = 0.0f; // 0%
// From resources:
public final SpacingAndPunctuations mSpacingAndPunctuations;
@@ -96,6 +97,7 @@ public class SettingsValues {
public final int mKeyPreviewPopupDismissDelay;
private final boolean mAutoCorrectEnabled;
public final float mAutoCorrectionThreshold;
+ public final float mPlausibilityThreshold;
public final boolean mAutoCorrectionEnabledPerUserSettings;
private final boolean mSuggestionsEnabledPerUserSettings;
private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds;
@@ -112,6 +114,9 @@ public class SettingsValues {
public final boolean mHasCustomKeyPreviewAnimationParams;
public final boolean mHasKeyboardResize;
public final float mKeyboardHeightScale;
+ public final float mKeyboardBottomMarginScale;
+ public final float mKeyboardLeftMarginScale;
+ public final float mKeyboardRightMarginScale;
public final int mKeyPreviewShowUpDuration;
public final int mKeyPreviewDismissDuration;
public final float mKeyPreviewShowUpStartXScale;
@@ -172,6 +177,7 @@ public class SettingsValues {
Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY, true);
mAutoCorrectionThreshold = readAutoCorrectionThreshold(res,
autoCorrectionThresholdRawValue);
+ mPlausibilityThreshold = Settings.readPlausibilityThreshold(res);
mGestureInputEnabled = Settings.readGestureInputEnabled(prefs, res);
mGestureTrailEnabled = prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true);
mGestureFloatingPreviewTextEnabled = !mInputAttributes.mDisableGestureFloatingPreviewText
@@ -188,8 +194,14 @@ public class SettingsValues {
mHasCustomKeyPreviewAnimationParams = prefs.getBoolean(
DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, false);
mHasKeyboardResize = prefs.getBoolean(DebugSettings.PREF_RESIZE_KEYBOARD, false);
- mKeyboardHeightScale = Settings.readKeyboardHeight(
+ mKeyboardHeightScale = Settings.readKeyboardScale(
prefs, DebugSettings.PREF_KEYBOARD_HEIGHT_SCALE, DEFAULT_SIZE_SCALE);
+ mKeyboardBottomMarginScale = Settings.readKeyboardScale(
+ prefs, DebugSettings.PREF_KEYBOARD_BOTTOM_MARGIN, DEFAULT_MARGIN_SCALE);
+ mKeyboardLeftMarginScale = Settings.readKeyboardScale(
+ prefs, DebugSettings.PREF_KEYBOARD_LEFT_MARGIN, DEFAULT_MARGIN_SCALE);
+ mKeyboardRightMarginScale = Settings.readKeyboardScale(
+ prefs, DebugSettings.PREF_KEYBOARD_RIGHT_MARGIN, DEFAULT_MARGIN_SCALE);
mKeyPreviewShowUpDuration = Settings.readKeyPreviewAnimationDuration(
prefs, DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION,
res.getInteger(R.integer.config_key_preview_show_up_duration));
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index c90e8a3cf..4b8d2a3f9 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -115,7 +115,8 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
@Override
public void onCreate() {
final String localeString = getLocale();
- mLocale = LocaleUtils.constructLocaleFromString(localeString);
+ mLocale = (null == localeString) ? null
+ : LocaleUtils.constructLocaleFromString(localeString);
mScript = ScriptUtils.getScriptFromSpellCheckerLocale(mLocale);
}
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java
index 22fc35a42..69029c51e 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java
@@ -34,6 +34,8 @@ import java.util.ArrayList;
import java.util.Locale;
import java.util.TreeSet;
+import javax.annotation.Nullable;
+
// Caveat: This class is basically taken from
// packages/apps/Settings/src/com/android/settings/inputmethod/UserDictionaryAddWordContents.java
// in order to deal with some devices that have issues with the user dictionary handling
@@ -218,8 +220,8 @@ public class UserDictionaryAddWordContents {
public static class LocaleRenderer {
private final String mLocaleString;
private final String mDescription;
- // LocaleString may NOT be null.
- public LocaleRenderer(final Context context, final String localeString) {
+
+ public LocaleRenderer(final Context context, @Nullable final String localeString) {
mLocaleString = localeString;
if (null == localeString) {
mDescription = context.getString(R.string.user_dict_settings_more_languages);
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java
index b9ed35375..6254b54ff 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java
@@ -37,6 +37,8 @@ import java.util.List;
import java.util.Locale;
import java.util.TreeSet;
+import javax.annotation.Nullable;
+
// Caveat: This class is basically taken from
// packages/apps/Settings/src/com/android/settings/inputmethod/UserDictionaryList.java
// in order to deal with some devices that have issues with the user dictionary handling
@@ -131,21 +133,23 @@ public class UserDictionaryList extends PreferenceFragment {
/**
* Create a single User Dictionary Preference object, with its parameters set.
- * @param locale The locale for which this user dictionary is for.
+ * @param localeString The locale for which this user dictionary is for.
* @return The corresponding preference.
*/
- protected Preference createUserDictionaryPreference(final String locale) {
+ protected Preference createUserDictionaryPreference(@Nullable final String localeString) {
final Preference newPref = new Preference(getActivity());
final Intent intent = new Intent(USER_DICTIONARY_SETTINGS_INTENT_ACTION);
- if (null == locale) {
+ if (null == localeString) {
newPref.setTitle(Locale.getDefault().getDisplayName());
} else {
- if ("".equals(locale))
+ if (localeString.isEmpty()) {
newPref.setTitle(getString(R.string.user_dict_settings_all_languages));
- else
- newPref.setTitle(LocaleUtils.constructLocaleFromString(locale).getDisplayName());
- intent.putExtra("locale", locale);
- newPref.getExtras().putString("locale", locale);
+ } else {
+ newPref.setTitle(
+ LocaleUtils.constructLocaleFromString(localeString).getDisplayName());
+ }
+ intent.putExtra("locale", localeString);
+ newPref.getExtras().putString("locale", localeString);
}
newPref.setIntent(intent);
newPref.setFragment(UserDictionarySettings.class.getName());
diff --git a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java
index 120cffbde..2fd257922 100644
--- a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java
@@ -29,9 +29,8 @@ public final class AutoCorrectionUtils {
// Purely static class: can't instantiate.
}
- public static boolean suggestionExceedsAutoCorrectionThreshold(
- final SuggestedWordInfo suggestion, final String consideredWord,
- final float autoCorrectionThreshold) {
+ public static boolean suggestionExceedsThreshold(final SuggestedWordInfo suggestion,
+ final String consideredWord, final float threshold) {
if (null != suggestion) {
// Shortlist a whitelisted word
if (suggestion.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
@@ -45,11 +44,11 @@ public final class AutoCorrectionUtils {
if (DBG) {
Log.d(TAG, "Normalized " + consideredWord + "," + suggestion + ","
+ autoCorrectionSuggestionScore + ", " + normalizedScore
- + "(" + autoCorrectionThreshold + ")");
+ + "(" + threshold + ")");
}
- if (normalizedScore >= autoCorrectionThreshold) {
+ if (normalizedScore >= threshold) {
if (DBG) {
- Log.d(TAG, "Auto corrected by S-threshold.");
+ Log.d(TAG, "Exceeds threshold.");
}
return true;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java
index 8699f2ce7..476c13406 100644
--- a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java
@@ -88,7 +88,7 @@ public class CombinedFormatUtils {
for (int i = 0; i < ngramProperty.mNgramContext.getPrevWordCount(); i++) {
builder.append(" " + NGRAM_PREV_WORD_TAG + "[" + i + "]="
+ ngramProperty.mNgramContext.getNthPrevWord(i + 1));
- if (ngramProperty.mNgramContext.isNthPrevWordBeginningOfSontence(i + 1)) {
+ if (ngramProperty.mNgramContext.isNthPrevWordBeginningOfSentence(i + 1)) {
builder.append("," + BEGINNING_OF_SENTENCE_TAG + "=true");
}
builder.append("\n");
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 81c3e3c61..fcce1ecdd 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -40,6 +40,9 @@ import java.util.Iterator;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* This class encapsulates the logic for the Latin-IME side of dictionary information management.
*/
@@ -59,19 +62,26 @@ public class DictionaryInfoUtils {
private static final String DATE_COLUMN = "date";
private static final String FILESIZE_COLUMN = "filesize";
private static final String VERSION_COLUMN = "version";
+ @Nonnull
public final String mId;
+ @Nonnull
public final Locale mLocale;
+ @Nullable
public final String mDescription;
+ @Nonnull
public final AssetFileAddress mFileAddress;
public final int mVersion;
- public DictionaryInfo(final String id, final Locale locale, final String description,
- final AssetFileAddress fileAddress, final int version) {
+
+ public DictionaryInfo(@Nonnull final String id, @Nonnull final Locale locale,
+ @Nullable final String description, @Nonnull final AssetFileAddress fileAddress,
+ final int version) {
mId = id;
mLocale = locale;
mDescription = description;
mFileAddress = fileAddress;
mVersion = version;
}
+
public ContentValues toContentValues() {
final ContentValues values = new ContentValues();
values.put(WORDLISTID_COLUMN, mId);
@@ -144,7 +154,8 @@ public class DictionaryInfoUtils {
/**
* Reverse escaping done by replaceFileNameDangerousCharacters.
*/
- public static String getWordListIdFromFileName(final String fname) {
+ @Nonnull
+ public static String getWordListIdFromFileName(@Nonnull final String fname) {
final StringBuilder sb = new StringBuilder();
final int fnameLength = fname.length();
for (int i = 0; i < fnameLength; i = fname.offsetByCodePoints(i, 1)) {
@@ -176,12 +187,15 @@ public class DictionaryInfoUtils {
* {@link #getMainDictId(Locale)} and {@link #isMainWordListId(String)}.
* @return The category as a string or null if it can't be found in the file name.
*/
- public static String getCategoryFromFileName(final String fileName) {
+ @Nullable
+ public static String getCategoryFromFileName(@Nonnull final String fileName) {
final String id = getWordListIdFromFileName(fileName);
final String[] idArray = id.split(BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR);
// An id is supposed to be in format category:locale, so splitting on the separator
// should yield a 2-elements array
- if (2 != idArray.length) return null;
+ if (2 != idArray.length) {
+ return null;
+ }
return idArray[0];
}
@@ -225,11 +239,24 @@ public class DictionaryInfoUtils {
final String[] idArray = id.split(BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR);
// An id is supposed to be in format category:locale, so splitting on the separator
// should yield a 2-elements array
- if (2 != idArray.length) return false;
+ if (2 != idArray.length) {
+ return false;
+ }
return BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY.equals(idArray[0]);
}
/**
+ * Find out whether a dictionary is available for this locale.
+ * @param context the context on which to check resources.
+ * @param locale the locale to check for.
+ * @return whether a (non-placeholder) dictionary is available or not.
+ */
+ public static boolean isDictionaryAvailable(final Context context, final Locale locale) {
+ final Resources res = context.getResources();
+ return 0 != getMainDictionaryResourceIdIfAvailableForLocale(res, locale);
+ }
+
+ /**
* Helper method to return a dictionary res id for a locale, or 0 if none.
* @param res resources for the app
* @param locale dictionary locale
@@ -266,7 +293,9 @@ public class DictionaryInfoUtils {
*/
public static int getMainDictionaryResourceId(final Resources res, final Locale locale) {
int resourceId = getMainDictionaryResourceIdIfAvailableForLocale(res, locale);
- if (0 != resourceId) return resourceId;
+ if (0 != resourceId) {
+ return resourceId;
+ }
return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", RESOURCE_PACKAGE_NAME);
}
@@ -335,10 +364,10 @@ public class DictionaryInfoUtils {
if (header == null) {
return null;
}
- final String id = header.getId();
- final Locale locale = LocaleUtils.constructLocaleFromString(header.getLocaleString());
+ final String id = header.mIdString;
+ final Locale locale = LocaleUtils.constructLocaleFromString(header.mLocaleString);
final String description = header.getDescription();
- final String version = header.getVersion();
+ final String version = header.mVersionString;
return new DictionaryInfo(id, locale, description, fileAddress, Integer.parseInt(version));
}
@@ -366,10 +395,13 @@ public class DictionaryInfoUtils {
if (null != directoryList) {
for (final File directory : directoryList) {
final String localeString = getWordListIdFromFileName(directory.getName());
- File[] dicts = BinaryDictionaryGetter.getCachedWordLists(localeString, context);
+ final File[] dicts = BinaryDictionaryGetter.getCachedWordLists(
+ localeString, context);
for (final File dict : dicts) {
final String wordListId = getWordListIdFromFileName(dict.getName());
- if (!DictionaryInfoUtils.isMainWordListId(wordListId)) continue;
+ if (!DictionaryInfoUtils.isMainWordListId(wordListId)) {
+ continue;
+ }
final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
final AssetFileAddress fileAddress = AssetFileAddress.makeFromFile(dict);
final DictionaryInfo dictionaryInfo =
@@ -377,7 +409,9 @@ public class DictionaryInfoUtils {
// Protect against cases of a less-specific dictionary being found, like an
// en dictionary being used for an en_US locale. In this case, the en dictionary
// should be used for en_US but discounted for listing purposes.
- if (dictionaryInfo == null || !dictionaryInfo.mLocale.equals(locale)) continue;
+ if (dictionaryInfo == null || !dictionaryInfo.mLocale.equals(locale)) {
+ continue;
+ }
addOrUpdateDictInfo(dictList, dictionaryInfo);
}
}
@@ -391,14 +425,18 @@ public class DictionaryInfoUtils {
final int resourceId =
DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
context.getResources(), locale);
- if (0 == resourceId) continue;
+ if (0 == resourceId) {
+ continue;
+ }
final AssetFileAddress fileAddress =
BinaryDictionaryGetter.loadFallbackResource(context, resourceId);
final DictionaryInfo dictionaryInfo = createDictionaryInfoFromFileAddress(fileAddress);
// Protect against cases of a less-specific dictionary being found, like an
// en dictionary being used for an en_US locale. In this case, the en dictionary
// should be used for en_US but discounted for listing purposes.
- if (!dictionaryInfo.mLocale.equals(locale)) continue;
+ if (!dictionaryInfo.mLocale.equals(locale)) {
+ continue;
+ }
addOrUpdateDictInfo(dictList, dictionaryInfo);
}
@@ -408,7 +446,9 @@ public class DictionaryInfoUtils {
@UsedForTesting
public static boolean looksValidForDictionaryInsertion(final CharSequence text,
final SpacingAndPunctuations spacingAndPunctuations) {
- if (TextUtils.isEmpty(text)) return false;
+ if (TextUtils.isEmpty(text)) {
+ return false;
+ }
final int length = text.length();
if (length > Constants.DICTIONARY_MAX_WORD_LENGTH) {
return false;
@@ -424,7 +464,9 @@ public class DictionaryInfoUtils {
digitCount += charCount;
continue;
}
- if (!spacingAndPunctuations.isWordCodePoint(codePoint)) return false;
+ if (!spacingAndPunctuations.isWordCodePoint(codePoint)) {
+ return false;
+ }
}
// We reject strings entirely comprised of digits to avoid using PIN codes or credit
// card numbers. It would come in handy for word prediction though; a good example is
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 9c6a94810..0c01a737c 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -143,7 +143,7 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
mContext, editorInfo);
final Resources res = mContext.getResources();
- final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
+ final int keyboardWidth = ResourceUtils.getKeyboardFrameWidth(res);
final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
builder.setKeyboardGeometry(keyboardWidth, keyboardHeight);
builder.setSubtype(new RichInputMethodSubtype(subtype));
diff --git a/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
index cc0d470df..0a757877a 100644
--- a/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
@@ -182,18 +182,63 @@ public final class ResourceUtils {
return matchedAll;
}
- public static int getDefaultKeyboardWidth(final Resources res) {
+ public static int getKeyboardFrameWidth(final Resources res) {
final DisplayMetrics dm = res.getDisplayMetrics();
return dm.widthPixels;
}
+ public static int getKeyboardWidth(final Resources res, final SettingsValues settingsValues) {
+ final int frameWidth = getKeyboardFrameWidth(res);
+ if (settingsValues.mHasKeyboardResize) {
+ final float widthFraction = 1f - settingsValues.mKeyboardLeftMarginScale
+ - settingsValues.mKeyboardRightMarginScale;
+ return (int)(frameWidth * widthFraction);
+ }
+ return frameWidth;
+ }
+
+ public static int getKeyboardFrameHeight(final Resources res,
+ final SettingsValues settingsValues) {
+ if (settingsValues.mHasKeyboardResize) {
+ return getKeyboardHeight(res, settingsValues)
+ + getKeyboardBottomMargin(res, settingsValues);
+ }
+ return getDefaultKeyboardHeight(res);
+ }
+
public static int getKeyboardHeight(final Resources res, final SettingsValues settingsValues) {
- final int defaultKeyboardHeight = getDefaultKeyboardHeight(res);
+ final int keyboardHeight = getDefaultKeyboardHeight(res);
+ if (settingsValues.mHasKeyboardResize) {
+ return (int)(keyboardHeight * settingsValues.mKeyboardHeightScale);
+ }
+ return keyboardHeight;
+ }
+
+ public static int getKeyboardLeftMargin(
+ final Resources res, final SettingsValues settingsValues) {
+ if (settingsValues.mHasKeyboardResize) {
+ final int frameWidth = getKeyboardFrameWidth(res);
+ return (int)(frameWidth * settingsValues.mKeyboardLeftMarginScale);
+ }
+ return 0;
+ }
+
+ public static int getKeyboardRightMargin(
+ final Resources res, final SettingsValues settingsValues) {
+ if (settingsValues.mHasKeyboardResize) {
+ final int frameWidth = getKeyboardFrameWidth(res);
+ return (int)(frameWidth * settingsValues.mKeyboardRightMarginScale);
+ }
+ return 0;
+ }
+
+ public static int getKeyboardBottomMargin(
+ final Resources res, final SettingsValues settingsValues) {
if (settingsValues.mHasKeyboardResize) {
- // mKeyboardHeightScale Ranges from [.5,1.2], from xml/prefs_screen_debug.xml
- return (int)(defaultKeyboardHeight * settingsValues.mKeyboardHeightScale);
+ final int defaultHeight = getDefaultKeyboardHeight(res);
+ return (int)(defaultHeight * settingsValues.mKeyboardBottomMarginScale);
}
- return defaultKeyboardHeight;
+ return 0;
}
public static int getDefaultKeyboardHeight(final Resources res) {
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 0e7f4717d..54a3fc39c 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -199,8 +199,7 @@ public final class SubtypeLocaleUtils {
if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) {
languageString = localeString;
} else {
- final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
- languageString = locale.getLanguage();
+ languageString = LocaleUtils.constructLocaleFromString(localeString).getLanguage();
}
return getSubtypeLocaleDisplayNameInternal(languageString, displayLocale);
}
@@ -232,8 +231,8 @@ public final class SubtypeLocaleUtils {
};
displayName = getExceptionalName.runInLocale(sResources, displayLocale);
} else {
- final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
- displayName = locale.getDisplayName(displayLocale);
+ displayName = LocaleUtils.constructLocaleFromString(localeString)
+ .getDisplayName(displayLocale);
}
return StringUtils.capitalizeFirstCodePoint(displayName, displayLocale);
}