diff options
45 files changed, 393 insertions, 317 deletions
diff --git a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java index 9d7258de7..5738ea2b2 100644 --- a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java +++ b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java @@ -24,14 +24,6 @@ public final class ProductionFlags { public static final boolean IS_HARDWARE_KEYBOARD_SUPPORTED = false; /** - * When true, enable {@link InputMethodService#onUpdateCursorAnchorInfo} callback via - * {@link InputConnection#requestUpdateCursorAnchorInfo}. This flag has no effect in API - * Level 20 and prior. In general, this callback provides detailed positional information, - * even though an explicit support is required by the editor. - */ - public static final boolean ENABLE_CURSOR_ANCHOR_INFO_CALLBACK = true; - - /** * Include all suggestions from all dictionaries in {@link SuggestedWords#mRawSuggestions}. */ public static final boolean INCLUDE_RAW_SUGGESTIONS = false; diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 25fa0f9e3..ee1cef6b5 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -89,8 +89,7 @@ <activity android:name=".settings.SettingsActivity" android:theme="@style/platformSettingsTheme" - android:label="@string/english_ime_settings" - android:uiOptions="splitActionBarWhenNarrow"> + android:label="@string/english_ime_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> diff --git a/java/res/raw/setup_welcome_image.png b/java/res/raw/setup_welcome_image.png Binary files differindex 98e731331..b72618114 100644 --- a/java/res/raw/setup_welcome_image.png +++ b/java/res/raw/setup_welcome_image.png diff --git a/java/res/raw/setup_welcome_video.mp4 b/java/res/raw/setup_welcome_video.mp4 Binary files differindex 224bf250c..09be565e4 100644 --- a/java/res/raw/setup_welcome_video.mp4 +++ b/java/res/raw/setup_welcome_video.mp4 diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 8cc66425c..77a46f9c7 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -183,6 +183,7 @@ /> <!-- TODO: This Bengali (Bangladesh) keyboard is a preliminary layout. This isn't based on the final specification. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xa2144b0c" @@ -191,6 +192,7 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=bengali_akkhor,EmojiCapable" android:isAsciiCapable="false" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xbff5986c" @@ -369,6 +371,7 @@ /> <!-- TODO: This Hinglish keyboard is a preliminary layout. This isn't based on the final specification. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_hi_ZZ" android:subtypeId="0x352eb37c" @@ -377,6 +380,7 @@ android:imeSubtypeExtraValue="AsciiCapable,KeyboardLayoutSet=qwerty,EmojiCapable" android:isAsciiCapable="true" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x35b7526a" @@ -549,6 +553,7 @@ /> <!-- TODO: This Myanmar keyboard is a preliminary layout. This isn't based on the final specification. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xea266ea4" @@ -557,6 +562,7 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=myanmar,EmojiCapable,CombiningRules=MyanmarReordering" android:isAsciiCapable="false" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x3f12ee14" @@ -639,6 +645,7 @@ /> <!-- TODO: This Sinhala keyboard is a preliminary layout. This isn't based on the final specification. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x5c6b3bde" @@ -647,6 +654,7 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=sinhala,EmojiCapable" android:isAsciiCapable="false" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x8e94d413" @@ -673,6 +681,7 @@ /> <!-- TODO: This Serbian Latin keyboard is a preliminary layout. This isn't based on the final specification. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_sr_ZZ" android:subtypeId="0xf4a5569c" @@ -681,6 +690,7 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=serbian_qwertz,AsciiCapable,EmojiCapable" android:isAsciiCapable="true" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x48b4ff43" @@ -706,6 +716,7 @@ android:isAsciiCapable="false" /> <!-- TODO: Enabling/Disabling ta_LK subtype must be aligned with si_LK subtype. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x6ca12d84" @@ -714,6 +725,7 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=tamil,EmojiCapable" android:isAsciiCapable="false" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x785abbd9" @@ -764,6 +776,7 @@ /> <!-- TODO: This Uzbek keyboard is a preliminary layout. This isn't based on the final specification. --> + <!-- <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xad5cf7f6" @@ -772,6 +785,7 @@ android:imeSubtypeExtraValue="KeyboardLayoutSet=uzbek,AsciiCapable,EmojiCapable" android:isAsciiCapable="true" /> + --> <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x93972eee" diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index bf29b5ffe..45ce6a85f 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -278,8 +278,8 @@ public class Key implements Comparable<Key> { mLabelFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags) | row.getDefaultKeyLabelFlags(); - final boolean needsToUpperCase = needsToUpperCase(mLabelFlags, params.mId.mElementId); - final Locale locale = params.mId.mLocale; + final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId); + final Locale localeForUpcasing = params.mId.getLocales()[0]; int actionFlags = style.getFlags(keyAttr, R.styleable.Keyboard_Key_keyActionFlags); String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys); @@ -321,7 +321,7 @@ public class Key implements Comparable<Key> { actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS; mMoreKeys = new MoreKeySpec[moreKeys.length]; for (int i = 0; i < moreKeys.length; i++) { - mMoreKeys[i] = new MoreKeySpec(moreKeys[i], needsToUpperCase, locale); + mMoreKeys[i] = new MoreKeySpec(moreKeys[i], needsToUpcase, localeForUpcasing); } } else { mMoreKeys = null; @@ -342,16 +342,16 @@ public class Key implements Comparable<Key> { mLabel = new StringBuilder().appendCodePoint(code).toString(); } else { mLabel = StringUtils.toUpperCaseOfStringForLocale( - KeySpecParser.getLabel(keySpec), needsToUpperCase, locale); + KeySpecParser.getLabel(keySpec), needsToUpcase, localeForUpcasing); } if ((mLabelFlags & LABEL_FLAGS_DISABLE_HINT_LABEL) != 0) { mHintLabel = null; } else { mHintLabel = StringUtils.toUpperCaseOfStringForLocale(style.getString(keyAttr, - R.styleable.Keyboard_Key_keyHintLabel), needsToUpperCase, locale); + R.styleable.Keyboard_Key_keyHintLabel), needsToUpcase, localeForUpcasing); } String outputText = StringUtils.toUpperCaseOfStringForLocale( - KeySpecParser.getOutputText(keySpec), needsToUpperCase, locale); + KeySpecParser.getOutputText(keySpec), needsToUpcase, localeForUpcasing); // Choose the first letter of the label as primary code if not specified. if (code == CODE_UNSPECIFIED && TextUtils.isEmpty(outputText) && !TextUtils.isEmpty(mLabel)) { @@ -377,12 +377,12 @@ public class Key implements Comparable<Key> { mCode = CODE_OUTPUT_TEXT; } } else { - mCode = StringUtils.toUpperCaseOfCodeForLocale(code, needsToUpperCase, locale); + mCode = StringUtils.toUpperCaseOfCodeForLocale(code, needsToUpcase, localeForUpcasing); } final int altCodeInAttr = KeySpecParser.parseCode( style.getString(keyAttr, R.styleable.Keyboard_Key_altCode), CODE_UNSPECIFIED); final int altCode = StringUtils.toUpperCaseOfCodeForLocale( - altCodeInAttr, needsToUpperCase, locale); + altCodeInAttr, needsToUpcase, localeForUpcasing); mOptionalAttributes = OptionalAttributes.newInstance(outputText, altCode, disabledIconId, visualInsetsLeft, visualInsetsRight); mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr); @@ -432,7 +432,7 @@ public class Key implements Comparable<Key> { return (filteredMoreKeys == moreKeys) ? key : new Key(key, filteredMoreKeys); } - private static boolean needsToUpperCase(final int labelFlags, final int keyboardElementId) { + private static boolean needsToUpcase(final int labelFlags, final int keyboardElementId) { if ((labelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0) return false; switch (keyboardElementId) { case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED: diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index f9cf3535e..ab0d63306 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -63,7 +63,6 @@ public final class KeyboardId { public static final int ELEMENT_EMOJI_CATEGORY6 = 16; public final RichInputMethodSubtype mSubtype; - public final Locale mLocale; public final int mWidth; public final int mHeight; public final int mMode; @@ -79,7 +78,6 @@ public final class KeyboardId { public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) { mSubtype = params.mSubtype; - mLocale = SubtypeLocaleUtils.getSubtypeLocale(mSubtype); mWidth = params.mKeyboardWidth; mHeight = params.mKeyboardHeight; mMode = params.mMode; @@ -167,6 +165,10 @@ public final class KeyboardId { return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo); } + public Locale[] getLocales() { + return mSubtype.getLocales(); + } + @Override public boolean equals(final Object other) { return other instanceof KeyboardId && equals((KeyboardId) other); @@ -181,7 +183,8 @@ public final class KeyboardId { public String toString() { return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]", elementIdToName(mElementId), - mLocale, mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), + Arrays.deepToString(mSubtype.getLocales()), + mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), mWidth, mHeight, modeName(mMode), actionName(imeAction()), diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 7f2957fff..93123d1ec 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -120,7 +120,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mKeyboardLayoutSet = builder.build(); try { mState.onLoadKeyboard(currentAutoCapsState, currentRecapitalizeState); - mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocale(), mThemeContext); + // TODO: revisit this for multi-lingual input + mKeyboardTextsSet.setLocale(mSubtypeSwitcher.getCurrentSubtypeLocales()[0], + mThemeContext); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); return; @@ -161,7 +163,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { currentSettingsValues.mKeyPreviewDismissDuration); keyboardView.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady()); final boolean subtypeChanged = (oldKeyboard == null) - || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); + || !keyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype); final int languageOnSpacebarFormatType = mSubtypeSwitcher.getLanguageOnSpacebarFormatType( keyboard.mId.mSubtype); final boolean hasMultipleEnabledIMEsOrSubtypes = RichInputMethodManager.getInstance() diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index cded2cb8c..ad30b746e 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -875,6 +875,11 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // Layout language name on spacebar. private String layoutLanguageOnSpacebar(final Paint paint, final RichInputMethodSubtype subtype, final int width) { + if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_MULTIPLE) { + // TODO: return an appropriate string + return ""; + } + // Choose appropriate language name to fit into the width. if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) { final String fullText = subtype.getFullDisplayName(); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java index 50385555c..f4e010c4d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java @@ -45,6 +45,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.util.Arrays; +import java.util.Locale; /** * Keyboard Building helper. @@ -281,7 +282,8 @@ public class KeyboardBuilder<KP extends KeyboardParams> { params.mThemeId = keyboardAttr.getInt(R.styleable.Keyboard_themeId, 0); params.mIconsSet.loadIcons(keyboardAttr); - params.mTextsSet.setLocale(params.mId.mLocale, mContext); + // TODO: this needs to be revisited for multi-lingual input. + params.mTextsSet.setLocale(params.mId.getLocales()[0], mContext); final int resourceId = keyboardAttr.getResourceId( R.styleable.Keyboard_touchPositionCorrectionData, 0); @@ -672,12 +674,10 @@ public class KeyboardBuilder<KP extends KeyboardParams> { R.styleable.Keyboard_Case_imeAction, id.imeAction()); final boolean isIconDefinedMatched = isIconDefined(caseAttr, R.styleable.Keyboard_Case_isIconDefined, mParams.mIconsSet); - final boolean localeCodeMatched = matchString(caseAttr, - R.styleable.Keyboard_Case_localeCode, id.mLocale.toString()); - final boolean languageCodeMatched = matchString(caseAttr, - R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage()); - final boolean countryCodeMatched = matchString(caseAttr, - R.styleable.Keyboard_Case_countryCode, id.mLocale.getCountry()); + final Locale[] locales = id.getLocales(); + final boolean localeCodeMatched = matchLocaleCodes(caseAttr, locales); + final boolean languageCodeMatched = matchLanguageCodes(caseAttr, locales); + final boolean countryCodeMatched = matchCountryCodes(caseAttr, locales); final boolean splitLayoutMatched = matchBoolean(caseAttr, R.styleable.Keyboard_Case_isSplitLayout, id.mIsSplitLayout); final boolean selected = keyboardLayoutSetMatched && keyboardLayoutSetElementMatched @@ -733,6 +733,23 @@ public class KeyboardBuilder<KP extends KeyboardParams> { } } + private boolean matchLocaleCodes(TypedArray caseAttr, final Locale[] locales) { + // TODO: adujst this for multilingual input + return matchString(caseAttr, R.styleable.Keyboard_Case_localeCode, locales[0].toString()); + } + + private boolean matchLanguageCodes(TypedArray caseAttr, Locale[] locales) { + // TODO: adujst this for multilingual input + return matchString(caseAttr, R.styleable.Keyboard_Case_languageCode, + locales[0].getLanguage()); + } + + private boolean matchCountryCodes(TypedArray caseAttr, Locale[] locales) { + // TODO: adujst this for multilingual input + return matchString(caseAttr, R.styleable.Keyboard_Case_countryCode, + locales[0].getCountry()); + } + private static boolean matchInteger(final TypedArray a, final int index, final int value) { // If <case> does not have "index" attribute, that means this <case> is wild-card for // the attribute. diff --git a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java index 72ad2bd97..21eaed950 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java +++ b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java @@ -23,6 +23,7 @@ import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * This class determines that the language name on the spacebar should be displayed in what format. @@ -31,6 +32,7 @@ public final class LanguageOnSpacebarHelper { public static final int FORMAT_TYPE_NONE = 0; public static final int FORMAT_TYPE_LANGUAGE_ONLY = 1; public static final int FORMAT_TYPE_FULL_LOCALE = 2; + public static final int FORMAT_TYPE_MULTIPLE = 3; private List<InputMethodSubtype> mEnabledSubtypes = Collections.emptyList(); private boolean mIsSystemLanguageSameAsInputLanguage; @@ -43,7 +45,11 @@ public final class LanguageOnSpacebarHelper { if (mEnabledSubtypes.size() < 2 && mIsSystemLanguageSameAsInputLanguage) { return FORMAT_TYPE_NONE; } - final String keyboardLanguage = SubtypeLocaleUtils.getSubtypeLocale(subtype).getLanguage(); + final Locale[] locales = subtype.getLocales(); + if (1 < locales.length) { + return FORMAT_TYPE_MULTIPLE; + } + final String keyboardLanguage = locales[0].getLanguage(); final String keyboardLayout = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype); int sameLanguageAndLayoutCount = 0; for (final InputMethodSubtype ims : mEnabledSubtypes) { diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index 1f0317288..4a218d550 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -416,33 +416,38 @@ public class DictionaryFacilitator { } @UsedForTesting - public void resetDictionariesForTesting(final Context context, final Locale locale, + public void resetDictionariesForTesting(final Context context, final Locale[] locales, final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, final Map<String, Map<String, String>> additionalDictAttributes) { Dictionary mainDictionary = null; final Map<String, ExpandableBinaryDictionary> subDicts = new HashMap<>(); - for (final String dictType : dictionaryTypes) { - if (dictType.equals(Dictionary.TYPE_MAIN)) { - mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, locale); - } else { - final File dictFile = dictionaryFiles.get(dictType); - final ExpandableBinaryDictionary dict = getSubDict( - dictType, context, locale, dictFile, "" /* dictNamePrefix */); - if (additionalDictAttributes.containsKey(dictType)) { - dict.clearAndFlushDictionaryWithAdditionalAttributes( - additionalDictAttributes.get(dictType)); - } - if (dict == null) { - throw new RuntimeException("Unknown dictionary type: " + dictType); + final DictionaryGroup[] dictionaryGroups = new DictionaryGroup[locales.length]; + for (int i = 0; i < locales.length; ++i) { + final Locale locale = locales[i]; + for (final String dictType : dictionaryTypes) { + if (dictType.equals(Dictionary.TYPE_MAIN)) { + mainDictionary = DictionaryFactory.createMainDictionaryFromManager(context, + locale); + } else { + final File dictFile = dictionaryFiles.get(dictType); + final ExpandableBinaryDictionary dict = getSubDict( + dictType, context, locale, dictFile, "" /* dictNamePrefix */); + if (additionalDictAttributes.containsKey(dictType)) { + dict.clearAndFlushDictionaryWithAdditionalAttributes( + additionalDictAttributes.get(dictType)); + } + if (dict == null) { + throw new RuntimeException("Unknown dictionary type: " + dictType); + } + dict.reloadDictionaryIfRequired(); + dict.waitAllTasksForTests(); + subDicts.put(dictType, dict); } - dict.reloadDictionaryIfRequired(); - dict.waitAllTasksForTests(); - subDicts.put(dictType, dict); } + dictionaryGroups[i] = new DictionaryGroup(locale, mainDictionary, subDicts); } - mDictionaryGroups = new DictionaryGroup[] { - new DictionaryGroup(locale, mainDictionary, subDicts) }; + mDictionaryGroups = dictionaryGroups; } public void closeDictionaries() { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index be2efb2dc..8e93761a2 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -102,7 +102,7 @@ import com.android.inputmethod.latin.utils.ViewLayoutUtils; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; @@ -575,18 +575,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Has to be package-visible for unit tests @UsedForTesting void loadSettings() { - final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); + final Locale[] locales = mSubtypeSwitcher.getCurrentSubtypeLocales(); final EditorInfo editorInfo = getCurrentInputEditorInfo(); final InputAttributes inputAttributes = new InputAttributes( editorInfo, isFullscreenMode(), getPackageName()); - mSettings.loadSettings(this, locale, inputAttributes); + // TODO: pass the array instead + mSettings.loadSettings(this, locales[0], inputAttributes); final SettingsValues currentSettingsValues = mSettings.getCurrent(); AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues); // This method is called on startup and language switch, before the new layout has // been displayed. Opening dictionaries never affects responsivity as dictionaries are // asynchronously loaded. if (!mHandler.hasPendingReopenDictionaries()) { - resetDictionaryFacilitatorForLocale(locale); + resetDictionaryFacilitatorForLocale(locales); } mDictionaryFacilitator.updateEnabledSubtypes(mRichImm.getMyEnabledInputMethodSubtypeList( true /* allowsImplicitlySelectedSubtypes */)); @@ -628,35 +629,34 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } private void resetDictionaryFacilitatorIfNecessary() { - final Locale switcherSubtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); - if (mDictionaryFacilitator.isForLocales(new Locale[] { switcherSubtypeLocale })) { + final Locale[] subtypeSwitcherLocales = mSubtypeSwitcher.getCurrentSubtypeLocales(); + if (mDictionaryFacilitator.isForLocales(subtypeSwitcherLocales)) { return; } - final String switcherLocaleStr = switcherSubtypeLocale.toString(); - final Locale subtypeLocale; - if (TextUtils.isEmpty(switcherLocaleStr)) { + final Locale[] subtypeLocales; + if (0 == subtypeSwitcherLocales.length) { // This happens in very rare corner cases - for example, immediately after a switch // to LatinIME has been requested, about a frame later another switch happens. In this // case, we are about to go down but we still don't know it, however the system tells - // us there is no current subtype so the locale is the empty string. Take the best - // possible guess instead -- it's bound to have no consequences, and we have no way - // of knowing anyway. + // us there is no current subtype. Log.e(TAG, "System is reporting no current subtype."); - subtypeLocale = getResources().getConfiguration().locale; + subtypeLocales = new Locale[] { getResources().getConfiguration().locale }; } else { - subtypeLocale = switcherSubtypeLocale; + subtypeLocales = subtypeSwitcherLocales; } - resetDictionaryFacilitatorForLocale(subtypeLocale); + resetDictionaryFacilitatorForLocale(subtypeLocales); } /** - * Reset the facilitator by loading dictionaries for the locale and the current settings values. + * Reset the facilitator by loading dictionaries for the locales and the current settings values * - * @param locale the locale + * @param locales the locales */ - // TODO: make sure the current settings always have the right locale, and read from them - private void resetDictionaryFacilitatorForLocale(final Locale locale) { + // TODO: make sure the current settings always have the right locales, and read from them + private void resetDictionaryFacilitatorForLocale(final Locale[] locales) { final SettingsValues settingsValues = mSettings.getCurrent(); + // TODO: pass the array instead + final Locale locale = locales[0]; mDictionaryFacilitator.resetDictionaries(this /* context */, locale, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, false /* forceReloadMainDictionary */, this); @@ -755,12 +755,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (prevExtractEditText == nextExtractEditText) { return; } - if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && prevExtractEditText != null) { + if (prevExtractEditText != null) { prevExtractEditText.getViewTreeObserver().removeOnPreDrawListener( mExtractTextViewPreDrawListener); } mExtractEditText = nextExtractEditText; - if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK && mExtractEditText != null) { + if (mExtractEditText != null) { mExtractEditText.getViewTreeObserver().addOnPreDrawListener( mExtractTextViewPreDrawListener); } @@ -776,8 +776,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen }; private void onExtractTextViewPreDraw() { - if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || !isFullscreenMode() - || mExtractEditText == null) { + if (!isFullscreenMode() || mExtractEditText == null) { return; } final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText); @@ -881,7 +880,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(), - Collections.singletonList(mSubtypeSwitcher.getCurrentSubtypeLocale()), + Arrays.asList(mSubtypeSwitcher.getCurrentSubtypeLocales()), switcher.getKeyboard()); // Forward this event to the accessibility utilities, if enabled. @@ -1060,7 +1059,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // We cannot mark this method as @Override until new SDK becomes publicly available. // @Override public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) { - if (!ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK || isFullscreenMode()) { + if (isFullscreenMode()) { return; } mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info)); @@ -1434,7 +1433,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen public void onStartBatchInput() { mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler); mGestureConsumer.onGestureStarted( - Collections.singletonList(mSubtypeSwitcher.getCurrentSubtypeLocale()), + Arrays.asList(mSubtypeSwitcher.getCurrentSubtypeLocales()), mKeyboardSwitcher.getKeyboard()); } @@ -1558,7 +1557,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, - SubtypeLocaleUtils.isRtlLanguage(mSubtypeSwitcher.getCurrentSubtype())); + mSubtypeSwitcher.getCurrentSubtype().isRtlSubtype()); } } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java index 0b08c48e5..8d055531c 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java @@ -114,10 +114,13 @@ public final class RichInputMethodSubtype { return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales); } - // TODO: remove this method! We can always have several locales. Multi-lingual input will only - // be done when this method is gone. - public String getLocale() { - return mSubtype.getLocale(); + public Locale[] getLocales() { + return mLocales; + } + + public boolean isRtlSubtype() { + // The subtype is considered RTL if the language of the main subtype is RTL. + return SubtypeLocaleUtils.isRtlLanguage(mLocales[0]); } // TODO: remove this method diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 45d67ff88..c339e96fb 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -170,15 +170,21 @@ public final class SubtypeSwitcher { Log.w(TAG, "onSubtypeChanged: " + newSubtype.getNameForLogging()); } - final Locale newLocale = SubtypeLocaleUtils.getSubtypeLocale(newSubtype); - final Locale systemLocale = mResources.getConfiguration().locale; - final boolean sameLocale = systemLocale.equals(newLocale); - final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage()); - final boolean implicitlyEnabled = mRichImm - .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype.getRawSubtype()); - mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage( - sameLocale || (sameLanguage && implicitlyEnabled)); - + final Locale[] newLocales = newSubtype.getLocales(); + if (newLocales.length > 1) { + // In multi-locales mode, the system language is never the same as the input language + // because there is no single input language. + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false); + } else { + final Locale newLocale = newLocales[0]; + final Locale systemLocale = mResources.getConfiguration().locale; + final boolean sameLocale = systemLocale.equals(newLocale); + final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage()); + final boolean implicitlyEnabled = mRichImm + .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype.getRawSubtype()); + mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage( + sameLocale || (sameLanguage && implicitlyEnabled)); + } updateShortcutIME(); } @@ -284,11 +290,11 @@ public final class SubtypeSwitcher { sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype); } - public Locale getCurrentSubtypeLocale() { + public Locale[] getCurrentSubtypeLocales() { if (null != sForcedSubtypeForTesting) { - return LocaleUtils.constructLocaleFromString(sForcedSubtypeForTesting.getLocale()); + return sForcedSubtypeForTesting.getLocales(); } - return SubtypeLocaleUtils.getSubtypeLocale(getCurrentSubtype()); + return getCurrentSubtype().getLocales(); } public RichInputMethodSubtype getCurrentSubtype() { diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 1b1d5e7e5..f67a9a6ef 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -169,14 +169,11 @@ public final class InputLogic { mInputLogicHandler.reset(); } - if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) { - // AcceptTypedWord feature relies on CursorAnchorInfo. - if (settingsValues.mShouldShowUiToAcceptTypedWord) { - mConnection.requestCursorUpdates(true /* enableMonitor */, - true /* requestImmediateCallback */); - } - mTextDecorator.reset(); + if (settingsValues.mShouldShowUiToAcceptTypedWord) { + mConnection.requestCursorUpdates(true /* enableMonitor */, + true /* requestImmediateCallback */); } + mTextDecorator.reset(); } /** diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java index 2174f5224..c633fc167 100644 --- a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java @@ -33,7 +33,6 @@ import android.preference.PreferenceGroup; import android.support.v4.view.ViewCompat; import android.text.TextUtils; import android.util.Log; -import android.util.Pair; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -80,25 +79,26 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment { "is_subtype_enabler_notification_dialog_open"; private static final String KEY_SUBTYPE_FOR_SUBTYPE_ENABLER = "subtype_for_subtype_enabler"; - static final class SubtypeLocaleItem extends Pair<String, String> - implements Comparable<SubtypeLocaleItem> { - public SubtypeLocaleItem(final String localeString, final String displayName) { - super(localeString, displayName); - } + static final class SubtypeLocaleItem implements Comparable<SubtypeLocaleItem> { + public final String mLocaleString; + private final String mDisplayName; - public SubtypeLocaleItem(final String localeString) { - this(localeString, - SubtypeLocaleUtils.getSubtypeLocaleDisplayNameInSystemLocale(localeString)); + public SubtypeLocaleItem(final InputMethodSubtype subtype) { + mLocaleString = subtype.getLocale(); + mDisplayName = SubtypeLocaleUtils.getSubtypeLocaleDisplayNameInSystemLocale( + mLocaleString); } + // {@link ArrayAdapter<T>} that hosts the instance of this class needs {@link #toString()} + // to get display name. @Override public String toString() { - return second; + return mDisplayName; } @Override public int compareTo(final SubtypeLocaleItem o) { - return first.compareTo(o.first); + return mLocaleString.compareTo(o.mLocaleString); } } @@ -121,32 +121,28 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype))); } if (InputMethodSubtypeCompatUtils.isAsciiCapable(subtype)) { - items.add(createItem(context, subtype.getLocale())); + items.add(new SubtypeLocaleItem(subtype)); } } // TODO: Should filter out already existing combinations of locale and layout. addAll(items); } - - public static SubtypeLocaleItem createItem(final Context context, - final String localeString) { - if (localeString.equals(SubtypeLocaleUtils.NO_LANGUAGE)) { - final String displayName = context.getString(R.string.subtype_no_language); - return new SubtypeLocaleItem(localeString, displayName); - } - return new SubtypeLocaleItem(localeString); - } } - static final class KeyboardLayoutSetItem extends Pair<String, String> { + static final class KeyboardLayoutSetItem { + public final String mLayoutName; + private final String mDisplayName; + public KeyboardLayoutSetItem(final InputMethodSubtype subtype) { - super(SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype), - SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype)); + mLayoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype); + mDisplayName = SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype); } + // {@link ArrayAdapter<T>} that hosts the instance of this class needs {@link #toString()} + // to get display name. @Override public String toString() { - return second; + return mDisplayName; } } @@ -255,7 +251,6 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment { @Override protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) { - final Context context = builder.getContext(); builder.setCancelable(true).setOnCancelListener(this); if (isIncomplete()) { builder.setPositiveButton(R.string.add, this) @@ -264,8 +259,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment { builder.setPositiveButton(R.string.save, this) .setNeutralButton(android.R.string.cancel, this) .setNegativeButton(R.string.remove, this); - final SubtypeLocaleItem localeItem = SubtypeLocaleAdapter.createItem( - context, mSubtype.getLocale()); + final SubtypeLocaleItem localeItem = new SubtypeLocaleItem(mSubtype); final KeyboardLayoutSetItem layoutItem = new KeyboardLayoutSetItem(mSubtype); setSpinnerPosition(mSubtypeLocaleSpinner, localeItem); setSpinnerPosition(mKeyboardLayoutSetSpinner, layoutItem); @@ -303,7 +297,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment { (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem(); final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( - locale.first, layout.first); + locale.mLocaleString, layout.mLayoutName); setSubtype(subtype); notifyChanged(); if (isEditing) { @@ -469,8 +463,6 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment { KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN)) { mSubtypePreferenceKeyForSubtypeEnabler = savedInstanceState.getString( KEY_SUBTYPE_FOR_SUBTYPE_ENABLER); - final SubtypePreference subtypePref = (SubtypePreference)findPreference( - mSubtypePreferenceKeyForSubtypeEnabler); mSubtypeEnablerNotificationDialog = createDialog(); mSubtypeEnablerNotificationDialog.show(); } diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java index b770ea512..7607429f8 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java @@ -17,12 +17,8 @@ package com.android.inputmethod.latin.setup; import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.provider.Settings; -import android.view.inputmethod.InputMethodInfo; -import android.view.inputmethod.InputMethodManager; public final class SetupActivity extends Activity { @Override diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java index e455e53d3..54562f39d 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java @@ -46,6 +46,8 @@ import java.util.ArrayList; public final class SetupWizardActivity extends Activity implements View.OnClickListener { static final String TAG = SetupWizardActivity.class.getSimpleName(); + // For debugging purpose. + private static final boolean FORCE_TO_SHOW_WELCOME_SCREEN = false; private static final boolean ENABLE_WELCOME_VIDEO = true; private InputMethodManager mImm; @@ -304,6 +306,9 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL private int determineSetupStepNumber() { mHandler.cancelPollingImeSettings(); + if (FORCE_TO_SHOW_WELCOME_SCREEN) { + return STEP_1; + } if (!UncachedInputMethodManagerUtils.isThisImeEnabled(this, mImm)) { return STEP_1; } diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java index 5a7f7662c..61661cd52 100644 --- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java @@ -293,13 +293,6 @@ public final class SubtypeLocaleUtils { return LocaleUtils.constructLocaleFromString(localeString); } - // TODO: remove this. When RichInputMethodSubtype#getLocale is removed we can do away with this - // method at the same time. - public static Locale getSubtypeLocale(final RichInputMethodSubtype subtype) { - final String localeString = subtype.getLocale(); - return LocaleUtils.constructLocaleFromString(localeString); - } - public static String getKeyboardLayoutSetDisplayName(final InputMethodSubtype subtype) { final String layoutName = getKeyboardLayoutSetName(subtype); return getKeyboardLayoutSetDisplayName(layoutName); @@ -348,10 +341,6 @@ public final class SubtypeLocaleUtils { return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0; } - public static boolean isRtlLanguage(final RichInputMethodSubtype subtype) { - return isRtlLanguage(getSubtypeLocale(subtype)); - } - public static String getCombiningRulesExtraValue(final InputMethodSubtype subtype) { return subtype.getExtraValueOf(Constants.Subtype.ExtraValue.COMBINING_RULES); } diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 365217a60..76c7fdd6f 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -252,6 +252,9 @@ static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, } else { dictionary->getPredictions(&prevWordsInfo, &suggestionResults); } + if (DEBUG_DICT) { + suggestionResults.dumpSuggestions(); + } suggestionResults.outputSuggestions(env, outSuggestionCount, outCodePointsArray, outScoresArray, outSpaceIndicesArray, outTypesArray, outAutoCommitFirstWordConfidenceArray, inOutWeightOfLangModelVsSpatialModel); diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index e55c9eb8a..885118524 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -119,7 +119,7 @@ static inline void dumpWordInfo(const int *word, const int length, const int ran const int probability) { static char charBuf[50]; const int N = intArrayToCharArray(word, length, charBuf, NELEMS(charBuf)); - if (N > 1) { + if (N > 0) { AKLOGI("%2d [ %s ] (%d)", rank, charBuf, probability); } } diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp index 8d3f8a9f8..7a69d3ceb 100644 --- a/native/jni/src/suggest/core/dictionary/dictionary.cpp +++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp @@ -55,9 +55,6 @@ void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession suggest->getSuggestions(proximityInfo, traverseSession, xcoordinates, ycoordinates, times, pointerIds, inputCodePoints, inputSize, weightOfLangModelVsSpatialModel, outSuggestionResults); - if (DEBUG_DICT) { - outSuggestionResults->dumpSuggestions(); - } } Dictionary::NgramListenerForPrediction::NgramListenerForPrediction( diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp index 6ed65d921..4c4dfc578 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp @@ -35,23 +35,15 @@ const char *const HeaderPolicy::EXTENDED_REGION_SIZE_KEY = "EXTENDED_REGION_SIZE // count. const char *const HeaderPolicy::HAS_HISTORICAL_INFO_KEY = "HAS_HISTORICAL_INFO"; const char *const HeaderPolicy::LOCALE_KEY = "locale"; // match Java declaration -const char *const HeaderPolicy::FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY = - "FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP"; const char *const HeaderPolicy::FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY = "FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID"; -const char *const HeaderPolicy::FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY = - "FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS"; const char *const HeaderPolicy::MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_COUNT"; const char *const HeaderPolicy::MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_COUNT"; const int HeaderPolicy::DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE = 100; const float HeaderPolicy::MULTIPLE_WORD_COST_MULTIPLIER_SCALE = 100.0f; -const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP = 2; const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID = 3; -// 30 days -const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS = - 30 * 24 * 60 * 60; const int HeaderPolicy::DEFAULT_MAX_UNIGRAM_COUNT = 10000; const int HeaderPolicy::DEFAULT_MAX_BIGRAM_COUNT = 10000; diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h index daf40d4f9..bc8eaded3 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h @@ -53,15 +53,9 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { EXTENDED_REGION_SIZE_KEY, 0 /* defaultValue */)), mHasHistoricalInfoOfWords(HeaderReadWriteUtils::readBoolAttributeValue( &mAttributeMap, HAS_HISTORICAL_INFO_KEY, false /* defaultValue */)), - mForgettingCurveOccurrencesToLevelUp(HeaderReadWriteUtils::readIntAttributeValue( - &mAttributeMap, FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY, - DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP)), mForgettingCurveProbabilityValuesTableId(HeaderReadWriteUtils::readIntAttributeValue( &mAttributeMap, FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY, DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID)), - mForgettingCurveDurationToLevelDown(HeaderReadWriteUtils::readIntAttributeValue( - &mAttributeMap, FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY, - DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS)), mMaxUnigramCount(HeaderReadWriteUtils::readIntAttributeValue( &mAttributeMap, MAX_UNIGRAM_COUNT_KEY, DEFAULT_MAX_UNIGRAM_COUNT)), mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue( @@ -86,15 +80,9 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { mUnigramCount(0), mBigramCount(0), mExtendedRegionSize(0), mHasHistoricalInfoOfWords(HeaderReadWriteUtils::readBoolAttributeValue( &mAttributeMap, HAS_HISTORICAL_INFO_KEY, false /* defaultValue */)), - mForgettingCurveOccurrencesToLevelUp(HeaderReadWriteUtils::readIntAttributeValue( - &mAttributeMap, FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP_KEY, - DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP)), mForgettingCurveProbabilityValuesTableId(HeaderReadWriteUtils::readIntAttributeValue( &mAttributeMap, FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY, DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID)), - mForgettingCurveDurationToLevelDown(HeaderReadWriteUtils::readIntAttributeValue( - &mAttributeMap, FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY, - DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS)), mMaxUnigramCount(HeaderReadWriteUtils::readIntAttributeValue( &mAttributeMap, MAX_UNIGRAM_COUNT_KEY, DEFAULT_MAX_UNIGRAM_COUNT)), mMaxBigramCount(HeaderReadWriteUtils::readIntAttributeValue( @@ -113,12 +101,8 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { mUnigramCount(headerPolicy->mUnigramCount), mBigramCount(headerPolicy->mBigramCount), mExtendedRegionSize(headerPolicy->mExtendedRegionSize), mHasHistoricalInfoOfWords(headerPolicy->mHasHistoricalInfoOfWords), - mForgettingCurveOccurrencesToLevelUp( - headerPolicy->mForgettingCurveOccurrencesToLevelUp), mForgettingCurveProbabilityValuesTableId( headerPolicy->mForgettingCurveProbabilityValuesTableId), - mForgettingCurveDurationToLevelDown( - headerPolicy->mForgettingCurveDurationToLevelDown), mMaxUnigramCount(headerPolicy->mMaxUnigramCount), mMaxBigramCount(headerPolicy->mMaxBigramCount), mCodePointTable(headerPolicy->mCodePointTable) {} @@ -130,8 +114,7 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { mRequiresGermanUmlautProcessing(false), mIsDecayingDict(false), mDate(0), mLastDecayedTime(0), mUnigramCount(0), mBigramCount(0), mExtendedRegionSize(0), mHasHistoricalInfoOfWords(false), - mForgettingCurveOccurrencesToLevelUp(0), mForgettingCurveProbabilityValuesTableId(0), - mForgettingCurveDurationToLevelDown(0), mMaxUnigramCount(0), mMaxBigramCount(0), + mForgettingCurveProbabilityValuesTableId(0), mMaxUnigramCount(0), mMaxBigramCount(0), mCodePointTable(nullptr) {} ~HeaderPolicy() {} @@ -217,18 +200,10 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { return &mAttributeMap; } - AK_FORCE_INLINE int getForgettingCurveOccurrencesToLevelUp() const { - return mForgettingCurveOccurrencesToLevelUp; - } - AK_FORCE_INLINE int getForgettingCurveProbabilityValuesTableId() const { return mForgettingCurveProbabilityValuesTableId; } - AK_FORCE_INLINE int getForgettingCurveDurationToLevelDown() const { - return mForgettingCurveDurationToLevelDown; - } - AK_FORCE_INLINE int getMaxUnigramCount() const { return mMaxUnigramCount; } @@ -280,9 +255,7 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { static const char *const MAX_BIGRAM_COUNT_KEY; static const int DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE; static const float MULTIPLE_WORD_COST_MULTIPLIER_SCALE; - static const int DEFAULT_FORGETTING_CURVE_OCCURRENCES_TO_LEVEL_UP; static const int DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID; - static const int DEFAULT_FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS; static const int DEFAULT_MAX_UNIGRAM_COUNT; static const int DEFAULT_MAX_BIGRAM_COUNT; @@ -300,9 +273,7 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy { const int mBigramCount; const int mExtendedRegionSize; const bool mHasHistoricalInfoOfWords; - const int mForgettingCurveOccurrencesToLevelUp; const int mForgettingCurveProbabilityValuesTableId; - const int mForgettingCurveDurationToLevelDown; const int mMaxUnigramCount; const int mMaxBigramCount; const int *const mCodePointTable; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp index 11f7b305f..36eafa1e9 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp @@ -146,18 +146,15 @@ const WordAttributes Ver4PatriciaTriePolicy::getWordAttributes(const int probabi int Ver4PatriciaTriePolicy::getProbability(const int unigramProbability, const int bigramProbability) const { - if (mHeaderPolicy->isDecayingDict()) { - // Both probabilities are encoded. Decode them and get probability. - return ForgettingCurveUtils::getProbability(unigramProbability, bigramProbability); - } else { - if (unigramProbability == NOT_A_PROBABILITY) { - return NOT_A_PROBABILITY; - } else if (bigramProbability == NOT_A_PROBABILITY) { - return ProbabilityUtils::backoff(unigramProbability); - } else { - return bigramProbability; - } + // In the v4 format, bigramProbability is a conditional probability. + const int bigramConditionalProbability = bigramProbability; + if (unigramProbability == NOT_A_PROBABILITY) { + return NOT_A_PROBABILITY; } + if (bigramConditionalProbability == NOT_A_PROBABILITY) { + return ProbabilityUtils::backoff(unigramProbability); + } + return bigramConditionalProbability; } int Ver4PatriciaTriePolicy::getProbabilityOfWord(const WordIdArrayView prevWordIds, @@ -170,37 +167,66 @@ int Ver4PatriciaTriePolicy::getProbabilityOfWord(const WordIdArrayView prevWordI if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) { return NOT_A_PROBABILITY; } - if (!prevWordIds.empty()) { - const int bigramsPosition = getBigramsPositionOfPtNode( - getTerminalPtNodePosFromWordId(prevWordIds[0])); - BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition); - while (bigramsIt.hasNext()) { - bigramsIt.next(); - if (bigramsIt.getBigramPos() == ptNodePos - && bigramsIt.getProbability() != NOT_A_PROBABILITY) { - return getProbability(ptNodeParams.getProbability(), bigramsIt.getProbability()); - } - } + if (prevWordIds.empty()) { + return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); + } + if (prevWordIds[0] == NOT_A_WORD_ID) { return NOT_A_PROBABILITY; } - return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); + const PtNodeParams prevWordPtNodeParams = + mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(prevWordIds[0]); + if (prevWordPtNodeParams.isDeleted()) { + return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY); + } + const int bigramsPosition = mBuffers->getBigramDictContent()->getBigramListHeadPos( + prevWordPtNodeParams.getTerminalId()); + BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition); + while (bigramsIt.hasNext()) { + bigramsIt.next(); + if (bigramsIt.getBigramPos() == ptNodePos + && bigramsIt.getProbability() != NOT_A_PROBABILITY) { + const int bigramConditionalProbability = getBigramConditionalProbability( + prevWordPtNodeParams.getProbability(), bigramsIt.getProbability()); + return getProbability(ptNodeParams.getProbability(), bigramConditionalProbability); + } + } + return NOT_A_PROBABILITY; } void Ver4PatriciaTriePolicy::iterateNgramEntries(const WordIdArrayView prevWordIds, NgramListener *const listener) const { - if (prevWordIds.empty()) { + if (prevWordIds.firstOrDefault(NOT_A_DICT_POS) == NOT_A_DICT_POS) { + return; + } + const PtNodeParams prevWordPtNodeParams = + mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(prevWordIds[0]); + if (prevWordPtNodeParams.isDeleted()) { return; } - const int bigramsPosition = getBigramsPositionOfPtNode( - getTerminalPtNodePosFromWordId(prevWordIds[0])); + const int bigramsPosition = mBuffers->getBigramDictContent()->getBigramListHeadPos( + prevWordPtNodeParams.getTerminalId()); BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition); while (bigramsIt.hasNext()) { bigramsIt.next(); - listener->onVisitEntry(bigramsIt.getProbability(), + const int bigramConditionalProbability = getBigramConditionalProbability( + prevWordPtNodeParams.getProbability(), bigramsIt.getProbability()); + listener->onVisitEntry(bigramConditionalProbability, getWordIdFromTerminalPtNodePos(bigramsIt.getBigramPos())); } } +int Ver4PatriciaTriePolicy::getBigramConditionalProbability(const int prevWordUnigramProbability, + const int bigramProbability) const { + if (mHeaderPolicy->hasHistoricalInfoOfWords()) { + // Calculate conditional probability. + return std::min(MAX_PROBABILITY - prevWordUnigramProbability + bigramProbability, + MAX_PROBABILITY); + } else { + // bigramProbability is a conditional probability. + return bigramProbability; + } +} + BinaryDictionaryShortcutIterator Ver4PatriciaTriePolicy::getShortcutIterator( const int wordId) const { const int shortcutPos = getShortcutPositionOfPtNode(getTerminalPtNodePosFromWordId(wordId)); @@ -428,7 +454,10 @@ bool Ver4PatriciaTriePolicy::updateCounter(const PrevWordsInfo *const prevWordsI AKLOGE("Cannot update unigarm entry in updateCounter()."); return false; } - const NgramProperty ngramProperty(wordCodePoints.toVector(), probability, historicalInfo); + const int probabilityForNgram = prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */) + ? NOT_A_PROBABILITY : probability; + const NgramProperty ngramProperty(wordCodePoints.toVector(), probabilityForNgram, + historicalInfo); if (!addNgramEntry(prevWordsInfo, &ngramProperty)) { AKLOGE("Cannot update unigarm entry in updateCounter()."); return false; diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h index 995d7764f..b82563e61 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h @@ -174,6 +174,8 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { int getTerminalPtNodePosFromWordId(const int wordId) const; const WordAttributes getWordAttributes(const int probability, const PtNodeParams &ptNodeParams) const; + int getBigramConditionalProbability(const int prevWordUnigramProbability, + const int bigramProbability) const; }; } // namespace v402 } // namespace backward diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp index 41b109f95..036197c41 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp @@ -378,7 +378,10 @@ bool Ver4PatriciaTriePolicy::updateCounter(const PrevWordsInfo *const prevWordsI AKLOGE("Cannot update unigarm entry in updateCounter()."); return false; } - const NgramProperty ngramProperty(wordCodePoints.toVector(), probability, historicalInfo); + const int probabilityForNgram = prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */) + ? NOT_A_PROBABILITY : probability; + const NgramProperty ngramProperty(wordCodePoints.toVector(), probabilityForNgram, + historicalInfo); for (size_t i = 1; i <= prevWordsInfo->getPrevWordCount(); ++i) { const PrevWordsInfo trimmedPrevWordsInfo(prevWordsInfo->getTrimmedPrevWordsInfo(i)); if (!addNgramEntry(&trimmedPrevWordsInfo, &ngramProperty)) { diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp index af4bc186a..e5ef2abf8 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.cpp @@ -29,10 +29,14 @@ namespace latinime { const int ForgettingCurveUtils::MULTIPLIER_TWO_IN_PROBABILITY_SCALE = 8; const int ForgettingCurveUtils::DECAY_INTERVAL_SECONDS = 2 * 60 * 60; -const int ForgettingCurveUtils::MAX_LEVEL = 3; -const int ForgettingCurveUtils::MIN_VISIBLE_LEVEL = 1; -const int ForgettingCurveUtils::MAX_ELAPSED_TIME_STEP_COUNT = 15; -const int ForgettingCurveUtils::DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD = 14; +const int ForgettingCurveUtils::MAX_LEVEL = 15; +const int ForgettingCurveUtils::MIN_VISIBLE_LEVEL = 2; +const int ForgettingCurveUtils::MAX_ELAPSED_TIME_STEP_COUNT = 31; +const int ForgettingCurveUtils::DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD = 30; +const int ForgettingCurveUtils::OCCURRENCES_TO_RAISE_THE_LEVEL = 1; +// TODO: Evaluate whether this should be 7.5 days. +// 15 days +const int ForgettingCurveUtils::DURATION_TO_LOWER_THE_LEVEL_IN_SECONDS = 15 * 24 * 60 * 60; const float ForgettingCurveUtils::UNIGRAM_COUNT_HARD_LIMIT_WEIGHT = 1.2; const float ForgettingCurveUtils::BIGRAM_COUNT_HARD_LIMIT_WEIGHT = 1.2; @@ -54,19 +58,23 @@ const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityT || (originalHistoricalInfo->getLevel() == newHistoricalInfo->getLevel() && originalHistoricalInfo->getCount() < newHistoricalInfo->getCount())) { // Initial information. + int count = newHistoricalInfo->getCount(); + if (count >= OCCURRENCES_TO_RAISE_THE_LEVEL) { + const int level = clampToValidLevelRange(newHistoricalInfo->getLevel() + 1); + return HistoricalInfo(timestamp, level, 0 /* count */); + } const int level = clampToValidLevelRange(newHistoricalInfo->getLevel()); - const int count = clampToValidCountRange(newHistoricalInfo->getCount(), headerPolicy); - return HistoricalInfo(timestamp, level, count); + return HistoricalInfo(timestamp, level, clampToValidCountRange(count, headerPolicy)); } else { const int updatedCount = originalHistoricalInfo->getCount() + 1; - if (updatedCount >= headerPolicy->getForgettingCurveOccurrencesToLevelUp()) { + if (updatedCount >= OCCURRENCES_TO_RAISE_THE_LEVEL) { // The count exceeds the max value the level can be incremented. if (originalHistoricalInfo->getLevel() >= MAX_LEVEL) { // The level is already max. return HistoricalInfo(timestamp, originalHistoricalInfo->getLevel(), originalHistoricalInfo->getCount()); } else { - // Level up. + // Raise the level. return HistoricalInfo(timestamp, originalHistoricalInfo->getLevel() + 1, 0 /* count */); } @@ -79,31 +87,18 @@ const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityT /* static */ int ForgettingCurveUtils::decodeProbability( const HistoricalInfo *const historicalInfo, const HeaderPolicy *const headerPolicy) { const int elapsedTimeStepCount = getElapsedTimeStepCount(historicalInfo->getTimestamp(), - headerPolicy->getForgettingCurveDurationToLevelDown()); + DURATION_TO_LOWER_THE_LEVEL_IN_SECONDS); return sProbabilityTable.getProbability( headerPolicy->getForgettingCurveProbabilityValuesTableId(), clampToValidLevelRange(historicalInfo->getLevel()), clampToValidTimeStepCountRange(elapsedTimeStepCount)); } -/* static */ int ForgettingCurveUtils::getProbability(const int unigramProbability, - const int bigramProbability) { - if (unigramProbability == NOT_A_PROBABILITY) { - return NOT_A_PROBABILITY; - } else if (bigramProbability == NOT_A_PROBABILITY) { - return std::min(backoff(unigramProbability), MAX_PROBABILITY); - } else { - // TODO: Investigate better way to handle bigram probability. - return std::min(std::max(unigramProbability, - bigramProbability + MULTIPLIER_TWO_IN_PROBABILITY_SCALE), MAX_PROBABILITY); - } -} - /* static */ bool ForgettingCurveUtils::needsToKeep(const HistoricalInfo *const historicalInfo, const HeaderPolicy *const headerPolicy) { return historicalInfo->getLevel() > 0 || getElapsedTimeStepCount(historicalInfo->getTimestamp(), - headerPolicy->getForgettingCurveDurationToLevelDown()) + DURATION_TO_LOWER_THE_LEVEL_IN_SECONDS) < DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD; } @@ -113,14 +108,14 @@ const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityT if (originalHistoricalInfo->getTimestamp() == NOT_A_TIMESTAMP) { return HistoricalInfo(); } - const int durationToLevelDownInSeconds = headerPolicy->getForgettingCurveDurationToLevelDown(); + const int durationToLevelDownInSeconds = DURATION_TO_LOWER_THE_LEVEL_IN_SECONDS; const int elapsedTimeStep = getElapsedTimeStepCount( originalHistoricalInfo->getTimestamp(), durationToLevelDownInSeconds); if (elapsedTimeStep <= MAX_ELAPSED_TIME_STEP_COUNT) { // No need to update historical info. return *originalHistoricalInfo; } - // Level down. + // Lower the level. const int maxLevelDownAmonut = elapsedTimeStep / (MAX_ELAPSED_TIME_STEP_COUNT + 1); const int levelDownAmount = (maxLevelDownAmonut >= originalHistoricalInfo->getLevel()) ? originalHistoricalInfo->getLevel() : maxLevelDownAmonut; @@ -170,7 +165,7 @@ const ForgettingCurveUtils::ProbabilityTable ForgettingCurveUtils::sProbabilityT /* static */ int ForgettingCurveUtils::clampToValidCountRange(const int count, const HeaderPolicy *const headerPolicy) { - return std::min(std::max(count, 0), headerPolicy->getForgettingCurveOccurrencesToLevelUp() - 1); + return std::min(std::max(count, 0), OCCURRENCES_TO_RAISE_THE_LEVEL - 1); } /* static */ int ForgettingCurveUtils::clampToValidLevelRange(const int level) { @@ -187,9 +182,9 @@ const int ForgettingCurveUtils::ProbabilityTable::MODEST_PROBABILITY_TABLE_ID = const int ForgettingCurveUtils::ProbabilityTable::STRONG_PROBABILITY_TABLE_ID = 2; const int ForgettingCurveUtils::ProbabilityTable::AGGRESSIVE_PROBABILITY_TABLE_ID = 3; const int ForgettingCurveUtils::ProbabilityTable::WEAK_MAX_PROBABILITY = 127; -const int ForgettingCurveUtils::ProbabilityTable::MODEST_BASE_PROBABILITY = 32; -const int ForgettingCurveUtils::ProbabilityTable::STRONG_BASE_PROBABILITY = 35; -const int ForgettingCurveUtils::ProbabilityTable::AGGRESSIVE_BASE_PROBABILITY = 40; +const int ForgettingCurveUtils::ProbabilityTable::MODEST_BASE_PROBABILITY = 8; +const int ForgettingCurveUtils::ProbabilityTable::STRONG_BASE_PROBABILITY = 9; +const int ForgettingCurveUtils::ProbabilityTable::AGGRESSIVE_BASE_PROBABILITY = 10; ForgettingCurveUtils::ProbabilityTable::ProbabilityTable() : mTables() { @@ -202,7 +197,7 @@ ForgettingCurveUtils::ProbabilityTable::ProbabilityTable() : mTables() { const float endProbability = getBaseProbabilityForLevel(tableId, level - 1); for (int timeStepCount = 0; timeStepCount <= MAX_ELAPSED_TIME_STEP_COUNT; ++timeStepCount) { - if (level == 0) { + if (level < MIN_VISIBLE_LEVEL) { mTables[tableId][level][timeStepCount] = NOT_A_PROBABILITY; continue; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h index 10abb405a..ccbc4a98d 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h @@ -39,9 +39,6 @@ class ForgettingCurveUtils { static int decodeProbability(const HistoricalInfo *const historicalInfo, const HeaderPolicy *const headerPolicy); - static int getProbability(const int encodedUnigramProbability, - const int encodedBigramProbability); - static bool needsToKeep(const HistoricalInfo *const historicalInfo, const HeaderPolicy *const headerPolicy); @@ -101,6 +98,8 @@ class ForgettingCurveUtils { static const int MIN_VISIBLE_LEVEL; static const int MAX_ELAPSED_TIME_STEP_COUNT; static const int DISCARD_LEVEL_ZERO_ENTRY_TIME_STEP_COUNT_THRESHOLD; + static const int OCCURRENCES_TO_RAISE_THE_LEVEL; + static const int DURATION_TO_LOWER_THE_LEVEL_IN_SECONDS; static const float UNIGRAM_COUNT_HARD_LIMIT_WEIGHT; static const float BIGRAM_COUNT_HARD_LIMIT_WEIGHT; diff --git a/tests/src/com/android/inputmethod/keyboard/action/KlpActionLabelTests.java b/tests/src/com/android/inputmethod/keyboard/action/KlpActionLabelTests.java index 74343cb6a..07c604e59 100644 --- a/tests/src/com/android/inputmethod/keyboard/action/KlpActionLabelTests.java +++ b/tests/src/com/android/inputmethod/keyboard/action/KlpActionLabelTests.java @@ -131,7 +131,7 @@ public class KlpActionLabelTests extends KlpActionTestsBase { textsSet.getText("label_done_key")); final ExpectedActionKey previousKey = ExpectedActionKey.newLabelKey( textsSet.getText("label_previous_key")); - final String tag = "label=hi_ZZ system=" + systemLocale + final String tag = "label=" + subtype.getLocale() + " system=" + systemLocale + " " + SubtypeLocaleUtils.getSubtypeNameForLogging(subtype); final RunInLocale<Void> job = new RunInLocale<Void>() { @Override @@ -147,26 +147,34 @@ public class KlpActionLabelTests extends KlpActionTestsBase { public void testHinglishActionLabel() { final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); final Locale hi_ZZ = new Locale("hi", "ZZ"); - final InputMethodSubtype hinglish = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( + final InputMethodSubtype hiLatn = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( hi_ZZ.toString(), SubtypeLocaleUtils.QWERTY); + // This is a preliminary subtype and may not exist. + if (hiLatn == null) { + return; + } // An action label should be displayed in subtype's locale regardless of the system locale. - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, hi_ZZ); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.US); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.FRENCH); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.ITALIAN); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, hi_ZZ, Locale.JAPANESE); + doTestActionKeysInLocaleWithKeyboardTextsSet(hiLatn, hi_ZZ, new Locale("hi")); + doTestActionKeysInLocaleWithKeyboardTextsSet(hiLatn, hi_ZZ, Locale.US); + doTestActionKeysInLocaleWithKeyboardTextsSet(hiLatn, hi_ZZ, Locale.FRENCH); + doTestActionKeysInLocaleWithKeyboardTextsSet(hiLatn, hi_ZZ, Locale.ITALIAN); + doTestActionKeysInLocaleWithKeyboardTextsSet(hiLatn, hi_ZZ, Locale.JAPANESE); } public void testSerbianLatinActionLabel() { final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); final Locale sr_ZZ = new Locale("sr", "ZZ"); - final InputMethodSubtype hinglish = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( + final InputMethodSubtype srLatn = richImm.findSubtypeByLocaleAndKeyboardLayoutSet( sr_ZZ.toString(), "serbian_qwertz"); + // This is a preliminary subtype and may not exist. + if (srLatn == null) { + return; + } // An action label should be displayed in subtype's locale regardless of the system locale. - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, sr_ZZ, sr_ZZ); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, sr_ZZ, Locale.US); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, sr_ZZ, Locale.FRENCH); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, sr_ZZ, Locale.ITALIAN); - doTestActionKeysInLocaleWithKeyboardTextsSet(hinglish, sr_ZZ, Locale.JAPANESE); + doTestActionKeysInLocaleWithKeyboardTextsSet(srLatn, sr_ZZ, new Locale("sr")); + doTestActionKeysInLocaleWithKeyboardTextsSet(srLatn, sr_ZZ, Locale.US); + doTestActionKeysInLocaleWithKeyboardTextsSet(srLatn, sr_ZZ, Locale.FRENCH); + doTestActionKeysInLocaleWithKeyboardTextsSet(srLatn, sr_ZZ, Locale.ITALIAN); + doTestActionKeysInLocaleWithKeyboardTextsSet(srLatn, sr_ZZ, Locale.JAPANESE); } } diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/KeyboardLayoutSetSubtypesCountTests.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/KeyboardLayoutSetSubtypesCountTests.java index 6f747b377..2134eb5fe 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/KeyboardLayoutSetSubtypesCountTests.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/KeyboardLayoutSetSubtypesCountTests.java @@ -27,8 +27,8 @@ import java.util.ArrayList; @SmallTest public class KeyboardLayoutSetSubtypesCountTests extends KeyboardLayoutSetTestsBase { - private static final int NUMBER_OF_SUBTYPES = 85; - private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 50; + private static final int NUMBER_OF_SUBTYPES = 78; + private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 47; private static final int NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES = 2; @Override diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBengaliBD.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBengaliBD.java index 62625890e..c39a392eb 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBengaliBD.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsBengaliBD.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.BengaliAkkhor; import com.android.inputmethod.keyboard.layout.LayoutBase; @@ -29,7 +29,7 @@ import java.util.Locale; /** * bn_BD: Bengali (Bangladesh)/bengali_akkhor */ -@SmallTest +@Suppress public final class TestsBengaliBD extends LayoutTestsBase { private static final Locale LOCALE = new Locale("bn", "BD"); private static final LayoutBase LAYOUT = new BengaliAkkhor(new BengaliBDCustomzier(LOCALE)); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHinglish.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHinglish.java index 613b3bbc2..a8e872316 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHinglish.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHinglish.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.LayoutBase; import com.android.inputmethod.keyboard.layout.Qwerty; @@ -30,7 +30,7 @@ import java.util.Locale; /* * hi_ZZ: Hinglish/qwerty */ -@SmallTest +@Suppress public final class TestsHinglish extends LayoutTestsBase { private static final Locale LOCALE = new Locale("hi", "ZZ"); private static final LayoutBase LAYOUT = new Qwerty(new HinglishCustomizer(LOCALE)); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java index b581e4a12..18baa6152 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.LayoutBase; import com.android.inputmethod.keyboard.layout.Myanmar; @@ -26,7 +26,7 @@ import java.util.Locale; /** * my_MM: Myanmar (Myanmar)/myanmar */ -@SmallTest +@Suppress public final class TestsMyanmarMM extends LayoutTestsBase { private static final Locale LOCALE = new Locale("my", "MM"); private static final LayoutBase LAYOUT = new Myanmar(LOCALE); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatin.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatin.java index 7490d30ab..ea957e44f 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatin.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatin.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.LayoutBase; import com.android.inputmethod.keyboard.layout.SerbianQwertz; @@ -27,7 +27,7 @@ import java.util.Locale; /** * sr_ZZ: Serbian (Latin)/serbian_qwertz */ -@SmallTest +@Suppress public final class TestsSerbianLatin extends LayoutTestsBase { private static final Locale LOCALE = new Locale("sr", "ZZ"); private static final LayoutBase LAYOUT = new SerbianQwertz(new SerbianLatinCustomizer(LOCALE)); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatinQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatinQwerty.java index 6d9351c9d..a1984735d 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatinQwerty.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSerbianLatinQwerty.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.LayoutBase; import com.android.inputmethod.keyboard.layout.Qwerty; @@ -29,7 +29,7 @@ import java.util.Locale; /** * sr_ZZ: Serbian (Latin)/qwerty */ -@SmallTest +@Suppress public final class TestsSerbianLatinQwerty extends LayoutTestsBase { private static final Locale LOCALE = new Locale("sr", "ZZ"); private static final LayoutBase LAYOUT = new Qwerty(new SerbianLatinQwertyCustomizer(LOCALE)); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbek.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbek.java index fd12a6a82..169de1f31 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbek.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbek.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.LayoutBase; import com.android.inputmethod.keyboard.layout.Uzbek; @@ -27,7 +27,7 @@ import java.util.Locale; /** * uz_UZ: Uzbek (Uzbekistan)/uzbek */ -@SmallTest +@Suppress public final class TestsUzbek extends LayoutTestsBase { private static final Locale LOCALE = new Locale("uz", "UZ"); private static final LayoutBase LAYOUT = new Uzbek(new UzbekCustomizer(LOCALE)); diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbekQwerty.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbekQwerty.java index 4c33a8cc1..c210da163 100644 --- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbekQwerty.java +++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsUzbekQwerty.java @@ -16,7 +16,7 @@ package com.android.inputmethod.keyboard.layout.tests; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; import com.android.inputmethod.keyboard.layout.LayoutBase; import com.android.inputmethod.keyboard.layout.Qwerty; @@ -28,7 +28,7 @@ import java.util.Locale; /** * uz_UZ: Uzbek (Uzbekistan)/qwerty */ -@SmallTest +@Suppress public final class TestsUzbekQwerty extends LayoutTestsBase { private static final Locale LOCALE = new Locale("uz", "UZ"); private static final LayoutBase LAYOUT = new Qwerty(new UzbekQwertyCustomizer(LOCALE)); diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index c3c2bb2fd..0e58b7211 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -611,17 +611,23 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { mCurrentTime); final NgramContext beginningOfSentenceContext = NgramContext.BEGINNING_OF_SENTENCE; onInputWordWithBeginningOfSentenceContext(binaryDictionary, "aaa", true /* isValidWord */); + assertFalse(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa")); + onInputWordWithBeginningOfSentenceContext(binaryDictionary, "aaa", true /* isValidWord */); assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa")); onInputWordWithBeginningOfSentenceContext(binaryDictionary, "aaa", true /* isValidWord */); onInputWordWithBeginningOfSentenceContext(binaryDictionary, "bbb", true /* isValidWord */); + assertFalse(binaryDictionary.isValidNgram(beginningOfSentenceContext, "bbb")); onInputWordWithBeginningOfSentenceContext(binaryDictionary, "bbb", true /* isValidWord */); assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa")); assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "bbb")); forcePassingLongTime(binaryDictionary); assertFalse(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa")); assertFalse(binaryDictionary.isValidNgram(beginningOfSentenceContext, "bbb")); - onInputWordWithBeginningOfSentenceContext(binaryDictionary, "aaa", true /* isValidWord */); + assertFalse(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa")); + onInputWordWithBeginningOfSentenceContext(binaryDictionary, "aaa", true /* isValidWord */); + onInputWordWithBeginningOfSentenceContext(binaryDictionary, "bbb", true /* isValidWord */); + assertFalse(binaryDictionary.isValidNgram(beginningOfSentenceContext, "bbb")); onInputWordWithBeginningOfSentenceContext(binaryDictionary, "bbb", true /* isValidWord */); assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "aaa")); assertTrue(binaryDictionary.isValidNgram(beginningOfSentenceContext, "bbb")); diff --git a/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java index 565fadb2a..011309942 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java @@ -42,8 +42,9 @@ public class ContextualDictionaryTests extends AndroidTestCase { final ArrayList<String> dictTypes = new ArrayList<>(); dictTypes.add(Dictionary.TYPE_CONTEXTUAL); final DictionaryFacilitator dictionaryFacilitator = new DictionaryFacilitator(); - dictionaryFacilitator.resetDictionariesForTesting(getContext(), LOCALE_EN_US, dictTypes, - new HashMap<String, File>(), new HashMap<String, Map<String, String>>()); + dictionaryFacilitator.resetDictionariesForTesting(getContext(), + new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(), + new HashMap<String, Map<String, String>>()); return dictionaryFacilitator; } diff --git a/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java index 4e7e8140a..afabbbd38 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java @@ -55,8 +55,9 @@ public class PersonalizationDictionaryTests extends AndroidTestCase { dictTypes.add(Dictionary.TYPE_MAIN); dictTypes.add(Dictionary.TYPE_PERSONALIZATION); final DictionaryFacilitator dictionaryFacilitator = new DictionaryFacilitator(getContext()); - dictionaryFacilitator.resetDictionariesForTesting(getContext(), LOCALE_EN_US, dictTypes, - new HashMap<String, File>(), new HashMap<String, Map<String, String>>()); + dictionaryFacilitator.resetDictionariesForTesting(getContext(), + new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(), + new HashMap<String, Map<String, String>>()); // Set subtypes. RichInputMethodManager.init(getContext()); final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java index b766ab2e7..e6131cf65 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java @@ -45,7 +45,6 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { RichInputMethodSubtype FR_CH; RichInputMethodSubtype DE; RichInputMethodSubtype DE_CH; - RichInputMethodSubtype HI_ZZ; RichInputMethodSubtype ZZ; RichInputMethodSubtype DE_QWERTY; RichInputMethodSubtype FR_QWERTZ; @@ -55,6 +54,9 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { RichInputMethodSubtype ZZ_AZERTY; RichInputMethodSubtype ZZ_PC; + // This is a preliminary subtype and may not exist. + RichInputMethodSubtype HI_LATN; + @Override protected void setUp() throws Exception { super.setUp(); @@ -87,8 +89,6 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { Locale.GERMAN.toString(), "qwertz")); DE_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( "de_CH", "swiss")); - HI_ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - "hi_ZZ", "qwerty")); ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty")); DE_QWERTY = new RichInputMethodSubtype( @@ -112,6 +112,12 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { ZZ_PC = new RichInputMethodSubtype( AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty")); + + final InputMethodSubtype hiLatn = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( + "hi_ZZ", "qwerty"); + if (hiLatn != null) { + HI_LATN = new RichInputMethodSubtype(hiLatn); + } } public void testAllFullDisplayNameForSpacebar() { @@ -119,12 +125,17 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { final String subtypeName = SubtypeLocaleUtils .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); final String spacebarText = subtype.getFullDisplayName(); - final String languageName = SubtypeLocaleUtils - .getSubtypeLocaleDisplayName(subtype.getLocale()); - if (subtype.isNoLanguage()) { - assertFalse(subtypeName, spacebarText.contains(languageName)); + final Locale[] locales = subtype.getLocales(); + if (1 == locales.length) { + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayName(locales[0].toString()); + if (subtype.isNoLanguage()) { + assertFalse(subtypeName, spacebarText.contains(languageName)); + } else { + assertTrue(subtypeName, spacebarText.contains(languageName)); + } } else { - assertTrue(subtypeName, spacebarText.contains(languageName)); + // TODO: test multi-lingual subtype spacebar display } } } @@ -133,8 +144,14 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { for (final RichInputMethodSubtype subtype : mSubtypesList) { final String subtypeName = SubtypeLocaleUtils .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); + final Locale[] locales = subtype.getLocales(); + if (locales.length > 1) { + // TODO: test multi-lingual subtype spacebar display + continue; + } + final Locale locale = locales[0]; if (SubtypeLocaleUtils.sExceptionalLocaleDisplayedInRootLocale.contains( - subtype.getLocale())) { + locale.toString())) { // Skip test because the language part of this locale string doesn't represent // the locale to be displayed on the spacebar (for example hi_ZZ and Hinglish). continue; @@ -144,7 +161,6 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals(subtypeName, SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName( subtype.getRawSubtype()), spacebarText); } else { - final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); assertEquals(subtypeName, SubtypeLocaleUtils.getSubtypeLocaleDisplayName(locale.getLanguage()), spacebarText); @@ -182,8 +198,11 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "Français (Suisse)", FR_CH.getFullDisplayName()); assertEquals("de", "Deutsch", DE.getFullDisplayName()); assertEquals("de_CH", "Deutsch (Schweiz)", DE_CH.getFullDisplayName()); - assertEquals("hi_ZZ", "Hinglish", HI_ZZ.getFullDisplayName()); assertEquals("zz", "QWERTY", ZZ.getFullDisplayName()); + // This is a preliminary subtype and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "Hinglish", HI_LATN.getFullDisplayName()); + } assertEquals("en_US", "English", EN_US.getMiddleDisplayName()); assertEquals("en_GB", "English", EN_GB.getMiddleDisplayName()); @@ -193,8 +212,11 @@ public class SpacebarLanguageUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "Français", FR_CH.getMiddleDisplayName()); assertEquals("de", "Deutsch", DE.getMiddleDisplayName()); assertEquals("de_CH", "Deutsch", DE_CH.getMiddleDisplayName()); - assertEquals("hi_ZZ", "Hinglish", HI_ZZ.getMiddleDisplayName()); assertEquals("zz", "QWERTY", ZZ.getMiddleDisplayName()); + // This is a preliminary subtype and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "Hinglish", HI_LATN.getMiddleDisplayName()); + } return null; } }; diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java index c095e6831..dfc3fecfd 100644 --- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java @@ -45,7 +45,6 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype FR_CH; InputMethodSubtype DE; InputMethodSubtype DE_CH; - InputMethodSubtype HI_ZZ; InputMethodSubtype ZZ; InputMethodSubtype DE_QWERTY; InputMethodSubtype FR_QWERTZ; @@ -55,6 +54,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { InputMethodSubtype ZZ_AZERTY; InputMethodSubtype ZZ_PC; + // This is a preliminary subtype and may not exist. + InputMethodSubtype HI_LATN; + @Override protected void setUp() throws Exception { super.setUp(); @@ -87,8 +89,6 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { Locale.GERMAN.toString(), "qwertz"); DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( "de_CH", "swiss"); - HI_ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( - "hi_ZZ", "qwerty"); ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"); DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( @@ -105,20 +105,27 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.NO_LANGUAGE, "azerty"); ZZ_PC = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype( SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty"); + + HI_LATN = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet("hi_ZZ", "qwerty"); } public void testAllFullDisplayName() { for (final RichInputMethodSubtype subtype : mSubtypesList) { final String subtypeName = SubtypeLocaleUtils .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype()); - if (subtype.isNoLanguage()) { - final String layoutName = SubtypeLocaleUtils - .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype()); - assertTrue(subtypeName, subtypeName.contains(layoutName)); + final Locale[] locales = subtype.getLocales(); + if (1 == locales.length) { + if (subtype.isNoLanguage()) { + final String layoutName = SubtypeLocaleUtils + .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype()); + assertTrue(subtypeName, subtypeName.contains(layoutName)); + } else { + final String languageName = SubtypeLocaleUtils + .getSubtypeLocaleDisplayNameInSystemLocale(locales[0].toString()); + assertTrue(subtypeName, subtypeName.contains(languageName)); + } } else { - final String languageName = SubtypeLocaleUtils - .getSubtypeLocaleDisplayNameInSystemLocale(subtype.getLocale()); - assertTrue(subtypeName, subtypeName.contains(languageName)); + // TODO: test multi-lingual subtype spacebar display } } } @@ -132,8 +139,11 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { assertEquals("fr_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_CH)); assertEquals("de", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE)); assertEquals("de_CH", "swiss", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_CH)); - assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_ZZ)); assertEquals("zz", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(ZZ)); + // This is a preliminary subtype and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(HI_LATN)); + } assertEquals("de qwerty", "qwerty", SubtypeLocaleUtils.getKeyboardLayoutSetName(DE_QWERTY)); assertEquals("fr qwertz", "qwertz", SubtypeLocaleUtils.getKeyboardLayoutSetName(FR_QWERTZ)); @@ -188,10 +198,13 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "German (Switzerland)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); - assertEquals("hi_ZZ", "Hinglish", - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_ZZ)); assertEquals("zz", "Alphabet (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); + // This is a preliminary subtype and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "Hinglish", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); + } return null; } }; @@ -263,10 +276,13 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE)); assertEquals("de_CH", "Allemand (Suisse)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(DE_CH)); - assertEquals("hi_ZZ", "Hindi/Anglais", - SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_ZZ)); assertEquals("zz", "Alphabet latin (QWERTY)", SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(ZZ)); + // This is a preliminary subtype and may not exist. + if (HI_LATN != null) { + assertEquals("hi_ZZ", "Hindi/Anglais", + SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(HI_LATN)); + } return null; } }; @@ -315,9 +331,9 @@ public class SubtypeLocaleUtilsTests extends AndroidTestCase { .getSubtypeDisplayNameInSystemLocale(rawSubtype); if (rawSubtype.equals(ARABIC) || rawSubtype.equals(FARSI) || rawSubtype.equals(HEBREW)) { - assertTrue(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); + assertTrue(subtypeName, subtype.isRtlSubtype()); } else { - assertFalse(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype)); + assertFalse(subtypeName, subtype.isRtlSubtype()); } } } diff --git a/tools/dicttool/compat/android/util/Pair.java b/tools/dicttool/compat/android/util/Pair.java index 5bf34848d..ab6096ee3 100644 --- a/tools/dicttool/compat/android/util/Pair.java +++ b/tools/dicttool/compat/android/util/Pair.java @@ -17,6 +17,7 @@ package android.util; import java.util.Arrays; +import java.util.Objects; public class Pair<T1, T2> { public final T1 mFirst; @@ -29,7 +30,8 @@ public class Pair<T1, T2> { @Override public int hashCode() { - return Arrays.hashCode(new Object[] { mFirst, mSecond }); + return (mFirst == null ? 0 : mFirst.hashCode()) + ^ (mSecond == null ? 0 : mSecond.hashCode()); } @Override @@ -37,7 +39,6 @@ public class Pair<T1, T2> { if (o == this) return true; if (!(o instanceof Pair)) return false; Pair<?, ?> p = (Pair<?, ?>)o; - return ((mFirst == null && p.mFirst == null) || mFirst.equals(p.mFirst)) - && ((mSecond == null && p.mSecond == null) || mSecond.equals(p.mSecond)); + return Objects.equals(mFirst, p.mFirst) && Objects.equals(mSecond, p.mSecond); } } |