aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/inputmethod/latin/AutoDictionary.java217
-rw-r--r--src/com/android/inputmethod/latin/InputLanguageSelection.java7
-rw-r--r--src/com/android/inputmethod/latin/KeyboardSwitcher.java1
-rw-r--r--src/com/android/inputmethod/latin/LanguageSwitcher.java6
-rw-r--r--src/com/android/inputmethod/latin/LatinIME.java82
-rw-r--r--src/com/android/inputmethod/latin/UserDictionary.java19
6 files changed, 251 insertions, 81 deletions
diff --git a/src/com/android/inputmethod/latin/AutoDictionary.java b/src/com/android/inputmethod/latin/AutoDictionary.java
new file mode 100644
index 000000000..3d76dc301
--- /dev/null
+++ b/src/com/android/inputmethod/latin/AutoDictionary.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 java.util.HashMap;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.provider.BaseColumns;
+import android.provider.UserDictionary.Words;
+import android.util.Log;
+
+/**
+ * Stores new words temporarily until they are promoted to the user dictionary
+ * for longevity. Words in the auto dictionary are used to determine if it's ok
+ * to accept a word that's not in the main or user dictionary. Using a new word
+ * repeatedly will promote it to the user dictionary.
+ */
+public class AutoDictionary extends ExpandableDictionary {
+ // Weight added to a user picking a new word from the suggestion strip
+ static final int FREQUENCY_FOR_PICKED = 3;
+ // Weight added to a user typing a new word that doesn't get corrected (or is reverted)
+ static final int FREQUENCY_FOR_TYPED = 1;
+ // A word that is frequently typed and gets promoted to the user dictionary, uses this
+ // frequency.
+ static final int FREQUENCY_FOR_AUTO_ADD = 250;
+ // If the user touches a typed word 2 times or more, it will become valid.
+ private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED;
+ // If the user touches a typed word 4 times or more, it will be added to the user dict.
+ private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED;
+
+ private LatinIME mIme;
+ // Locale for which this auto dictionary is storing words
+ private String mLocale;
+
+ private static final String DATABASE_NAME = "auto_dict.db";
+ private static final int DATABASE_VERSION = 1;
+
+ // These are the columns in the dictionary
+ // TODO: Consume less space by using a unique id for locale instead of the whole
+ // 2-5 character string.
+ private static final String COLUMN_ID = BaseColumns._ID;
+ private static final String COLUMN_WORD = "word";
+ private static final String COLUMN_FREQUENCY = "freq";
+ private static final String COLUMN_LOCALE = "locale";
+
+ /** Sort by descending order of frequency. */
+ public static final String DEFAULT_SORT_ORDER = COLUMN_FREQUENCY + " DESC";
+
+ /** Name of the words table in the auto_dict.db */
+ private static final String AUTODICT_TABLE_NAME = "words";
+
+ private static HashMap<String, String> sDictProjectionMap;
+
+ static {
+ sDictProjectionMap = new HashMap<String, String>();
+ sDictProjectionMap.put(COLUMN_ID, COLUMN_ID);
+ sDictProjectionMap.put(COLUMN_WORD, COLUMN_WORD);
+ sDictProjectionMap.put(COLUMN_FREQUENCY, COLUMN_FREQUENCY);
+ sDictProjectionMap.put(COLUMN_LOCALE, COLUMN_LOCALE);
+ }
+
+ private DatabaseHelper mOpenHelper;
+
+ public AutoDictionary(Context context, LatinIME ime, String locale) {
+ super(context);
+ mIme = ime;
+ mLocale = locale;
+ mOpenHelper = new DatabaseHelper(getContext());
+ if (mLocale != null && mLocale.length() > 1) {
+ loadDictionary();
+ }
+ }
+
+ @Override
+ public boolean isValidWord(CharSequence word) {
+ final int frequency = getWordFrequency(word);
+ return frequency >= VALIDITY_THRESHOLD;
+ }
+
+ public void close() {
+ mOpenHelper.close();
+ }
+
+ private void loadDictionary() {
+ // Load the words that correspond to the current input locale
+ Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale });
+ if (cursor.moveToFirst()) {
+ int wordIndex = cursor.getColumnIndex(COLUMN_WORD);
+ int frequencyIndex = cursor.getColumnIndex(COLUMN_FREQUENCY);
+ while (!cursor.isAfterLast()) {
+ String word = cursor.getString(wordIndex);
+ int frequency = cursor.getInt(frequencyIndex);
+ // Safeguard against adding really long words. Stack may overflow due
+ // to recursive lookup
+ if (word.length() < getMaxWordLength()) {
+ super.addWord(word, frequency);
+ }
+ cursor.moveToNext();
+ }
+ }
+ cursor.close();
+ }
+
+ @Override
+ public void addWord(String word, int addFrequency) {
+ final int length = word.length();
+ // Don't add very short or very long words.
+ if (length < 2 || length > getMaxWordLength()) return;
+ if (mIme.getCurrentWord().isAutoCapitalized()) {
+ // Remove caps before adding
+ word = Character.toLowerCase(word.charAt(0)) + word.substring(1);
+ }
+ int freq = getWordFrequency(word);
+ freq = freq < 0 ? addFrequency : freq + addFrequency;
+ super.addWord(word, freq);
+ if (freq >= PROMOTION_THRESHOLD) {
+ mIme.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD);
+ // Delete the word (for input locale) from the auto dictionary db, as it
+ // is now in the user dictionary provider.
+ delete(COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?",
+ new String[] { word, mLocale });
+ } else {
+ update(word, freq, mLocale);
+ }
+ }
+
+ /**
+ * This class helps open, create, and upgrade the database file.
+ */
+ private static class DatabaseHelper extends SQLiteOpenHelper {
+
+ DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + AUTODICT_TABLE_NAME + " ("
+ + COLUMN_ID + " INTEGER PRIMARY KEY,"
+ + COLUMN_WORD + " TEXT,"
+ + COLUMN_FREQUENCY + " INTEGER,"
+ + COLUMN_LOCALE + " TEXT"
+ + ");");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.w("AutoDictionary", "Upgrading database from version " + oldVersion + " to "
+ + newVersion + ", which will destroy all old data");
+ db.execSQL("DROP TABLE IF EXISTS " + AUTODICT_TABLE_NAME);
+ onCreate(db);
+ }
+ }
+
+ private Cursor query(String selection, String[] selectionArgs) {
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(AUTODICT_TABLE_NAME);
+ qb.setProjectionMap(sDictProjectionMap);
+
+ // Get the database and run the query
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor c = qb.query(db, null, selection, selectionArgs, null, null,
+ DEFAULT_SORT_ORDER);
+ return c;
+ }
+
+ private boolean insert(ContentValues values) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ long rowId = db.insert(AUTODICT_TABLE_NAME, Words.WORD, values);
+ if (rowId > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private int delete(String where, String[] whereArgs) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ int count = db.delete(AUTODICT_TABLE_NAME, where, whereArgs);
+ return count;
+ }
+
+ private int update(String word, int frequency, String locale) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ long count = db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?",
+ new String[] { word, locale });
+ count = db.insert(AUTODICT_TABLE_NAME, null,
+ getContentValues(word, frequency, locale));
+ return (int) count;
+ }
+
+ private ContentValues getContentValues(String word, int frequency, String locale) {
+ ContentValues values = new ContentValues(4);
+ values.put(COLUMN_WORD, word);
+ values.put(COLUMN_FREQUENCY, frequency);
+ values.put(COLUMN_LOCALE, locale);
+ return values;
+ }
+}
diff --git a/src/com/android/inputmethod/latin/InputLanguageSelection.java b/src/com/android/inputmethod/latin/InputLanguageSelection.java
index 2c5fec6e8..73298e33c 100644
--- a/src/com/android/inputmethod/latin/InputLanguageSelection.java
+++ b/src/com/android/inputmethod/latin/InputLanguageSelection.java
@@ -19,7 +19,6 @@ package com.android.inputmethod.latin;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
import java.util.Locale;
import android.content.SharedPreferences;
@@ -29,7 +28,7 @@ import android.preference.CheckBoxPreference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
-import android.util.Log;
+import android.text.TextUtils;
public class InputLanguageSelection extends PreferenceActivity {
@@ -91,7 +90,9 @@ public class InputLanguageSelection extends PreferenceActivity {
}
private String get5Code(Locale locale) {
- return locale.getLanguage() + "_" + locale.getCountry();
+ String country = locale.getCountry();
+ return locale.getLanguage()
+ + (TextUtils.isEmpty(country) ? "" : "_" + country);
}
@Override
diff --git a/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/src/com/android/inputmethod/latin/KeyboardSwitcher.java
index 529edeb81..38979edde 100644
--- a/src/com/android/inputmethod/latin/KeyboardSwitcher.java
+++ b/src/com/android/inputmethod/latin/KeyboardSwitcher.java
@@ -180,6 +180,7 @@ public class KeyboardSwitcher {
void setKeyboardMode(int mode, int imeOptions,
boolean enableVoice, boolean isSymbols) {
+ if (mInputView == null) return;
mMode = mode;
mImeOptions = imeOptions;
mHasVoice = enableVoice;
diff --git a/src/com/android/inputmethod/latin/LanguageSwitcher.java b/src/com/android/inputmethod/latin/LanguageSwitcher.java
index 68d0d15cc..12045125f 100644
--- a/src/com/android/inputmethod/latin/LanguageSwitcher.java
+++ b/src/com/android/inputmethod/latin/LanguageSwitcher.java
@@ -21,6 +21,7 @@ import java.util.Locale;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;
+import android.text.TextUtils;
/**
* Keeps track of list of selected input languages and the current
@@ -88,8 +89,9 @@ public class LanguageSwitcher {
private void loadDefaults() {
mDefaultInputLocale = mIme.getResources().getConfiguration().locale;
- mDefaultInputLanguage = mDefaultInputLocale.getLanguage() + "_"
- + mDefaultInputLocale.getCountry();
+ String country = mDefaultInputLocale.getCountry();
+ mDefaultInputLanguage = mDefaultInputLocale.getLanguage() +
+ (TextUtils.isEmpty(country) ? "" : "_" + country);
}
private void constructLocales() {
diff --git a/src/com/android/inputmethod/latin/LatinIME.java b/src/com/android/inputmethod/latin/LatinIME.java
index 5022a2cba..e08af1ad9 100644
--- a/src/com/android/inputmethod/latin/LatinIME.java
+++ b/src/com/android/inputmethod/latin/LatinIME.java
@@ -130,21 +130,10 @@ public class LatinIME extends InputMethodService
// ignored, since it may in fact be two key presses in quick succession.
private static final long MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE = 1000;
- // If we detect a swipe gesture, and the user types N ms later, cancel the
- // swipe since it was probably a false trigger.
- private static final long MIN_MILLIS_AFTER_SWIPE_TO_WAIT_FOR_TYPING = 500;
-
// How many continuous deletes at which to start deleting at a higher speed.
private static final int DELETE_ACCELERATE_AT = 20;
// Key events coming any faster than this are long-presses.
private static final int QUICK_PRESS = 200;
- // Weight added to a user picking a new word from the suggestion strip
- static final int FREQUENCY_FOR_PICKED = 3;
- // Weight added to a user typing a new word that doesn't get corrected (or is reverted)
- static final int FREQUENCY_FOR_TYPED = 1;
- // A word that is frequently typed and get's promoted to the user dictionary, uses this
- // frequency.
- static final int FREQUENCY_FOR_AUTO_ADD = 250;
static final int KEYCODE_ENTER = '\n';
static final int KEYCODE_SPACE = ' ';
@@ -329,14 +318,14 @@ public class LatinIME extends InputMethodService
mSuggest = new Suggest(this, R.raw.main);
updateAutoTextEnabled(saveLocale);
if (mUserDictionary != null) mUserDictionary.close();
- mUserDictionary = new UserDictionary(this);
+ mUserDictionary = new UserDictionary(this, mLocale);
if (mContactsDictionary == null) {
mContactsDictionary = new ContactsDictionary(this);
}
- // TODO: Save and restore the dictionary for the current input language.
- if (mAutoDictionary == null) {
- mAutoDictionary = new AutoDictionary(this);
+ if (mAutoDictionary != null) {
+ mAutoDictionary.close();
}
+ mAutoDictionary = new AutoDictionary(this, this, mLocale);
mSuggest.setUserDictionary(mUserDictionary);
mSuggest.setContactsDictionary(mContactsDictionary);
mSuggest.setAutoDictionary(mAutoDictionary);
@@ -815,7 +804,7 @@ public class LatinIME extends InputMethodService
}
mCommittedLength = mComposing.length();
TextEntryState.acceptedTyped(mComposing);
- checkAddToDictionary(mComposing, FREQUENCY_FOR_TYPED);
+ checkAddToDictionary(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
}
updateSuggestions();
}
@@ -1196,7 +1185,6 @@ public class LatinIME extends InputMethodService
private boolean isPredictionOn() {
boolean predictionOn = mPredictionOn;
- //if (isFullscreenMode()) predictionOn &= mPredictionLandscape;
return predictionOn;
}
@@ -1522,7 +1510,7 @@ public class LatinIME extends InputMethodService
}
}
// Add the word to the auto dictionary if it's not a known word
- checkAddToDictionary(suggestion, FREQUENCY_FOR_PICKED);
+ checkAddToDictionary(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
mPredicting = false;
mCommittedLength = suggestion.length();
setNextSuggestions();
@@ -1683,11 +1671,6 @@ public class LatinIME extends InputMethodService
&& !mVoiceInput.isBlacklistedField(fieldContext);
}
- private boolean fieldIsRecommendedForVoice(FieldContext fieldContext) {
- // TODO: Move this logic into the VoiceInput method.
- return !mPasswordText && !mEmailText && mVoiceInput.isRecommendedField(fieldContext);
- }
-
private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) {
return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
&& !(attribute != null && attribute.privateImeOptions != null
@@ -1718,21 +1701,6 @@ public class LatinIME extends InputMethodService
> MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE;
}
- /*
- * Only trigger a swipe action if the user hasn't typed X millis before
- * now, and if they don't type Y millis after the swipe is detected. This
- * delays the onset of the swipe action by Y millis.
- */
- private void conservativelyTriggerSwipeAction(final Runnable action) {
- if (userHasNotTypedRecently()) {
- mSwipeTriggerTimeMillis = System.currentTimeMillis();
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_START_LISTENING_AFTER_SWIPE),
- MIN_MILLIS_AFTER_SWIPE_TO_WAIT_FOR_TYPING);
- }
- }
-
-
private void playKeyClick(int primaryCode) {
// if mAudioManager is null, we don't have the ringer state yet
// mAudioManager will be set by updateRingerMode
@@ -1796,6 +1764,10 @@ public class LatinIME extends InputMethodService
mUserDictionary.addWord(word, frequency);
}
+ WordComposer getCurrentWord() {
+ return mWord;
+ }
+
private void updateCorrectionMode() {
mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
@@ -1972,38 +1944,4 @@ public class LatinIME extends InputMethodService
System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
}
- class AutoDictionary extends ExpandableDictionary {
- // If the user touches a typed word 2 times or more, it will become valid.
- private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED;
- // If the user touches a typed word 5 times or more, it will be added to the user dict.
- private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED;
-
- public AutoDictionary(Context context) {
- super(context);
- }
-
- @Override
- public boolean isValidWord(CharSequence word) {
- final int frequency = getWordFrequency(word);
- return frequency >= VALIDITY_THRESHOLD;
- }
-
- @Override
- public void addWord(String word, int addFrequency) {
- final int length = word.length();
- // Don't add very short or very long words.
- if (length < 2 || length > getMaxWordLength()) return;
- if (mWord.isAutoCapitalized()) {
- // Remove caps before adding
- word = Character.toLowerCase(word.charAt(0))
- + word.substring(1);
- }
- int freq = getWordFrequency(word);
- freq = freq < 0 ? addFrequency : freq + addFrequency;
- super.addWord(word, freq);
- if (freq >= PROMOTION_THRESHOLD) {
- LatinIME.this.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD);
- }
- }
- }
}
diff --git a/src/com/android/inputmethod/latin/UserDictionary.java b/src/com/android/inputmethod/latin/UserDictionary.java
index edd82aaa3..4b98eacce 100644
--- a/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/src/com/android/inputmethod/latin/UserDictionary.java
@@ -21,9 +21,11 @@ import java.util.List;
import java.util.Locale;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.net.Uri;
import android.provider.UserDictionary.Words;
public class UserDictionary extends ExpandableDictionary {
@@ -40,9 +42,11 @@ public class UserDictionary extends ExpandableDictionary {
private ContentObserver mObserver;
private boolean mRequiresReload;
-
- public UserDictionary(Context context) {
+ private String mLocale;
+
+ public UserDictionary(Context context, String locale) {
super(context);
+ mLocale = locale;
// Perform a managed query. The Activity will handle closing and requerying the cursor
// when needed.
ContentResolver cres = context.getContentResolver();
@@ -67,7 +71,7 @@ public class UserDictionary extends ExpandableDictionary {
private synchronized void loadDictionary() {
Cursor cursor = getContext().getContentResolver()
.query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)",
- new String[] { Locale.getDefault().toString() }, null);
+ new String[] { mLocale }, null);
addWords(cursor);
mRequiresReload = false;
}
@@ -88,7 +92,14 @@ public class UserDictionary extends ExpandableDictionary {
super.addWord(word, frequency);
- Words.addWord(getContext(), word, frequency, Words.LOCALE_TYPE_CURRENT);
+ // Update the user dictionary provider
+ ContentValues values = new ContentValues(5);
+ values.put(Words.WORD, word);
+ values.put(Words.FREQUENCY, frequency);
+ values.put(Words.LOCALE, mLocale);
+ values.put(Words.APP_ID, 0);
+
+ getContext().getContentResolver().insert(Words.CONTENT_URI, values);
// In case the above does a synchronous callback of the change observer
mRequiresReload = false;
}