aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/AndroidManifest.xml12
-rw-r--r--java/res/layout/dictionary_line.xml16
-rw-r--r--java/res/raw/empty.dict2
-rw-r--r--java/res/values/strings-appname.xml37
-rw-r--r--java/res/values/strings.xml12
-rw-r--r--java/res/values/styles.xml2
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ActionBatch.java7
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ButtonSwitcher.java109
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java6
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java15
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/WordListPreference.java39
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java6
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java14
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java8
-rw-r--r--java/src/com/android/inputmethod/latin/DebugSettings.java2
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java7
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java6
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java2
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupActivity.java3
-rw-r--r--native/jni/src/defines.h20
-rw-r--r--native/jni/src/dictionary.h5
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node.h9
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_state_input.h4
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_state_scoring.h37
-rw-r--r--native/jni/src/suggest/core/policy/traversal.h3
-rw-r--r--native/jni/src/suggest/core/policy/weighting.cpp63
-rw-r--r--native/jni/src/suggest/core/policy/weighting.h10
-rw-r--r--native/jni/src/suggest/core/suggest.cpp33
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_traversal.h9
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp35
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_weighting.h28
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;