diff options
31 files changed, 392 insertions, 169 deletions
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/dictionary_line.xml b/java/res/layout/dictionary_line.xml index 9eeea697e..9ddbcf714 100644 --- a/java/res/layout/dictionary_line.xml +++ b/java/res/layout/dictionary_line.xml @@ -84,5 +84,21 @@ android:singleLine="true" android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/install_dict" /> + <Button + android:id="@+android:id/dict_cancel_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right|center_vertical" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:text="@string/cancel_download_dict" /> + <Button + android:id="@+android:id/dict_delete_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right|center_vertical" + android:singleLine="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:text="@string/delete_dict" /> </com.android.inputmethod.dictionarypack.ButtonSwitcher> </LinearLayout> diff --git a/java/res/raw/empty.dict b/java/res/raw/empty.dict index da1bf9666..80ce06699 100644 --- a/java/res/raw/empty.dict +++ b/java/res/raw/empty.dict @@ -1 +1 @@ -x±
\ No newline at end of file +›Á:þ
\ No newline at end of file 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..9bf4ddde6 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> 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/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java index faf5d3c87..a9d799218 100644 --- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java +++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java @@ -138,7 +138,12 @@ public final class ActionBatch { if (null == manager) return; // This is an upgraded word list: we should download it. - final Uri uri = Uri.parse(mWordList.mRemoteFilename); + // Adding a disambiguator to circumvent a bug in older versions of DownloadManager. + // DownloadManager also stupidly cuts the extension to replace with its own that it + // gets from the content-type. We need to circumvent this. + final String disambiguator = "#" + System.currentTimeMillis() + + com.android.inputmethod.latin.Utils.getVersionName(context) + ".dict"; + final Uri uri = Uri.parse(mWordList.mRemoteFilename + disambiguator); final Request request = new Request(uri); final Resources res = context.getResources(); diff --git a/java/src/com/android/inputmethod/dictionarypack/ButtonSwitcher.java b/java/src/com/android/inputmethod/dictionarypack/ButtonSwitcher.java index a062298f2..391a15c97 100644 --- a/java/src/com/android/inputmethod/dictionarypack/ButtonSwitcher.java +++ b/java/src/com/android/inputmethod/dictionarypack/ButtonSwitcher.java @@ -16,9 +16,12 @@ package com.android.inputmethod.dictionarypack; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.util.AttributeSet; import android.view.View; +import android.view.ViewPropertyAnimator; import android.widget.Button; import android.widget.FrameLayout; @@ -28,10 +31,24 @@ import com.android.inputmethod.latin.R; * A view that handles buttons inside it according to a status. */ public class ButtonSwitcher extends FrameLayout { + public static final int NOT_INITIALIZED = -1; + public static final int STATUS_NO_BUTTON = 0; + public static final int STATUS_INSTALL = 1; + public static final int STATUS_CANCEL = 2; + public static final int STATUS_DELETE = 3; + // One of the above + private int mStatus = NOT_INITIALIZED; + private int mAnimateToStatus = NOT_INITIALIZED; + // Animation directions public static final int ANIMATION_IN = 1; public static final int ANIMATION_OUT = 2; + private Button mInstallButton; + private Button mCancelButton; + private Button mDeleteButton; + private OnClickListener mOnClickListener; + public ButtonSwitcher(Context context, AttributeSet attrs) { super(context, attrs); } @@ -40,30 +57,96 @@ public class ButtonSwitcher extends FrameLayout { super(context, attrs, defStyle); } - public void setText(final CharSequence text) { - ((Button)findViewById(R.id.dict_install_button)).setText(text); + @Override + protected void onLayout(final boolean changed, final int left, final int top, final int right, + final int bottom) { + super.onLayout(changed, left, top, right, bottom); + mInstallButton = (Button)findViewById(R.id.dict_install_button); + mCancelButton = (Button)findViewById(R.id.dict_cancel_button); + mDeleteButton = (Button)findViewById(R.id.dict_delete_button); + mInstallButton.setOnClickListener(mOnClickListener); + mCancelButton.setOnClickListener(mOnClickListener); + mDeleteButton.setOnClickListener(mOnClickListener); + setButtonPositionWithoutAnimation(mStatus); + if (mAnimateToStatus != NOT_INITIALIZED) { + // We have been asked to animate before we were ready, so we took a note of it. + // We are now ready: launch the animation. + animateButtonPosition(mStatus, mAnimateToStatus); + mStatus = mAnimateToStatus; + mAnimateToStatus = NOT_INITIALIZED; + } + } + + private Button getButton(final int status) { + switch(status) { + case STATUS_INSTALL: + return mInstallButton; + case STATUS_CANCEL: + return mCancelButton; + case STATUS_DELETE: + return mDeleteButton; + default: + return null; + } + } + + public void setStatusAndUpdateVisuals(final int status) { + if (mStatus == NOT_INITIALIZED) { + setButtonPositionWithoutAnimation(status); + mStatus = status; + } else { + if (null == mInstallButton) { + // We may come here before we have been layout. In this case we don't know our + // size yet so we can't start animations so we need to remember what animation to + // start once layout has gone through. + mAnimateToStatus = status; + } else { + animateButtonPosition(mStatus, status); + mStatus = status; + } + } } - public void setInternalButtonVisiblility(final int visibility) { - findViewById(R.id.dict_install_button).setVisibility(visibility); + private void setButtonPositionWithoutAnimation(final int status) { + // This may be called by setStatus() before the layout has come yet. + if (null == mInstallButton) return; + final int width = getWidth(); + // Set to out of the screen if that's not the currently displayed status + mInstallButton.setTranslationX(STATUS_INSTALL == status ? 0 : width); + mCancelButton.setTranslationX(STATUS_CANCEL == status ? 0 : width); + mDeleteButton.setTranslationX(STATUS_DELETE == status ? 0 : width); + } + + private void animateButtonPosition(final int oldStatus, final int newStatus) { + final View oldButton = getButton(oldStatus); + final View newButton = getButton(newStatus); + if (null != oldButton && null != newButton) { + // Transition between two buttons : animate out, then in + animateButton(oldButton, ANIMATION_OUT).setListener( + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(final Animator animation) { + animateButton(newButton, ANIMATION_IN); + } + }); + } else if (null != oldButton) { + animateButton(oldButton, ANIMATION_OUT); + } else if (null != newButton) { + animateButton(newButton, ANIMATION_IN); + } } public void setInternalOnClickListener(final OnClickListener listener) { - findViewById(R.id.dict_install_button).setOnClickListener(listener); + mOnClickListener = listener; } - public void animateButton(final int direction) { - final View button = findViewById(R.id.dict_install_button); + private ViewPropertyAnimator animateButton(final View button, final int direction) { final float outerX = getWidth(); final float innerX = button.getX() - button.getTranslationX(); - if (View.INVISIBLE == button.getVisibility()) { - button.setTranslationX(outerX - innerX); - button.setVisibility(View.VISIBLE); - } if (ANIMATION_IN == direction) { - button.animate().translationX(0); + return button.animate().translationX(0); } else { - button.animate().translationX(outerX - innerX); + return button.animate().translationX(outerX - innerX); } } } diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java index 8975d69a8..de3711c27 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java @@ -44,6 +44,12 @@ public class DictionaryListInterfaceState { return state.mOpen; } + public int getStatus(final String wordlistId) { + final State state = mWordlistToState.get(wordlistId); + if (null == state) return MetadataDbHelper.STATUS_UNKNOWN; + return state.mStatus; + } + public void setOpen(final String wordlistId, final int status) { final State newState; final State state = mWordlistToState.get(wordlistId); diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java index a59660954..3f917f13f 100644 --- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java +++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java @@ -212,7 +212,12 @@ public final class UpdateHandler { private static void updateClientsWithMetadataUri(final Context context, final boolean updateNow, final String metadataUri) { PrivateLog.log("Update for metadata URI " + Utils.s(metadataUri)); - final Request metadataRequest = new Request(Uri.parse(metadataUri)); + // Adding a disambiguator to circumvent a bug in older versions of DownloadManager. + // DownloadManager also stupidly cuts the extension to replace with its own that it + // gets from the content-type. We need to circumvent this. + final String disambiguator = "#" + System.currentTimeMillis() + + com.android.inputmethod.latin.Utils.getVersionName(context) + ".json"; + final Request metadataRequest = new Request(Uri.parse(metadataUri + disambiguator)); Utils.l("Request =", metadataRequest); final Resources res = context.getResources(); @@ -351,7 +356,13 @@ public final class UpdateHandler { final int columnUri = cursor.getColumnIndex(DownloadManager.COLUMN_URI); final int error = cursor.getInt(columnError); status = cursor.getInt(columnStatus); - uri = cursor.getString(columnUri); + final String uriWithAnchor = cursor.getString(columnUri); + int anchorIndex = uriWithAnchor.indexOf('#'); + if (anchorIndex != -1) { + uri = uriWithAnchor.substring(0, anchorIndex); + } else { + uri = uriWithAnchor; + } if (DownloadManager.STATUS_SUCCESSFUL != status) { Log.e(TAG, "Permanent failure of download " + downloadId + " with error code: " + error); diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java index f1c022808..1cf9196b5 100644 --- a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java +++ b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java @@ -110,29 +110,31 @@ public final class WordListPreference extends Preference { } } + // The table below needs to be kept in sync with MetadataDbHelper.STATUS_* since it uses + // the values as indices. private static final int sStatusActionList[][] = { // MetadataDbHelper.STATUS_UNKNOWN {}, // MetadataDbHelper.STATUS_AVAILABLE - { R.string.install_dict, ACTION_ENABLE_DICT }, + { ButtonSwitcher.STATUS_INSTALL, ACTION_ENABLE_DICT }, // MetadataDbHelper.STATUS_DOWNLOADING - { R.string.cancel_download_dict, ACTION_DISABLE_DICT }, + { ButtonSwitcher.STATUS_CANCEL, ACTION_DISABLE_DICT }, // MetadataDbHelper.STATUS_INSTALLED - { R.string.delete_dict, ACTION_DELETE_DICT }, + { ButtonSwitcher.STATUS_DELETE, ACTION_DELETE_DICT }, // MetadataDbHelper.STATUS_DISABLED - { R.string.delete_dict, ACTION_DELETE_DICT }, + { ButtonSwitcher.STATUS_DELETE, ACTION_DELETE_DICT }, // MetadataDbHelper.STATUS_DELETING // We show 'install' because the file is supposed to be deleted. // The user may reinstall it. - { R.string.install_dict, ACTION_ENABLE_DICT } + { ButtonSwitcher.STATUS_INSTALL, ACTION_ENABLE_DICT } }; - private CharSequence getButtonLabel(final int status) { + private int getButtonSwitcherStatus(final int status) { if (status >= sStatusActionList.length) { Log.e(TAG, "Unknown status " + status); - return ""; + return ButtonSwitcher.STATUS_NO_BUTTON; } - return mContext.getString(sStatusActionList[status][0]); + return sStatusActionList[status][0]; } private static int getActionIdFromStatusAndMenuEntry(final int status) { @@ -189,9 +191,20 @@ public final class WordListPreference extends Preference { ((ViewGroup)view).setLayoutTransition(null); final ButtonSwitcher buttonSwitcher = (ButtonSwitcher)view.findViewById(R.id.wordlist_button_switcher); - buttonSwitcher.setText(getButtonLabel(mStatus)); - buttonSwitcher.setInternalButtonVisiblility(mInterfaceState.isOpen(mWordlistId) ? - View.VISIBLE : View.INVISIBLE); + if (mInterfaceState.isOpen(mWordlistId)) { + // The button is open. + final int previousStatus = mInterfaceState.getStatus(mWordlistId); + buttonSwitcher.setStatusAndUpdateVisuals(getButtonSwitcherStatus(previousStatus)); + if (previousStatus != mStatus) { + // We come here if the status has changed since last time. We need to animate + // the transition. + buttonSwitcher.setStatusAndUpdateVisuals(getButtonSwitcherStatus(mStatus)); + mInterfaceState.setOpen(mWordlistId, mStatus); + } + } else { + // The button is closed. + buttonSwitcher.setStatusAndUpdateVisuals(ButtonSwitcher.STATUS_NO_BUTTON); + } buttonSwitcher.setInternalOnClickListener(mActionButtonClickHandler); view.setOnClickListener(mPreferenceClickHandler); } @@ -224,9 +237,9 @@ public final class WordListPreference extends Preference { final ButtonSwitcher buttonSwitcher = (ButtonSwitcher)listView.getChildAt(i) .findViewById(R.id.wordlist_button_switcher); if (i == indexToOpen) { - buttonSwitcher.animateButton(ButtonSwitcher.ANIMATION_IN); + buttonSwitcher.setStatusAndUpdateVisuals(getButtonSwitcherStatus(mStatus)); } else { - buttonSwitcher.animateButton(ButtonSwitcher.ANIMATION_OUT); + buttonSwitcher.setStatusAndUpdateVisuals(ButtonSwitcher.STATUS_NO_BUTTON); } } } diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index d74644d9e..8d4beeced 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(); @@ -581,6 +585,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( @@ -1054,6 +1059,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack @Override public void onShowMoreKeysPanel(final MoreKeysPanel panel) { + locatePreviewPlacerView(); if (isShowingMoreKeysPanel()) { onDismissMoreKeysPanel(); } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index dbc2b9082..03f7d1c10 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -147,10 +147,20 @@ public final class BinaryDictionary extends Dictionary { ++len; } if (len > 0) { - final int score = SuggestedWordInfo.KIND_WHITELIST == mOutputTypes[j] + final int flags = mOutputTypes[j] & SuggestedWordInfo.KIND_MASK_FLAGS; + if (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. + continue; + } + final int kind = mOutputTypes[j] & SuggestedWordInfo.KIND_MASK_KIND; + final int score = SuggestedWordInfo.KIND_WHITELIST == kind ? SuggestedWordInfo.MAX_SCORE : mOutputScores[j]; + // TODO: check that all users of the `kind' parameter are ready to accept + // flags too and pass mOutputTypes[j] instead of kind suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len), - score, mOutputTypes[j], mDictType)); + score, kind, mDictType)); } } return suggestions; diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 294312843..ddd72f18e 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -72,10 +72,16 @@ final class BinaryDictionaryGetter { public static String getTempFileName(final String id, final Context context) throws IOException { final String safeId = DictionaryInfoUtils.replaceFileNameDangerousCharacters(id); + final File directory = new File(DictionaryInfoUtils.getWordListTempDirectory(context)); + if (!directory.exists()) { + if (!directory.mkdirs()) { + Log.e(TAG, "Could not create the temporary directory"); + } + } // If the first argument is less than three chars, createTempFile throws a // RuntimeException. We don't really care about what name we get, so just // put a three-chars prefix makes us safe. - return File.createTempFile("xxx" + safeId, null).getAbsolutePath(); + return File.createTempFile("xxx" + safeId, null, directory).getAbsolutePath(); } /** diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java index 9d4794121..5969a63de 100644 --- a/java/src/com/android/inputmethod/latin/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/DebugSettings.java @@ -122,7 +122,7 @@ public final class DebugSettings extends PreferenceFragment } boolean isDebugMode = mDebugMode.isChecked(); final String version = getResources().getString( - R.string.version_text, Utils.getSdkVersion(getActivity())); + R.string.version_text, Utils.getVersionName(getActivity())); if (!isDebugMode) { mDebugMode.setTitle(version); mDebugMode.setSummary(""); diff --git a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java index dcfa483f8..df7bad8d0 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java @@ -129,6 +129,13 @@ public class DictionaryInfoUtils { } /** + * Helper method to get the top level temp directory. + */ + public static String getWordListTempDirectory(final Context context) { + return context.getFilesDir() + File.separator + "tmp"; + } + + /** * Reverse escaping done by replaceFileNameDangerousCharacters. */ public static String getWordListIdFromFileName(final String fname) { diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 616e1911b..dfddb0ffe 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -122,6 +122,7 @@ public final class SuggestedWords { public static final class SuggestedWordInfo { public static final int MAX_SCORE = Integer.MAX_VALUE; + public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind public static final int KIND_TYPED = 0; // What user typed public static final int KIND_CORRECTION = 1; // Simple correction/suggestion public static final int KIND_COMPLETION = 2; // Completion (suggestion with appended chars) @@ -132,6 +133,11 @@ public final class SuggestedWords { public static final int KIND_SHORTCUT = 7; // A shortcut public static final int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input) public static final int KIND_RESUMED = 9; // A resumed suggestion (comes from a span) + + public static final int KIND_MASK_FLAGS = 0xFFFFFF00; // Mask to get the flags + public static final int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000; + public static final int KIND_FLAG_EXACT_MATCH = 0x40000000; + public final String mWord; public final int mScore; public final int mKind; // one of the KIND_* constants above diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index fc32bd45e..0f96c54dc 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -475,7 +475,7 @@ public final class Utils { return 0; } - public static String getSdkVersion(Context context) { + public static String getVersionName(Context context) { try { if (context == null) { return ""; diff --git a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java index 578787dac..29ee63d4e 100644 --- a/java/src/com/android/inputmethod/latin/setup/SetupActivity.java +++ b/java/src/com/android/inputmethod/latin/setup/SetupActivity.java @@ -236,8 +236,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/native/jni/src/defines.h b/native/jni/src/defines.h index e6719c9c3..d3b351f81 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -438,4 +438,24 @@ typedef enum { // Create new word with space substitution CT_NEW_WORD_SPACE_SUBSTITUTION, } CorrectionType; + +// ErrorType is mainly decided by CorrectionType but it is also depending on if +// the correction has really been performed or not. +typedef enum { + // Substitution, omission and transposition + ET_EDIT_CORRECTION, + // Proximity error + ET_PROXIMITY_CORRECTION, + // Completion + ET_COMPLETION, + // New word + // TODO: Remove. + // A new word error should be an edit correction error or a proximity correction error. + ET_NEW_WORD, + // Treat error as an intentional omission when the CorrectionType is omission and the node can + // be intentional omission. + ET_INTENTIONAL_OMISSION, + // Not treated as an error. Tracked for checking exact match + ET_NOT_AN_ERROR +} ErrorType; #endif // LATINIME_DEFINES_H diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 0653d3ca9..2ad5b6c0b 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -31,6 +31,7 @@ class UnigramDictionary; class Dictionary { public: // Taken from SuggestedWords.java + static const int KIND_MASK_KIND = 0xFF; // Mask to get only the kind static const int KIND_TYPED = 0; // What user typed static const int KIND_CORRECTION = 1; // Simple correction/suggestion static const int KIND_COMPLETION = 2; // Completion (suggestion with appended chars) @@ -41,6 +42,10 @@ class Dictionary { static const int KIND_SHORTCUT = 7; // A shortcut static const int KIND_PREDICTION = 8; // A prediction (== a suggestion with no input) + static const int KIND_MASK_FLAGS = 0xFFFFFF00; // Mask to get the flags + static const int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000; + static const int KIND_FLAG_EXACT_MATCH = 0x40000000; + Dictionary(void *dict, int dictSize, int mmapFd, int dictBufAdjust); int getSuggestions(ProximityInfo *proximityInfo, void *traverseSession, int *xcoordinates, diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h index e8432546b..92783dec7 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node.h +++ b/native/jni/src/suggest/core/dicnode/dic_node.h @@ -463,6 +463,10 @@ class DicNode { mDicNodeState.mDicNodeStateScoring.advanceDigraphIndex(); } + bool isExactMatch() const { + return mDicNodeState.mDicNodeStateScoring.isExactMatch(); + } + uint8_t getFlags() const { return mDicNodeProperties.getFlags(); } @@ -542,13 +546,12 @@ class DicNode { // Caveat: Must not be called outside Weighting // This restriction is guaranteed by "friend" AK_FORCE_INLINE void addCost(const float spatialCost, const float languageCost, - const bool doNormalization, const int inputSize, const bool isEditCorrection, - const bool isProximityCorrection) { + const bool doNormalization, const int inputSize, const ErrorType errorType) { if (DEBUG_GEO_FULL) { LOGI_SHOW_ADD_COST_PROP; } mDicNodeState.mDicNodeStateScoring.addCost(spatialCost, languageCost, doNormalization, - inputSize, getTotalInputIndex(), isEditCorrection, isProximityCorrection); + inputSize, getTotalInputIndex(), errorType); } // Caveat: Must not be called outside Weighting diff --git a/native/jni/src/suggest/core/dicnode/dic_node_state_input.h b/native/jni/src/suggest/core/dicnode/dic_node_state_input.h index 7ad3e3e5f..bbd9435b5 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_state_input.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_state_input.h @@ -46,8 +46,8 @@ class DicNodeStateInput { for (int i = 0; i < MAX_POINTER_COUNT_G; i++) { mInputIndex[i] = src->mInputIndex[i]; mPrevCodePoint[i] = src->mPrevCodePoint[i]; - mTerminalDiffCost[i] = resetTerminalDiffCost ? - static_cast<float>(MAX_VALUE_FOR_WEIGHTING) : src->mTerminalDiffCost[i]; + mTerminalDiffCost[i] = resetTerminalDiffCost ? + static_cast<float>(MAX_VALUE_FOR_WEIGHTING) : src->mTerminalDiffCost[i]; } } diff --git a/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h b/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h index fd9d610e3..dca9d60da 100644 --- a/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h +++ b/native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h @@ -31,7 +31,7 @@ class DicNodeStateScoring { mDigraphIndex(DigraphUtils::NOT_A_DIGRAPH_INDEX), mEditCorrectionCount(0), mProximityCorrectionCount(0), mNormalizedCompoundDistance(0.0f), mSpatialDistance(0.0f), mLanguageDistance(0.0f), - mRawLength(0.0f) { + mRawLength(0.0f), mExactMatch(true) { } virtual ~DicNodeStateScoring() {} @@ -45,6 +45,7 @@ class DicNodeStateScoring { mRawLength = 0.0f; mDoubleLetterLevel = NOT_A_DOUBLE_LETTER; mDigraphIndex = DigraphUtils::NOT_A_DIGRAPH_INDEX; + mExactMatch = true; } AK_FORCE_INLINE void init(const DicNodeStateScoring *const scoring) { @@ -56,17 +57,32 @@ class DicNodeStateScoring { mRawLength = scoring->mRawLength; mDoubleLetterLevel = scoring->mDoubleLetterLevel; mDigraphIndex = scoring->mDigraphIndex; + mExactMatch = scoring->mExactMatch; } void addCost(const float spatialCost, const float languageCost, const bool doNormalization, - const int inputSize, const int totalInputIndex, const bool isEditCorrection, - const bool isProximityCorrection) { + const int inputSize, const int totalInputIndex, const ErrorType errorType) { addDistance(spatialCost, languageCost, doNormalization, inputSize, totalInputIndex); - if (isEditCorrection) { - ++mEditCorrectionCount; - } - if (isProximityCorrection) { - ++mProximityCorrectionCount; + switch (errorType) { + case ET_EDIT_CORRECTION: + ++mEditCorrectionCount; + mExactMatch = false; + break; + case ET_PROXIMITY_CORRECTION: + ++mProximityCorrectionCount; + mExactMatch = false; + break; + case ET_COMPLETION: + mExactMatch = false; + break; + case ET_NEW_WORD: + mExactMatch = false; + break; + case ET_INTENTIONAL_OMISSION: + mExactMatch = false; + break; + case ET_NOT_AN_ERROR: + break; } } @@ -143,6 +159,10 @@ class DicNodeStateScoring { } } + bool isExactMatch() const { + return mExactMatch; + } + private: // Caution!!! // Use a default copy constructor and an assign operator because shallow copies are ok @@ -157,6 +177,7 @@ class DicNodeStateScoring { float mSpatialDistance; float mLanguageDistance; float mRawLength; + bool mExactMatch; AK_FORCE_INLINE void addDistance(float spatialDistance, float languageDistance, bool doNormalization, int inputSize, int totalInputIndex) { 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/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp index 6c08e7678..857ddcc1d 100644 --- a/native/jni/src/suggest/core/policy/weighting.cpp +++ b/native/jni/src/suggest/core/policy/weighting.cpp @@ -80,9 +80,8 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n traverseSession, parentDicNode, dicNode, &inputStateG); const float languageCost = Weighting::getLanguageCost(weighting, correctionType, traverseSession, parentDicNode, dicNode, bigramCacheMap); - const bool edit = Weighting::isEditCorrection(correctionType); - const bool proximity = Weighting::isProximityCorrection(weighting, correctionType, - traverseSession, dicNode); + const ErrorType errorType = weighting->getErrorType(correctionType, traverseSession, + parentDicNode, dicNode); profile(correctionType, dicNode); if (inputStateG.mNeedsToUpdateInputStateG) { dicNode->updateInputIndexG(&inputStateG); @@ -91,7 +90,7 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n (correctionType == CT_TRANSPOSITION)); } dicNode->addCost(spatialCost, languageCost, weighting->needsToNormalizeCompoundDistance(), - inputSize, edit, proximity); + inputSize, errorType); } /* static */ float Weighting::getSpatialCost(const Weighting *const weighting, @@ -158,62 +157,6 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n } } -/* static */ bool Weighting::isEditCorrection(const CorrectionType correctionType) { - switch(correctionType) { - case CT_OMISSION: - return true; - case CT_ADDITIONAL_PROXIMITY: - return true; - case CT_SUBSTITUTION: - return true; - case CT_NEW_WORD_SPACE_OMITTION: - return false; - case CT_MATCH: - return false; - case CT_COMPLETION: - return false; - case CT_TERMINAL: - return false; - case CT_NEW_WORD_SPACE_SUBSTITUTION: - return false; - case CT_INSERTION: - return true; - case CT_TRANSPOSITION: - return true; - default: - return false; - } -} - -/* static */ bool Weighting::isProximityCorrection(const Weighting *const weighting, - const CorrectionType correctionType, - const DicTraverseSession *const traverseSession, const DicNode *const dicNode) { - switch(correctionType) { - case CT_OMISSION: - return false; - case CT_ADDITIONAL_PROXIMITY: - return true; - case CT_SUBSTITUTION: - return false; - case CT_NEW_WORD_SPACE_OMITTION: - return false; - case CT_MATCH: - return weighting->isProximityDicNode(traverseSession, dicNode); - case CT_COMPLETION: - return false; - case CT_TERMINAL: - return false; - case CT_NEW_WORD_SPACE_SUBSTITUTION: - return false; - case CT_INSERTION: - return false; - case CT_TRANSPOSITION: - return false; - default: - return false; - } -} - /* static */ int Weighting::getForwardInputCount(const CorrectionType correctionType) { switch(correctionType) { case CT_OMISSION: diff --git a/native/jni/src/suggest/core/policy/weighting.h b/native/jni/src/suggest/core/policy/weighting.h index bce479c51..6e740d9d6 100644 --- a/native/jni/src/suggest/core/policy/weighting.h +++ b/native/jni/src/suggest/core/policy/weighting.h @@ -80,6 +80,10 @@ class Weighting { virtual float getSpaceSubstitutionCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const = 0; + virtual ErrorType getErrorType(const CorrectionType correctionType, + const DicTraverseSession *const traverseSession, + const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0; + Weighting() {} virtual ~Weighting() {} @@ -95,12 +99,6 @@ class Weighting { const DicNode *const parentDicNode, const DicNode *const dicNode, hash_map_compat<int, int16_t> *const bigramCacheMap); // TODO: Move to TypingWeighting and GestureWeighting? - static bool isEditCorrection(const CorrectionType correctionType); - // TODO: Move to TypingWeighting and GestureWeighting? - static bool isProximityCorrection(const Weighting *const weighting, - const CorrectionType correctionType, const DicTraverseSession *const traverseSession, - const DicNode *const dicNode); - // TODO: Move to TypingWeighting and GestureWeighting? static int getForwardInputCount(const CorrectionType correctionType); }; } // namespace latinime diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp index 9de2cd2e2..4f94a9a3b 100644 --- a/native/jni/src/suggest/core/suggest.cpp +++ b/native/jni/src/suggest/core/suggest.cpp @@ -161,12 +161,15 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen + doubleLetterCost; const TerminalAttributes terminalAttributes(traverseSession->getOffsetDict(), terminalDicNode->getFlags(), terminalDicNode->getAttributesPos()); - const int originalTerminalProbability = terminalDicNode->getProbability(); + const bool isPossiblyOffensiveWord = terminalDicNode->getProbability() <= 0; + const bool isExactMatch = terminalDicNode->isExactMatch(); + const int outputTypeFlags = + isPossiblyOffensiveWord ? Dictionary::KIND_FLAG_POSSIBLY_OFFENSIVE : 0 + | isExactMatch ? Dictionary::KIND_FLAG_EXACT_MATCH : 0; + + // Entries that are blacklisted or do not represent a word should not be output. + const bool isValidWord = !terminalAttributes.isBlacklistedOrNotAWord(); - // Do not suggest words with a 0 probability, or entries that are blacklisted or do not - // represent a word. However, we should still submit their shortcuts if any. - const bool isValidWord = - originalTerminalProbability > 0 && !terminalAttributes.isBlacklistedOrNotAWord(); // Increase output score of top typing suggestion to ensure autocorrection. // TODO: Better integration with java side autocorrection logic. // Force autocorrection for obvious long multi-word suggestions. @@ -188,10 +191,9 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen } } - // Do not suggest words with a 0 probability, or entries that are blacklisted or do not - // represent a word. However, we should still submit their shortcuts if any. + // Don't output invalid words. However, we still need to submit their shortcuts if any. if (isValidWord) { - outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION; + outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION | outputTypeFlags; frequencies[outputWordIndex] = finalScore; // Populate the outputChars array with the suggested word. const int startIndex = outputWordIndex * MAX_WORD_LENGTH; @@ -294,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); @@ -422,20 +424,15 @@ void Suggest::processDicNodeAsDigraph(DicTraverseSession *traverseSession, */ void Suggest::processDicNodeAsOmission( DicTraverseSession *traverseSession, DicNode *dicNode) const { - // If the omission is surely intentional that it should incur zero cost. - const bool isZeroCostOmission = dicNode->isZeroCostOmission(); DicNodeVector childDicNodes; - DicNodeUtils::getAllChildDicNodes(dicNode, traverseSession->getOffsetDict(), &childDicNodes); const int size = childDicNodes.getSizeAndLock(); for (int i = 0; i < size; i++) { DicNode *const childDicNode = childDicNodes[i]; - if (!isZeroCostOmission) { - // Treat this word as omission - Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_OMISSION, traverseSession, - dicNode, childDicNode, 0 /* bigramCacheMap */); - } + // Treat this word as omission + Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_OMISSION, traverseSession, + dicNode, childDicNode, 0 /* bigramCacheMap */); weightChildNode(traverseSession, childDicNode); if (!TRAVERSAL->isPossibleOmissionChildNode(traverseSession, dicNode, 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)) { diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp index 1500341bd..47bd20425 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp @@ -21,4 +21,39 @@ namespace latinime { const TypingWeighting TypingWeighting::sInstance; + +ErrorType TypingWeighting::getErrorType(const CorrectionType correctionType, + const DicTraverseSession *const traverseSession, + const DicNode *const parentDicNode, const DicNode *const dicNode) const { + switch (correctionType) { + case CT_MATCH: + if (isProximityDicNode(traverseSession, dicNode)) { + return ET_PROXIMITY_CORRECTION; + } else { + return ET_NOT_AN_ERROR; + } + case CT_ADDITIONAL_PROXIMITY: + return ET_PROXIMITY_CORRECTION; + case CT_OMISSION: + if (parentDicNode->canBeIntentionalOmission()) { + return ET_INTENTIONAL_OMISSION; + } else { + return ET_EDIT_CORRECTION; + } + break; + case CT_SUBSTITUTION: + case CT_INSERTION: + case CT_TRANSPOSITION: + return ET_EDIT_CORRECTION; + case CT_NEW_WORD_SPACE_OMITTION: + case CT_NEW_WORD_SPACE_SUBSTITUTION: + return ET_NEW_WORD; + case CT_TERMINAL: + return ET_NOT_AN_ERROR; + case CT_COMPLETION: + return ET_COMPLETION; + default: + return ET_NOT_AN_ERROR; + } +} } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h index 34d25ae1a..4a0bd7194 100644 --- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h +++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h @@ -50,13 +50,14 @@ class TypingWeighting : public Weighting { } float getOmissionCost(const DicNode *const parentDicNode, const DicNode *const dicNode) const { - bool sameCodePoint = false; - bool isFirstLetterOmission = false; - float cost = 0.0f; - sameCodePoint = dicNode->isSameNodeCodePoint(parentDicNode); + const bool isZeroCostOmission = parentDicNode->isZeroCostOmission(); + const bool sameCodePoint = dicNode->isSameNodeCodePoint(parentDicNode); // If the traversal omitted the first letter then the dicNode should now be on the second. - isFirstLetterOmission = dicNode->getDepth() == 2; - if (isFirstLetterOmission) { + const bool isFirstLetterOmission = dicNode->getDepth() == 2; + float cost = 0.0f; + if (isZeroCostOmission) { + cost = 0.0f; + } else if (isFirstLetterOmission) { cost = ScoringParams::OMISSION_COST_FIRST_CHAR; } else { cost = sameCodePoint ? ScoringParams::OMISSION_COST_SAME_CHAR @@ -156,15 +157,8 @@ class TypingWeighting : public Weighting { float getTerminalLanguageCost(const DicTraverseSession *const traverseSession, const DicNode *const dicNode, const float dicNodeLanguageImprobability) const { - const bool hasEditCount = dicNode->getEditCorrectionCount() > 0; - const bool isSameLength = dicNode->getDepth() == traverseSession->getInputSize(); - const bool hasMultipleWords = dicNode->hasMultipleWords(); - const bool hasProximityErrors = dicNode->getProximityCorrectionCount() > 0; - // Gesture input is always assumed to have proximity errors - // because the input word shouldn't be treated as perfect - const bool isExactMatch = !hasEditCount && !hasMultipleWords - && !hasProximityErrors && isSameLength; - const float languageImprobability = isExactMatch ? 0.0f : dicNodeLanguageImprobability; + const float languageImprobability = (dicNode->isExactMatch()) ? + 0.0f : dicNodeLanguageImprobability; return languageImprobability * ScoringParams::DISTANCE_WEIGHT_LANGUAGE; } @@ -189,6 +183,10 @@ class TypingWeighting : public Weighting { return cost * traverseSession->getMultiWordCostMultiplier(); } + ErrorType getErrorType(const CorrectionType correctionType, + const DicTraverseSession *const traverseSession, + const DicNode *const parentDicNode, const DicNode *const dicNode) const; + private: DISALLOW_COPY_AND_ASSIGN(TypingWeighting); static const TypingWeighting sInstance; |