diff options
24 files changed, 263 insertions, 112 deletions
diff --git a/dictionaries/ru_wordlist.combined.gz b/dictionaries/ru_wordlist.combined.gz Binary files differindex 253c51506..86f95061e 100644 --- a/dictionaries/ru_wordlist.combined.gz +++ b/dictionaries/ru_wordlist.combined.gz diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml index 17d11c01d..22733941c 100644 --- a/java/AndroidManifest.xml +++ b/java/AndroidManifest.xml @@ -29,13 +29,13 @@ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> - <application android:label="@string/aosp_android_keyboard_ime_name" + <application android:label="@string/english_ime_name" android:icon="@mipmap/ic_ime_settings" android:killAfterRestore="false" android:supportsRtl="true"> <service android:name="LatinIME" - android:label="@string/aosp_android_keyboard_ime_name" + android:label="@string/english_ime_name" android:permission="android.permission.BIND_INPUT_METHOD"> <intent-filter> <action android:name="android.view.InputMethod" /> @@ -44,7 +44,7 @@ </service> <service android:name=".spellcheck.AndroidSpellCheckerService" - android:label="@string/aosp_spell_checker_service_name" + android:label="@string/spell_checker_service_name" android:permission="android.permission.BIND_TEXT_SERVICE"> <intent-filter> <action android:name="android.service.textservice.SpellCheckerService" /> @@ -53,7 +53,7 @@ </service> <activity android:name=".setup.SetupActivity" - android:label="@string/aosp_android_keyboard_ime_name" + android:label="@string/english_ime_name" android:icon="@drawable/ic_setup_wizard"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -69,7 +69,7 @@ </intent-filter> </receiver> - <activity android:name="SettingsActivity" android:label="@string/aosp_android_keyboard_ime_settings" + <activity android:name="SettingsActivity" android:label="@string/english_ime_settings" android:uiOptions="splitActionBarWhenNarrow"> <intent-filter> <action android:name="android.intent.action.MAIN" /> @@ -77,7 +77,7 @@ </activity> <activity android:name="com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsActivity" - android:label="@string/aosp_android_spell_checker_service_settings"> + android:label="@string/android_spell_checker_settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> diff --git a/java/res/layout/user_dictionary_item.xml b/java/res/layout/user_dictionary_item.xml index 3062ed89a..56bad7743 100644 --- a/java/res/layout/user_dictionary_item.xml +++ b/java/res/layout/user_dictionary_item.xml @@ -13,40 +13,39 @@ See the License for the specific language governing permissions and limitations under the License. --> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeight" + android:background="?android:attr/selectableItemBackground" android:gravity="center_vertical" - android:paddingEnd="?android:attr/scrollbarSize" - android:background="?android:attr/selectableItemBackground" > - - <RelativeLayout android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="15dip" - android:layout_marginEnd="6dip" - android:layout_marginTop="6dip" - android:layout_marginBottom="6dip" - android:layout_weight="1"> - - <TextView android:id="@+android:id/text1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceMedium" - android:ellipsize="marquee" - android:fadingEdge="horizontal" /> - - <TextView android:id="@+android:id/text2" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@android:id/text1" - android:layout_alignStart="@android:id/text1" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?android:attr/textColorSecondary" - android:maxLines="1" /> - - </RelativeLayout> + android:minHeight="?android:attr/listPreferredItemHeight" + android:paddingEnd="?android:attr/scrollbarSize" > + + <RelativeLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="6dip" + android:layout_weight="1" > + + <TextView + android:id="@+android:id/text1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView + android:id="@+android:id/text2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignStart="@android:id/text1" + android:layout_below="@android:id/text1" + android:maxLines="1" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorSecondary" + android:visibility="gone" /> + </RelativeLayout> </LinearLayout> diff --git a/java/res/raw/main_ru.dict b/java/res/raw/main_ru.dict Binary files differindex 9fd613343..9bb780534 100644 --- a/java/res/raw/main_ru.dict +++ b/java/res/raw/main_ru.dict diff --git a/java/res/values/config.xml b/java/res/values/config.xml index f2e76bd29..5b11e0711 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -75,6 +75,7 @@ <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if false --> <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool> + <bool name="config_block_potentially_offensive">true</bool> <integer name="config_gesture_floating_preview_text_linger_timeout">200</integer> <integer name="config_gesture_preview_trail_fadeout_start_delay">100</integer> <integer name="config_gesture_preview_trail_fadeout_duration">800</integer> diff --git a/java/res/values/strings-appname.xml b/java/res/values/strings-appname.xml new file mode 100644 index 000000000..46d8c44ac --- /dev/null +++ b/java/res/values/strings-appname.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2013, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<resources> + <!-- Application name for opensource Android keyboard. AOSP(Android Open Source Project) should not be translated. + This resource should be copied from msgid="8250992613616792321" --> + <string name="english_ime_name">Android Keyboard (AOSP)</string> + + <!-- Name of Android spell checker service. AOSP(Android Open Source Project) should not be translated. + This resource should be copied from msgid="511950477199948048" --> + <string name="spell_checker_service_name">Android Spell Checker (AOSP)</string> + + <!-- Title for Android Keyboard settings screen. AOSP(Android Open Source Project) should not be translated. + This resource should be copied from msgid="423615877174850267" --> + <string name="english_ime_settings">Android Keyboard Settings (AOSP)</string> + + <!-- Title for the spell checking service settings screen. AOSP(Android Open Source Project) should not be translated. + This resource should be copied from msgid="2970535894327288421" --> + <string name="android_spell_checker_settings">Android Spell Checker Settings (AOSP)</string> +</resources> diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 14839397a..a5567daa7 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -18,18 +18,6 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Application name for opensource Android keyboard. AOSP(Android Open Source Project) should not be translated. --> - <string name="aosp_android_keyboard_ime_name">Android Keyboard (AOSP)</string> - - <!-- Title for Android Keyboard settings screen. AOSP(Android Open Source Project) should not be translated. --> - <string name="aosp_android_keyboard_ime_settings">Android Keyboard Settings (AOSP)</string> - - <!-- Name of Android spell checker service. AOSP(Android Open Source Project) should not be translated. --> - <string name="aosp_spell_checker_service_name">Android Spell Checker (AOSP)</string> - - <!-- Title for the spell checking service settings screen. AOSP(Android Open Source Project) should not be translated. --> - <string name="aosp_android_spell_checker_service_settings">Android Spell Checker Settings (AOSP)</string> - <!-- Title for Latin keyboard input options dialog [CHAR LIMIT=25] --> <string name="english_ime_input_options">Input options</string> @@ -123,6 +111,11 @@ <string name="prefs_suggestion_visibility_show_only_portrait_name">Show in portrait mode</string> <string name="prefs_suggestion_visibility_hide_name">Always hide</string> + <!-- Option to block potentially offensive words to be shown [CHAR_LIMIT=30] --> + <string name="prefs_block_potentially_offensive_title">Block offensive words</string> + <!-- Summary for option to block potentially offensive words to be shown [CHAR_LIMIT=80 (two lines) or 40 (fits on one line, preferable)] --> + <string name="prefs_block_potentially_offensive_summary">Do not suggest potentially offensive words</string> + <!-- Option to decide the auto correction threshold score --> <!-- Option to enable auto correction [CHAR LIMIT=20]--> <string name="auto_correction">Auto-correction</string> diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 436e080f7..dad7e2064 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -94,8 +94,10 @@ <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item> <item name="languageOnSpacebarFinalAlpha">@integer/config_language_on_spacebar_final_alpha</item> <item name="languageOnSpacebarFadeoutAnimator">@anim/language_on_spacebar_fadeout</item> + <!-- Remove animations for now because it could drain a non-negligible amount of battery while typing. <item name="altCodeKeyWhileTypingFadeoutAnimator">@anim/alt_code_key_while_typing_fadeout</item> <item name="altCodeKeyWhileTypingFadeinAnimator">@anim/alt_code_key_while_typing_fadein</item> + --> <!-- Common attributes of MainKeyboardView for gesture typing detection and recognition --> <item name="gestureFloatingPreviewTextLingerTimeout">@integer/config_gesture_floating_preview_text_linger_timeout</item> <item name="gestureStaticTimeThresholdAfterFastTyping">@integer/config_gesture_static_time_threshold_after_fast_typing</item> diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index eea90f94b..51e3420e9 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -69,6 +69,12 @@ android:value="@string/dictionary_pack_client_id" /> </intent> </PreferenceScreen> + <CheckBoxPreference + android:key="pref_key_block_potentially_offensive" + android:title="@string/prefs_block_potentially_offensive_title" + android:summary="@string/prefs_block_potentially_offensive_summary" + android:persistent="true" + android:defaultValue="@bool/config_block_potentially_offensive" /> <ListPreference android:key="auto_correction_threshold" android:title="@string/auto_correction" diff --git a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java index ff6561c58..a0d76415c 100644 --- a/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java +++ b/java/src/com/android/inputmethod/compat/UserDictionaryCompatUtils.java @@ -28,6 +28,7 @@ public final class UserDictionaryCompatUtils { private static final Method METHOD_addWord = CompatUtils.getMethod(Words.class, "addWord", Context.class, String.class, Integer.TYPE, String.class, Locale.class); + @SuppressWarnings("deprecation") public static void addWord(final Context context, final String word, final int freq, final String shortcut, final Locale locale) { if (hasNewerAddWord()) { @@ -39,13 +40,18 @@ public final class UserDictionaryCompatUtils { if (null == locale) { localeType = Words.LOCALE_TYPE_ALL; } else { - localeType = Words.LOCALE_TYPE_CURRENT; + final Locale currentLocale = context.getResources().getConfiguration().locale; + if (locale.equals(currentLocale)) { + localeType = Words.LOCALE_TYPE_CURRENT; + } else { + localeType = Words.LOCALE_TYPE_ALL; + } } Words.addWord(context, word, freq, localeType); } } - private static final boolean hasNewerAddWord() { + public static final boolean hasNewerAddWord() { return null != METHOD_addWord; } } diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java index a9d799218..bf2230553 100644 --- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java +++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java @@ -483,13 +483,14 @@ public final class ActionBatch { if (MetadataDbHelper.STATUS_INSTALLED == status || MetadataDbHelper.STATUS_DISABLED == status || MetadataDbHelper.STATUS_DELETING == status) { - // If it is installed or disabled, then we cannot remove the entry lest the user - // lose the ability to delete the file or otherwise administrate it. We will thus - // leave it as is, but remove the URI from the database since it is not supposed to - // be accessible any more. + // If it is installed or disabled, we need to mark it as deleted so that LatinIME + // will remove it next time it enquires for dictionaries. // If it is deleting and we don't have a new version, then we have to wait until - // Android Keyboard actually has deleted it before we can remove its metadata. + // LatinIME actually has deleted it before we can remove its metadata. + // In both cases, remove the URI from the database since it is not supposed to + // be accessible any more. values.put(MetadataDbHelper.REMOTE_FILENAME_COLUMN, ""); + values.put(MetadataDbHelper.STATUS_COLUMN, MetadataDbHelper.STATUS_DELETING); db.update(MetadataDbHelper.METADATA_TABLE_NAME, values, MetadataDbHelper.WORDLISTID_COLUMN + " = ? AND " + MetadataDbHelper.VERSION_COLUMN + " = ?", diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 454469ce7..a0ac47535 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -333,6 +333,10 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private static void cancelAndStartAnimators(final ObjectAnimator animatorToCancel, final ObjectAnimator animatorToStart) { + if (animatorToCancel == null || animatorToStart == null) { + // TODO: Stop using null as a no-operation animator. + return; + } float startFraction = 0.0f; if (animatorToCancel.isStarted()) { animatorToCancel.cancel(); @@ -366,7 +370,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack // When user hits the space or the enter key, just cancel the while-typing timer. final int typedCode = typedKey.mCode; if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { - startWhileTypingFadeinAnimation(keyboardView); + if (isTyping) { + startWhileTypingFadeinAnimation(keyboardView); + } return; } @@ -581,6 +587,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack private ObjectAnimator loadObjectAnimator(final int resId, final Object target) { if (resId == 0) { + // TODO: Stop returning null. return null; } final ObjectAnimator animator = (ObjectAnimator)AnimatorInflater.loadAnimator( @@ -609,8 +616,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @ExternallyReferenced public void setAltCodeKeyWhileTypingAnimAlpha(final int alpha) { + if (mAltCodeKeyWhileTypingAnimAlpha == alpha) { + return; + } + // Update the visual of alt-code-key-while-typing. mAltCodeKeyWhileTypingAnimAlpha = alpha; - updateAltCodeKeyWhileTyping(); + final Keyboard keyboard = getKeyboard(); + if (keyboard == null) { + return; + } + for (final Key key : keyboard.mAltCodeKeysWhileTyping) { + invalidateKey(key); + } } public void setKeyboardActionListener(final KeyboardActionListener listener) { @@ -1277,16 +1294,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack invalidateKey(shortcutKey); } - private void updateAltCodeKeyWhileTyping() { - final Keyboard keyboard = getKeyboard(); - if (keyboard == null) { - return; - } - for (final Key key : keyboard.mAltCodeKeysWhileTyping) { - invalidateKey(key); - } - } - public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, final boolean needsToDisplayLanguage, final boolean hasMultipleEnabledIMEsOrSubtypes) { mNeedsToDisplayLanguage = needsToDisplayLanguage; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 03f7d1c10..c8c7bb456 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -139,6 +139,8 @@ public final class BinaryDictionary extends Dictionary { inputSize, 0 /* commitPoint */, isGesture, prevWordCodePointArray, mUseFullEditDistance, mOutputCodePoints, mOutputScores, mSpaceIndices, mOutputTypes); + final boolean blockPotentiallyOffensive = + Settings.getInstance().getBlockPotentiallyOffensive(); final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); for (int j = 0; j < count; ++j) { final int start = j * MAX_WORD_LENGTH; @@ -148,10 +150,11 @@ public final class BinaryDictionary extends Dictionary { } if (len > 0) { final int flags = mOutputTypes[j] & SuggestedWordInfo.KIND_MASK_FLAGS; - if (0 != (flags & SuggestedWordInfo.KIND_FLAG_POSSIBLY_OFFENSIVE) + if (blockPotentiallyOffensive + && 0 != (flags & SuggestedWordInfo.KIND_FLAG_POSSIBLY_OFFENSIVE) && 0 == (flags & SuggestedWordInfo.KIND_FLAG_EXACT_MATCH)) { - // If the word is possibly offensive, we don't output it unless it's also - // an exact match. + // If we block potentially offensive words, and if the word is possibly + // offensive, then we don't output it unless it's also an exact match. continue; } final int kind = mOutputTypes[j] & SuggestedWordInfo.KIND_MASK_KIND; diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 22ec01558..9fefb58a6 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -47,6 +47,8 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = "pref_key_use_double_space_period"; + public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE = + "pref_key_block_potentially_offensive"; public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY = "pref_show_language_switch_key"; public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST = @@ -144,6 +146,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return mCurrentLocale; } + public boolean getBlockPotentiallyOffensive() { + return mSettingsValues.mBlockPotentiallyOffensive; + } + // Accessed from the settings interface, hence public public static boolean readKeypressSoundEnabled(final SharedPreferences prefs, final Resources res) { @@ -165,6 +171,12 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } + public static boolean readBlockPotentiallyOffensive(final SharedPreferences prefs, + final Resources res) { + return prefs.getBoolean(Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE, + res.getBoolean(R.bool.config_block_potentially_offensive)); + } + public static boolean readFromBuildConfigIfGestureInputEnabled(final Resources res) { return res.getBoolean(R.bool.config_gesture_input_enabled_by_build_config); } diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java index c78064b23..830cae9b8 100644 --- a/java/src/com/android/inputmethod/latin/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -25,7 +25,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.media.AudioManager; -import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.ListPreference; @@ -46,7 +45,7 @@ import com.android.inputmethodcommon.InputMethodSettingsFragment; public final class SettingsFragment extends InputMethodSettingsFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private static final boolean DBG_USE_INTERNAL_USER_SETTINGS = false; + private static final boolean DBG_USE_INTERNAL_USER_DICTIONARY_SETTINGS = false; private ListPreference mVoicePreference; private ListPreference mShowCorrectionSuggestionsPreference; @@ -202,13 +201,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment final Intent editPersonalDictionaryIntent = editPersonalDictionary.getIntent(); final ResolveInfo ri = context.getPackageManager().resolveActivity( editPersonalDictionaryIntent, PackageManager.MATCH_DEFAULT_ONLY); - if (DBG_USE_INTERNAL_USER_SETTINGS || ri == null) { - // TODO: Support ICS - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - updateUserDictionaryPreference(editPersonalDictionary); - } else { - removePreference(Settings.PREF_EDIT_PERSONAL_DICTIONARY, getPreferenceScreen()); - } + if (DBG_USE_INTERNAL_USER_DICTIONARY_SETTINGS || ri == null) { + updateUserDictionaryPreference(editPersonalDictionary); } if (!Settings.readFromBuildConfigIfGestureInputEnabled(res)) { diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 838863c71..615b2dfab 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -57,6 +57,7 @@ public final class SettingsValues { public final boolean mShowsLanguageSwitchKey; public final boolean mUseContactsDict; public final boolean mUseDoubleSpacePeriod; + public final boolean mBlockPotentiallyOffensive; // Use bigrams to predict the next word when there is no input for it yet public final boolean mBigramPredictionEnabled; public final boolean mGestureInputEnabled; @@ -126,6 +127,7 @@ public final class SettingsValues { mShowsLanguageSwitchKey = Settings.readShowsLanguageSwitchKey(prefs); mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); + mBlockPotentiallyOffensive = Settings.readBlockPotentiallyOffensive(prefs, res); mAutoCorrectEnabled = Settings.readAutoCorrectEnabled(autoCorrectionThresholdRawValue, res); mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java index 72a485287..651fea6ab 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java @@ -244,8 +244,7 @@ public final class SetupActivity extends Activity implements View.OnClickListene final Intent intent = new Intent(); intent.setClass(this, SettingsActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED - | Intent.FLAG_ACTIVITY_CLEAR_TOP - | Intent.FLAG_ACTIVITY_NO_HISTORY); + | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); } diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java index f0dc526e4..2b6fda381 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin.userdictionary; +import com.android.inputmethod.compat.UserDictionaryCompatUtils; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; @@ -68,18 +69,28 @@ public class UserDictionaryAddWordContents { /* package */ UserDictionaryAddWordContents(final View view, final Bundle args) { mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text); mShortcutEditText = (EditText)view.findViewById(R.id.user_dictionary_add_shortcut); + if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) { + mShortcutEditText.setVisibility(View.GONE); + view.findViewById(R.id.user_dictionary_add_shortcut_label).setVisibility(View.GONE); + } final String word = args.getString(EXTRA_WORD); if (null != word) { mWordEditText.setText(word); mWordEditText.setSelection(word.length()); } - final String shortcut = args.getString(EXTRA_SHORTCUT); - if (null != shortcut && null != mShortcutEditText) { - mShortcutEditText.setText(shortcut); + final String shortcut; + if (UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) { + shortcut = args.getString(EXTRA_SHORTCUT); + if (null != shortcut && null != mShortcutEditText) { + mShortcutEditText.setText(shortcut); + } + mOldShortcut = args.getString(EXTRA_SHORTCUT); + } else { + shortcut = null; + mOldShortcut = null; } mMode = args.getInt(EXTRA_MODE); // default return value for #getInt() is 0 = MODE_EDIT mOldWord = args.getString(EXTRA_WORD); - mOldShortcut = args.getString(EXTRA_SHORTCUT); updateLocale(args.getString(EXTRA_LOCALE)); } @@ -110,7 +121,8 @@ public class UserDictionaryAddWordContents { // If we are in add mode, nothing was added, so we don't need to do anything. } - /* package */ int apply(final Context context, final Bundle outParameters) { + /* package */ + int apply(final Context context, final Bundle outParameters) { if (null != outParameters) saveStateIntoBundle(outParameters); final ContentResolver resolver = context.getContentResolver(); if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) { @@ -119,7 +131,9 @@ public class UserDictionaryAddWordContents { } final String newWord = mWordEditText.getText().toString(); final String newShortcut; - if (null == mShortcutEditText) { + if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) { + newShortcut = null; + } else if (null == mShortcutEditText) { newShortcut = null; } else { final String tmpShortcut = mShortcutEditText.getText().toString(); @@ -150,9 +164,9 @@ public class UserDictionaryAddWordContents { // In this class we use the empty string to represent 'all locales' and mLocale cannot // be null. However the addWord method takes null to mean 'all locales'. - UserDictionary.Words.addWord(context, newWord.toString(), - FREQUENCY_FOR_USER_DICTIONARY_ADDS, newShortcut, - TextUtils.isEmpty(mLocale) ? null : LocaleUtils.constructLocaleFromString(mLocale)); + UserDictionaryCompatUtils.addWord(context, newWord.toString(), + FREQUENCY_FOR_USER_DICTIONARY_ADDS, newShortcut, TextUtils.isEmpty(mLocale) ? + null : LocaleUtils.constructLocaleFromString(mLocale)); return CODE_WORD_ADDED; } diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java index 7970a365c..5f4c44636 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java @@ -49,7 +49,8 @@ import java.util.Locale; public class UserDictionaryAddWordFragment extends Fragment implements AdapterView.OnItemSelectedListener, LocationChangedListener { - private static final int OPTIONS_MENU_DELETE = Menu.FIRST; + private static final int OPTIONS_MENU_ADD = Menu.FIRST; + private static final int OPTIONS_MENU_DELETE = Menu.FIRST + 1; private UserDictionaryAddWordContents mContents; private View mRootView; @@ -73,21 +74,29 @@ public class UserDictionaryAddWordFragment extends Fragment @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - MenuItem actionItem = menu.add(0, OPTIONS_MENU_DELETE, 0, + final MenuItem actionItemDelete = menu.add(0, OPTIONS_MENU_DELETE, 0, R.string.user_dict_settings_delete).setIcon(android.R.drawable.ic_menu_delete); - actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | - MenuItem.SHOW_AS_ACTION_WITH_TEXT); + actionItemDelete.setShowAsAction( + MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); + final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0, + R.string.user_dict_settings_delete).setIcon(R.drawable.ic_menu_add); + actionItemAdd.setShowAsAction( + MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } /** * Callback for the framework when a menu option is pressed. * - * This class only supports the delete menu item. * @param MenuItem the item that was pressed * @return false to allow normal menu processing to proceed, true to consume it here */ @Override public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == OPTIONS_MENU_ADD) { + // added the entry in "onPause" + getActivity().onBackPressed(); + return true; + } if (item.getItemId() == OPTIONS_MENU_DELETE) { mContents.delete(getActivity()); mIsDeleting = true; diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java index 2d147aada..6e64882b6 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java @@ -27,6 +27,7 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.preference.PreferenceGroup; import android.provider.UserDictionary; +import android.text.TextUtils; import java.util.Locale; import java.util.TreeSet; @@ -52,16 +53,26 @@ public class UserDictionaryList extends PreferenceFragment { new String[] { UserDictionary.Words.LOCALE }, null, null, null); final TreeSet<String> localeList = new TreeSet<String>(); + boolean addedAllLocale = false; if (null == cursor) { // The user dictionary service is not present or disabled. Return null. return null; } else if (cursor.moveToFirst()) { final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE); do { - String locale = cursor.getString(columnIndex); - localeList.add(null != locale ? locale : ""); + final String locale = cursor.getString(columnIndex); + final boolean allLocale = TextUtils.isEmpty(locale); + localeList.add(allLocale ? "" : locale); + if (allLocale) { + addedAllLocale = true; + } } while (cursor.moveToNext()); } + if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED && !addedAllLocale) { + // For ICS, we need to show "For all languages" in case that the keyboard locale + // is different from the system locale + localeList.add(""); + } localeList.add(Locale.getDefault().toString()); return localeList; } diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java index a250c246e..36bc5ba49 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java @@ -23,6 +23,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.os.Build; import android.os.Bundle; import android.provider.UserDictionary; import android.text.TextUtils; @@ -47,13 +48,42 @@ import java.util.Locale; public class UserDictionarySettings extends ListFragment { - private static final String[] QUERY_PROJECTION = { - UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT - }; + public static final boolean IS_SHORTCUT_API_SUPPORTED = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; + + private static final String[] QUERY_PROJECTION_SHORTCUT_UNSUPPORTED = + { UserDictionary.Words._ID, UserDictionary.Words.WORD}; + private static final String[] QUERY_PROJECTION_SHORTCUT_SUPPORTED = + { UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT}; + private static final String[] QUERY_PROJECTION = + IS_SHORTCUT_API_SUPPORTED ? + QUERY_PROJECTION_SHORTCUT_SUPPORTED : QUERY_PROJECTION_SHORTCUT_UNSUPPORTED; // The index of the shortcut in the above array. private static final int INDEX_SHORTCUT = 2; + private static final String[] ADAPTER_FROM_SHORTCUT_UNSUPPORTED = { + UserDictionary.Words.WORD, + }; + + private static final String[] ADAPTER_FROM_SHORTCUT_SUPPORTED = { + UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT + }; + + private static final String[] ADAPTER_FROM = IS_SHORTCUT_API_SUPPORTED ? + ADAPTER_FROM_SHORTCUT_SUPPORTED : ADAPTER_FROM_SHORTCUT_UNSUPPORTED; + + private static final int[] ADAPTER_TO_SHORTCUT_UNSUPPORTED = { + android.R.id.text1, + }; + + private static final int[] ADAPTER_TO_SHORTCUT_SUPPORTED = { + android.R.id.text1, android.R.id.text2 + }; + + private static final int[] ADAPTER_TO = IS_SHORTCUT_API_SUPPORTED ? + ADAPTER_TO_SHORTCUT_SUPPORTED : ADAPTER_TO_SHORTCUT_UNSUPPORTED; + // Either the locale is empty (means the word is applicable to all locales) // or the word equals our current locale private static final String QUERY_SELECTION = @@ -66,6 +96,8 @@ public class UserDictionarySettings extends ListFragment { private static final String DELETE_SELECTION_WITHOUT_SHORTCUT = UserDictionary.Words.WORD + "=? AND " + UserDictionary.Words.SHORTCUT + " is null OR " + UserDictionary.Words.SHORTCUT + "=''"; + private static final String DELETE_SELECTION_SHORTCUT_UNSUPPORTED = + UserDictionary.Words.WORD + "=?"; private static final int OPTIONS_MENU_ADD = Menu.FIRST; @@ -146,10 +178,8 @@ public class UserDictionarySettings extends ListFragment { } private ListAdapter createAdapter() { - return new MyAdapter(getActivity(), - R.layout.user_dictionary_item, mCursor, - new String[] { UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT }, - new int[] { android.R.id.text1, android.R.id.text2 }, this); + return new MyAdapter(getActivity(), R.layout.user_dictionary_item, mCursor, + ADAPTER_FROM, ADAPTER_TO, this); } @Override @@ -163,11 +193,20 @@ public class UserDictionarySettings extends ListFragment { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) { + final Locale systemLocale = getResources().getConfiguration().locale; + if (!TextUtils.isEmpty(mLocale) && !mLocale.equals(systemLocale.toString())) { + // Hide the add button for ICS because it doesn't support specifying a locale + // for an entry. This new "locale"-aware API has been added in conjunction + // with the shortcut API. + return; + } + } MenuItem actionItem = menu.add(0, OPTIONS_MENU_ADD, 0, R.string.user_dict_settings_add_menu_title) .setIcon(R.drawable.ic_menu_add); - actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | - MenuItem.SHOW_AS_ACTION_WITH_TEXT); + actionItem.setShowAsAction( + MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } @Override @@ -209,6 +248,7 @@ public class UserDictionarySettings extends ListFragment { } private String getShortcut(final int position) { + if (!IS_SHORTCUT_API_SUPPORTED) return null; if (null == mCursor) return null; mCursor.moveToPosition(position); // Handle a possible race-condition @@ -220,7 +260,10 @@ public class UserDictionarySettings extends ListFragment { public static void deleteWord(final String word, final String shortcut, final ContentResolver resolver) { - if (TextUtils.isEmpty(shortcut)) { + if (!IS_SHORTCUT_API_SUPPORTED) { + resolver.delete(UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_SHORTCUT_UNSUPPORTED, + new String[] { word }); + } else if (TextUtils.isEmpty(shortcut)) { resolver.delete( UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITHOUT_SHORTCUT, new String[] { word }); @@ -239,6 +282,10 @@ public class UserDictionarySettings extends ListFragment { @Override public boolean setViewValue(View v, Cursor c, int columnIndex) { + if (!IS_SHORTCUT_API_SUPPORTED) { + // just let SimpleCursorAdapter set the view values + return false; + } if (columnIndex == INDEX_SHORTCUT) { final String shortcut = c.getString(INDEX_SHORTCUT); if (TextUtils.isEmpty(shortcut)) { diff --git a/native/jni/src/suggest/core/policy/traversal.h b/native/jni/src/suggest/core/policy/traversal.h index 02c358aec..d3146da7f 100644 --- a/native/jni/src/suggest/core/policy/traversal.h +++ b/native/jni/src/suggest/core/policy/traversal.h @@ -28,7 +28,8 @@ class Traversal { virtual int getMaxPointerCount() const = 0; virtual bool allowsErrorCorrections(const DicNode *const dicNode) const = 0; virtual bool isOmission(const DicTraverseSession *const traverseSession, - const DicNode *const dicNode, const DicNode *const childDicNode) const = 0; + const DicNode *const dicNode, const DicNode *const childDicNode, + const bool allowsErrorCorrections) const = 0; virtual bool isSpaceSubstitutionTerminal(const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const = 0; virtual bool isSpaceOmissionTerminal(const DicTraverseSession *const traverseSession, diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp index b1a5ff24e..4f94a9a3b 100644 --- a/native/jni/src/suggest/core/suggest.cpp +++ b/native/jni/src/suggest/core/suggest.cpp @@ -296,8 +296,8 @@ void Suggest::expandCurrentDicNodes(DicTraverseSession *traverseSession) const { correctionDicNode.advanceDigraphIndex(); processDicNodeAsDigraph(traverseSession, &correctionDicNode); } - if (allowsErrorCorrections - && TRAVERSAL->isOmission(traverseSession, &dicNode, childDicNode)) { + if (TRAVERSAL->isOmission(traverseSession, &dicNode, childDicNode, + allowsErrorCorrections)) { // TODO: (Gesture) Change weight between omission and substitution errors // TODO: (Gesture) Terminal node should not be handled as omission correctionDicNode.initByCopy(childDicNode); diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h index 9f8347452..fb1fb79d1 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h @@ -43,10 +43,17 @@ class TypingTraversal : public Traversal { } AK_FORCE_INLINE bool isOmission(const DicTraverseSession *const traverseSession, - const DicNode *const dicNode, const DicNode *const childDicNode) const { + const DicNode *const dicNode, const DicNode *const childDicNode, + const bool allowsErrorCorrections) const { if (!CORRECT_OMISSION) { return false; } + // Note: Always consider intentional omissions (like apostrophes) since they are common. + const bool canConsiderOmission = + allowsErrorCorrections || childDicNode->canBeIntentionalOmission(); + if (!canConsiderOmission) { + return false; + } const int inputSize = traverseSession->getInputSize(); // TODO: Don't refer to isCompletion? if (dicNode->isCompletion(inputSize)) { |