Add an auto complete's threshold option.
Change-Id: I3a6821ced8642ab8f954e79a25e31766e4a18eb8main
parent
6614ac9f7b
commit
b1abda8d62
|
@ -25,4 +25,14 @@
|
|||
<integer name="config_preview_fadeout_anim_time">90</integer>
|
||||
<integer name="config_mini_keyboard_fadein_anim_time">0</integer>
|
||||
<integer name="config_mini_keyboard_fadeout_anim_time">100</integer>
|
||||
<string-array name="auto_complete_threshold_values">
|
||||
<!-- Off, When auto completing setting is Off, this value is not used. -->
|
||||
<item></item>
|
||||
<!-- Modest : Suggestion whose normalized score is greater than this value
|
||||
will be subject to auto-completion. -->
|
||||
<item>0.22</item>
|
||||
<!-- Aggressive : Suggestion whose normalized score is greater than this value
|
||||
will be subject to auto-completion. -->
|
||||
<item>0</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -86,11 +86,6 @@
|
|||
<!-- Description for show suggestions -->
|
||||
<string name="show_suggestions_summary">Display suggested words while typing</string>
|
||||
|
||||
<!-- Option to enable auto completion -->
|
||||
<string name="auto_complete">Auto-complete</string>
|
||||
<!-- Description for auto completion -->
|
||||
<string name="auto_complete_summary">Spacebar and punctuation automatically insert highlighted word</string>
|
||||
|
||||
<!-- Option to show/hide the settings key -->
|
||||
<string name="prefs_settings_key">Show settings key</string>
|
||||
<!-- Array of the settings key mode values -->
|
||||
|
@ -112,6 +107,31 @@
|
|||
<item>@string/settings_key_mode_always_hide_name</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Option to decide the auto completion threshold score -->
|
||||
<!-- Option to enable auto completion -->
|
||||
<string name="auto_complete">Auto-complete</string>
|
||||
<!-- Description for auto completion -->
|
||||
<string name="auto_complete_summary">Spacebar and punctuation automatically insert highlighted word</string>
|
||||
<string name="auto_completion_threshold_mode_value_off" translatable="false">0</string>
|
||||
<string name="auto_completion_threshold_mode_value_modest" translatable="false">1</string>
|
||||
<string name="auto_completion_threshold_mode_value_aggeressive" translatable="false">2</string>
|
||||
<string-array name="auto_completion_threshold_mode_values" translatable="false">
|
||||
<item>@string/auto_completion_threshold_mode_value_off</item>
|
||||
<item>@string/auto_completion_threshold_mode_value_modest</item>
|
||||
<item>@string/auto_completion_threshold_mode_value_aggeressive</item>
|
||||
</string-array>
|
||||
<!-- Option to disable auto completion. -->
|
||||
<string name="auto_completion_threshold_mode_off">Off</string>
|
||||
<!-- Option to use modest auto completion. -->
|
||||
<string name="auto_completion_threshold_mode_modest">Modest</string>
|
||||
<!-- Option to use aggressive auto completion. -->
|
||||
<string name="auto_completion_threshold_mode_aggeressive">Aggressive</string>
|
||||
<string-array name="auto_completion_threshold_modes">
|
||||
<item>@string/auto_completion_threshold_mode_off</item>
|
||||
<item>@string/auto_completion_threshold_mode_modest</item>
|
||||
<item>@string/auto_completion_threshold_mode_aggeressive</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Option to enable bigram completion -->
|
||||
<string name="bigram_suggestion">Bigram Suggestions</string>
|
||||
<!-- Description for auto completion -->
|
||||
|
|
|
@ -97,13 +97,14 @@
|
|||
android:defaultValue="true"
|
||||
/>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="auto_complete"
|
||||
<ListPreference
|
||||
android:key="auto_completion_threshold"
|
||||
android:title="@string/auto_complete"
|
||||
android:summary="@string/auto_complete_summary"
|
||||
android:persistent="true"
|
||||
android:defaultValue="@bool/enable_autocorrect"
|
||||
android:dependency="show_suggestions"
|
||||
android:entryValues="@array/auto_completion_threshold_mode_values"
|
||||
android:entries="@array/auto_completion_threshold_modes"
|
||||
android:defaultValue="@string/auto_completion_threshold_mode_value_modest"
|
||||
/>
|
||||
|
||||
<CheckBoxPreference
|
||||
|
@ -112,7 +113,6 @@
|
|||
android:summary="@string/bigram_suggestion_summary"
|
||||
android:persistent="true"
|
||||
android:defaultValue="true"
|
||||
android:dependency="auto_complete"
|
||||
/>
|
||||
</PreferenceCategory>
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ import java.io.FileDescriptor;
|
|||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -94,7 +95,7 @@ public class LatinIME extends InputMethodService
|
|||
private static final String PREF_AUTO_CAP = "auto_cap";
|
||||
private static final String PREF_QUICK_FIXES = "quick_fixes";
|
||||
private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
|
||||
private static final String PREF_AUTO_COMPLETE = "auto_complete";
|
||||
private static final String PREF_AUTO_COMPLETION_THRESHOLD = "auto_completion_threshold";
|
||||
private static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
|
||||
private static final String PREF_VOICE_MODE = "voice_mode";
|
||||
|
||||
|
@ -445,6 +446,7 @@ public class LatinIME extends InputMethodService
|
|||
|
||||
int[] dictionaries = getDictionary(orig);
|
||||
mSuggest = new Suggest(this, dictionaries);
|
||||
loadAndSetAutoCompletionThreshold(sp);
|
||||
updateAutoTextEnabled(saveLocale);
|
||||
if (mUserDictionary != null) mUserDictionary.close();
|
||||
mUserDictionary = new UserDictionary(this, mInputLocale);
|
||||
|
@ -2469,6 +2471,9 @@ public class LatinIME extends InputMethodService
|
|||
mLocaleSupportedForVoiceInput = voiceInputSupportedLocales.contains(mInputLocale);
|
||||
|
||||
mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true);
|
||||
mAutoCorrectEnabled = mShowSuggestions && isAutoCorrectEnabled(sp);
|
||||
mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(sp);
|
||||
loadAndSetAutoCompletionThreshold(sp);
|
||||
|
||||
if (VOICE_INSTALLED) {
|
||||
final String voiceMode = sp.getString(PREF_VOICE_MODE,
|
||||
|
@ -2483,14 +2488,61 @@ public class LatinIME extends InputMethodService
|
|||
mEnableVoice = enableVoice;
|
||||
mVoiceOnPrimary = voiceOnPrimary;
|
||||
}
|
||||
mAutoCorrectEnabled = sp.getBoolean(PREF_AUTO_COMPLETE,
|
||||
mResources.getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions;
|
||||
mBigramSuggestionEnabled = sp.getBoolean(PREF_BIGRAM_SUGGESTIONS, true) & mShowSuggestions;
|
||||
updateCorrectionMode();
|
||||
updateAutoTextEnabled(mResources.getConfiguration().locale);
|
||||
mLanguageSwitcher.loadLocales(sp);
|
||||
}
|
||||
|
||||
/**
|
||||
* load Auto completion threshold from SharedPreferences,
|
||||
* and modify mSuggest's threshold.
|
||||
*/
|
||||
private void loadAndSetAutoCompletionThreshold(SharedPreferences sp) {
|
||||
// When mSuggest is not initialized, cannnot modify mSuggest's threshold.
|
||||
if (mSuggest == null) return;
|
||||
// When auto completion setting is turned off, the threshold is ignored.
|
||||
if (!isAutoCorrectEnabled(sp)) return;
|
||||
|
||||
final String currentAutoCompletionSetting = sp.getString(PREF_AUTO_COMPLETION_THRESHOLD,
|
||||
mResources.getString(R.string.auto_completion_threshold_mode_value_modest));
|
||||
final String[] autoCompletionThresholdValues = mResources.getStringArray(
|
||||
R.array.auto_complete_threshold_values);
|
||||
// When autoCompletionThreshold is greater than 1.0,
|
||||
// auto completion is virtually turned off.
|
||||
double autoCompletionThreshold = Double.MAX_VALUE;
|
||||
try {
|
||||
final int arrayIndex = Integer.valueOf(currentAutoCompletionSetting);
|
||||
if (arrayIndex >= 0 && arrayIndex < autoCompletionThresholdValues.length) {
|
||||
autoCompletionThreshold = Double.parseDouble(
|
||||
autoCompletionThresholdValues[arrayIndex]);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Whenever the threshold settings are correct,
|
||||
// never come here.
|
||||
autoCompletionThreshold = Double.MAX_VALUE;
|
||||
Log.w(TAG, "Cannot load auto completion threshold setting."
|
||||
+ " currentAutoCompletionSetting: " + currentAutoCompletionSetting
|
||||
+ ", autoCompletionThresholdValues: "
|
||||
+ Arrays.toString(autoCompletionThresholdValues));
|
||||
}
|
||||
// TODO: This should be refactored :
|
||||
// setAutoCompleteThreshold should be called outside of this method.
|
||||
mSuggest.setAutoCompleteThreshold(autoCompletionThreshold);
|
||||
}
|
||||
|
||||
private boolean isAutoCorrectEnabled(SharedPreferences sp) {
|
||||
final String currentAutoCompletionSetting = sp.getString(PREF_AUTO_COMPLETION_THRESHOLD,
|
||||
mResources.getString(R.string.auto_completion_threshold_mode_value_modest));
|
||||
final String autoCompletionOff = mResources.getString(
|
||||
R.string.auto_completion_threshold_mode_value_off);
|
||||
return !currentAutoCompletionSetting.equals(autoCompletionOff);
|
||||
}
|
||||
|
||||
private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
|
||||
// TODO: Define default value instead of 'true'.
|
||||
return sp.getBoolean(PREF_BIGRAM_SUGGESTIONS, true);
|
||||
}
|
||||
|
||||
private void initSuggestPuncList() {
|
||||
mSuggestPuncList = new ArrayList<CharSequence>();
|
||||
mSuggestPuncs = mResources.getString(R.string.suggested_punctuations);
|
||||
|
|
|
@ -43,6 +43,9 @@ public class LatinIMESettings extends PreferenceActivity
|
|||
private static final String QUICK_FIXES_KEY = "quick_fixes";
|
||||
private static final String PREDICTION_SETTINGS_KEY = "prediction_settings";
|
||||
private static final String VOICE_SETTINGS_KEY = "voice_mode";
|
||||
private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
|
||||
private static final String PREF_AUTO_COMPLETION_THRESHOLD = "auto_completion_threshold";
|
||||
private static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
|
||||
/* package */ static final String PREF_SETTINGS_KEY = "settings_key";
|
||||
|
||||
private static final String TAG = "LatinIMESettings";
|
||||
|
@ -53,6 +56,9 @@ public class LatinIMESettings extends PreferenceActivity
|
|||
private CheckBoxPreference mQuickFixes;
|
||||
private ListPreference mVoicePreference;
|
||||
private ListPreference mSettingsKeyPreference;
|
||||
private CheckBoxPreference mShowSuggestions;
|
||||
private ListPreference mAutoCompletionThreshold;
|
||||
private CheckBoxPreference mBigramSuggestion;
|
||||
private boolean mVoiceOn;
|
||||
|
||||
private VoiceInputLogger mLogger;
|
||||
|
@ -60,6 +66,18 @@ public class LatinIMESettings extends PreferenceActivity
|
|||
private boolean mOkClicked = false;
|
||||
private String mVoiceModeOff;
|
||||
|
||||
private void ensureConsistencyOfAutoCompletionSettings() {
|
||||
if (mShowSuggestions.isChecked()) {
|
||||
mAutoCompletionThreshold.setEnabled(true);
|
||||
final String autoCompletionOff = getResources().getString(
|
||||
R.string.auto_completion_threshold_mode_value_off);
|
||||
final String currentSetting = mAutoCompletionThreshold.getValue();
|
||||
mBigramSuggestion.setEnabled(!currentSetting.equals(autoCompletionOff));
|
||||
} else {
|
||||
mAutoCompletionThreshold.setEnabled(false);
|
||||
mBigramSuggestion.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
@ -73,6 +91,11 @@ public class LatinIMESettings extends PreferenceActivity
|
|||
mVoiceModeOff = getString(R.string.voice_mode_off);
|
||||
mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff));
|
||||
mLogger = VoiceInputLogger.getLogger(this);
|
||||
|
||||
mShowSuggestions = (CheckBoxPreference) findPreference(PREF_SHOW_SUGGESTIONS);
|
||||
mAutoCompletionThreshold = (ListPreference) findPreference(PREF_AUTO_COMPLETION_THRESHOLD);
|
||||
mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
|
||||
ensureConsistencyOfAutoCompletionSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,6 +131,7 @@ public class LatinIMESettings extends PreferenceActivity
|
|||
showVoiceConfirmation();
|
||||
}
|
||||
}
|
||||
ensureConsistencyOfAutoCompletionSettings();
|
||||
mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff));
|
||||
updateVoiceModeSummary();
|
||||
updateSettingsKeySummary();
|
||||
|
|
|
@ -168,4 +168,58 @@ public class LatinIMEUtil {
|
|||
mLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int editDistance(CharSequence s, CharSequence t) {
|
||||
if (s == null || t == null) {
|
||||
throw new IllegalArgumentException("editDistance: Arguments should not be null.");
|
||||
}
|
||||
final int sl = s.length();
|
||||
final int tl = t.length();
|
||||
int[][] dp = new int [sl + 1][tl + 1];
|
||||
for (int i = 0; i <= sl; i++) {
|
||||
dp[i][0] = i;
|
||||
}
|
||||
for (int j = 0; j <= tl; j++) {
|
||||
dp[0][j] = j;
|
||||
}
|
||||
for (int i = 0; i < sl; ++i) {
|
||||
for (int j = 0; j < tl; ++j) {
|
||||
if (s.charAt(i) == t.charAt(j)) {
|
||||
dp[i + 1][j + 1] = dp[i][j];
|
||||
} else {
|
||||
dp[i + 1][j + 1] = 1 + Math.min(dp[i][j],
|
||||
Math.min(dp[i + 1][j], dp[i][j + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[sl][tl];
|
||||
}
|
||||
|
||||
// In dictionary.cpp, getSuggestion() method,
|
||||
// suggestion scores are computed using the below formula.
|
||||
// original score (called 'frequency')
|
||||
// := pow(mTypedLetterMultiplier (this is defined 2),
|
||||
// (the number of matched characters between typed word and suggested word))
|
||||
// * (individual word's score which defined in the unigram dictionary,
|
||||
// and this score is defined in range [0, 255].)
|
||||
// * (when before.length() == after.length(),
|
||||
// mFullWordMultiplier (this is defined 2))
|
||||
// So, maximum original score is pow(2, before.length()) * 255 * 2
|
||||
// So, we can normalize original score by dividing this value.
|
||||
private static final int MAX_INITIAL_SCORE = 255;
|
||||
private static final int TYPED_LETTER_MULTIPLIER = 2;
|
||||
private static final int FULL_WORD_MULTIPLYER = 2;
|
||||
public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) {
|
||||
final int beforeLength = before.length();
|
||||
final int afterLength = after.length();
|
||||
final int distance = editDistance(before, after);
|
||||
final double maximumScore = MAX_INITIAL_SCORE
|
||||
* Math.pow(TYPED_LETTER_MULTIPLIER, beforeLength)
|
||||
* FULL_WORD_MULTIPLYER;
|
||||
// add a weight based on edit distance.
|
||||
// distance <= max(afterLength, beforeLength) == afterLength,
|
||||
// so, 0 <= distance / afterLength <= 1
|
||||
final double weight = 1.0 - (double) distance / afterLength;
|
||||
return (score / maximumScore) * weight;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
|
||||
private boolean mAutoTextEnabled;
|
||||
|
||||
private double mAutoCompleteThreshold;
|
||||
private int[] mPriorities = new int[mPrefMaxSuggestions];
|
||||
private int[] mBigramPriorities = new int[PREF_MAX_BIGRAMS];
|
||||
|
||||
|
@ -163,6 +164,10 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
mUserBigramDictionary = userBigramDictionary;
|
||||
}
|
||||
|
||||
public void setAutoCompleteThreshold(double threshold) {
|
||||
mAutoCompleteThreshold = threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of suggestions to generate from the input key sequence. This has
|
||||
* to be a number between 1 and 100 (inclusive).
|
||||
|
@ -301,8 +306,14 @@ public class Suggest implements Dictionary.WordCallback {
|
|||
}
|
||||
mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
|
||||
if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
|
||||
&& mSuggestions.size() > 0) {
|
||||
mHaveCorrection = true;
|
||||
&& mSuggestions.size() > 0 && mPriorities.length > 0) {
|
||||
// TODO: when the normalized score of the first suggestion is nearly equals to
|
||||
// the normalized score of the second suggestion, behave less aggressive.
|
||||
final double normalizedScore = LatinIMEUtil.calcNormalizedScore(
|
||||
mOriginalWord, mSuggestions.get(0), mPriorities[0]);
|
||||
if (normalizedScore >= mAutoCompleteThreshold) {
|
||||
mHaveCorrection = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mOriginalWord != null) {
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
public class EditDistanceTests extends AndroidTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/*
|
||||
* dist(kitten, sitting) == 3
|
||||
*
|
||||
* kitten-
|
||||
* .|||.|
|
||||
* sitting
|
||||
*/
|
||||
public void testExample1() {
|
||||
final int dist = LatinIMEUtil.editDistance("kitten", "sitting");
|
||||
assertEquals("edit distance between 'kitten' and 'sitting' is 3",
|
||||
3, dist);
|
||||
}
|
||||
|
||||
/*
|
||||
* dist(Sunday, Saturday) == 3
|
||||
*
|
||||
* Saturday
|
||||
* | |.|||
|
||||
* S--unday
|
||||
*/
|
||||
public void testExample2() {
|
||||
final int dist = LatinIMEUtil.editDistance("Saturday", "Sunday");
|
||||
assertEquals("edit distance between 'Saturday' and 'Sunday' is 3",
|
||||
3, dist);
|
||||
}
|
||||
|
||||
public void testBothEmpty() {
|
||||
final int dist = LatinIMEUtil.editDistance("", "");
|
||||
assertEquals("when both string are empty, no edits are needed",
|
||||
0, dist);
|
||||
}
|
||||
|
||||
public void testFirstArgIsEmpty() {
|
||||
final int dist = LatinIMEUtil.editDistance("", "aaaa");
|
||||
assertEquals("when only one string of the arguments is empty,"
|
||||
+ " the edit distance is the length of the other.",
|
||||
4, dist);
|
||||
}
|
||||
|
||||
public void testSecoondArgIsEmpty() {
|
||||
final int dist = LatinIMEUtil.editDistance("aaaa", "");
|
||||
assertEquals("when only one string of the arguments is empty,"
|
||||
+ " the edit distance is the length of the other.",
|
||||
4, dist);
|
||||
}
|
||||
|
||||
public void testSameStrings() {
|
||||
final String arg1 = "The quick brown fox jumps over the lazy dog.";
|
||||
final String arg2 = "The quick brown fox jumps over the lazy dog.";
|
||||
final int dist = LatinIMEUtil.editDistance(arg1, arg2);
|
||||
assertEquals("when same strings are passed, distance equals 0.",
|
||||
0, dist);
|
||||
}
|
||||
|
||||
public void testSameReference() {
|
||||
final String arg = "The quick brown fox jumps over the lazy dog.";
|
||||
final int dist = LatinIMEUtil.editDistance(arg, arg);
|
||||
assertEquals("when same string references are passed, the distance equals 0.",
|
||||
0, dist);
|
||||
}
|
||||
|
||||
public void testNullArg() {
|
||||
try {
|
||||
LatinIMEUtil.editDistance(null, "aaa");
|
||||
fail("IllegalArgumentException should be thrown.");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
try {
|
||||
LatinIMEUtil.editDistance("aaa", null);
|
||||
fail("IllegalArgumentException should be thrown.");
|
||||
} catch (Exception e) {
|
||||
assertTrue(e instanceof IllegalArgumentException);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue