From f4223452119f9ff8b52f026f7ef92d961736dc51 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 15 Jul 2011 07:57:26 +0900 Subject: Rename AutoDictionary to UserUnigramDictionary. ...and adjust internal functions, variables and constant names. Bug: 3459274 Change-Id: I1b11c6adfee360ac0fc22d627955688b3dbdcffc --- .../android/inputmethod/latin/AutoDictionary.java | 250 --------------------- .../com/android/inputmethod/latin/LatinIME.java | 39 ++-- .../src/com/android/inputmethod/latin/Suggest.java | 22 +- .../inputmethod/latin/UserUnigramDictionary.java | 250 +++++++++++++++++++++ 4 files changed, 286 insertions(+), 275 deletions(-) delete mode 100644 java/src/com/android/inputmethod/latin/AutoDictionary.java create mode 100644 java/src/com/android/inputmethod/latin/UserUnigramDictionary.java (limited to 'java/src') diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java deleted file mode 100644 index 460930f16..000000000 --- a/java/src/com/android/inputmethod/latin/AutoDictionary.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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.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.os.AsyncTask; -import android.provider.BaseColumns; -import android.util.Log; - -import java.util.HashMap; -import java.util.Map.Entry; -import java.util.Set; - -/** - * 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; - // 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; - - private LatinIME mIme; - // Locale for which this auto dictionary is storing words - private String mLocale; - - private HashMap mPendingWrites = new HashMap(); - private final Object mPendingWritesLock = new Object(); - - 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 sDictProjectionMap; - - static { - sDictProjectionMap = new HashMap(); - 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 static DatabaseHelper sOpenHelper = null; - - public AutoDictionary(Context context, LatinIME ime, String locale, int dicTypeId) { - super(context, dicTypeId); - mIme = ime; - mLocale = locale; - if (sOpenHelper == null) { - sOpenHelper = new DatabaseHelper(getContext()); - } - if (mLocale != null && mLocale.length() > 1) { - loadDictionary(); - } - } - - @Override - public synchronized boolean isValidWord(CharSequence word) { - final int frequency = getWordFrequency(word); - return frequency >= VALIDITY_THRESHOLD; - } - - @Override - public void close() { - flushPendingWrites(); - // Don't close the database as locale changes will require it to be reopened anyway - // Also, the database is written to somewhat frequently, so it needs to be kept alive - // throughout the life of the process. - // mOpenHelper.close(); - super.close(); - } - - @Override - public void loadDictionaryAsync() { - // Load the words that correspond to the current input locale - Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale }); - try { - 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(); - } - } - } finally { - cursor.close(); - } - } - - @Override - public void addWord(String newWord, int addFrequency) { - String word = newWord; - 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); - - synchronized (mPendingWritesLock) { - // Write a null frequency if it is to be deleted from the db - mPendingWrites.put(word, freq == 0 ? null : new Integer(freq)); - } - } - - /** - * Schedules a background thread to write any pending words to the database. - */ - public void flushPendingWrites() { - synchronized (mPendingWritesLock) { - // Nothing pending? Return - if (mPendingWrites.isEmpty()) return; - // Create a background thread to write the pending entries - new UpdateDbTask(getContext(), sOpenHelper, mPendingWrites, mLocale).execute(); - // Create a new map for writing new entries into while the old one is written to db - mPendingWrites = new HashMap(); - } - } - - /** - * 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 = sOpenHelper.getReadableDatabase(); - Cursor c = qb.query(db, null, selection, selectionArgs, null, null, - DEFAULT_SORT_ORDER); - return c; - } - - /** - * Async task to write pending words to the database so that it stays in sync with - * the in-memory trie. - */ - private static class UpdateDbTask extends AsyncTask { - private final HashMap mMap; - private final DatabaseHelper mDbHelper; - private final String mLocale; - - public UpdateDbTask(@SuppressWarnings("unused") Context context, DatabaseHelper openHelper, - HashMap pendingWrites, String locale) { - mMap = pendingWrites; - mLocale = locale; - mDbHelper = openHelper; - } - - @Override - protected Void doInBackground(Void... v) { - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - // Write all the entries to the db - Set> mEntries = mMap.entrySet(); - for (Entry entry : mEntries) { - Integer freq = entry.getValue(); - db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + "=?", - new String[] { entry.getKey(), mLocale }); - if (freq != null) { - db.insert(AUTODICT_TABLE_NAME, null, - getContentValues(entry.getKey(), freq, mLocale)); - } - } - return null; - } - - 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/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5304d830d..ae32a3cad 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -155,7 +155,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private UserDictionary mUserDictionary; private UserBigramDictionary mUserBigramDictionary; - private AutoDictionary mAutoDictionary; + private UserUnigramDictionary mUserUnigramDictionary; // TODO: Create an inner class to group options and pseudo-options to improve readability. // These variables are initialized according to the {@link EditorInfo#inputType}. @@ -443,10 +443,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar resetContactsDictionary(); - mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO); - mSuggest.setAutoDictionary(mAutoDictionary); + mUserUnigramDictionary + = new UserUnigramDictionary(this, this, localeStr, Suggest.DIC_USER_UNIGRAM); + mSuggest.setUserUnigramDictionary(mUserUnigramDictionary); - mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER); + mUserBigramDictionary + = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER_BIGRAM); mSuggest.setUserBigramDictionary(mUserBigramDictionary); updateCorrectionMode(); @@ -672,7 +674,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.closing(); - if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites(); + if (mUserUnigramDictionary != null) mUserUnigramDictionary.flushPendingWrites(); if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites(); } @@ -951,8 +953,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mCommittedLength = mComposingStringBuilder.length(); TextEntryState.acceptedTyped(mComposingStringBuilder); - addToAutoAndUserBigramDictionaries(mComposingStringBuilder, - AutoDictionary.FREQUENCY_FOR_TYPED); + addToUserUnigramAndBigramDictionaries(mComposingStringBuilder, + UserUnigramDictionary.FREQUENCY_FOR_TYPED); } updateSuggestions(); } @@ -1557,8 +1559,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode); mExpectingUpdateSelection = true; commitBestWord(mBestWord); - // Add the word to the auto dictionary if it's not a known word - addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED); + // Add the word to the user unigram dictionary if it's not a known word + addToUserUnigramAndBigramDictionaries(mBestWord, + UserUnigramDictionary.FREQUENCY_FOR_TYPED); return true; } return false; @@ -1627,7 +1630,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar commitBestWord(suggestion); // Add the word to the auto dictionary if it's not a known word if (index == 0) { - addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED); + addToUserUnigramAndBigramDictionaries(suggestion, + UserUnigramDictionary.FREQUENCY_FOR_PICKED); } else { addToOnlyBigramDictionary(suggestion, 1); } @@ -1725,7 +1729,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setSuggestionStripShown(isCandidateStripVisible()); } - private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) { + private void addToUserUnigramAndBigramDictionaries(CharSequence suggestion, + int frequencyDelta) { checkAddToDictionary(suggestion, frequencyDelta, false); } @@ -1734,7 +1739,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } /** - * Adds to the UserBigramDictionary and/or AutoDictionary + * Adds to the UserBigramDictionary and/or UserUnigramDictionary * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible */ private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta, @@ -1749,14 +1754,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return; } - final boolean selectedATypedWordAndItsInAutoDic = - !selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion); + final boolean selectedATypedWordAndItsInUserUnigramDic = + !selectedANotTypedWord && mUserUnigramDictionary.isValidWord(suggestion); final boolean isValidWord = AutoCorrection.isValidWord( mSuggest.getUnigramDictionaries(), suggestion, true); - final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic + final boolean needsToAddToUserUnigramDictionary = selectedATypedWordAndItsInUserUnigramDic || !isValidWord; - if (needsToAddToAutoDictionary) { - mAutoDictionary.addWord(suggestion.toString(), frequencyDelta); + if (needsToAddToUserUnigramDictionary) { + mUserUnigramDictionary.addWord(suggestion.toString(), frequencyDelta); } if (mUserBigramDictionary != null) { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index eb5ed5a65..8ae653f2f 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -60,18 +60,24 @@ public class Suggest implements Dictionary.WordCallback { */ public static final int MAXIMUM_BIGRAM_FREQUENCY = 127; + // It seems the following values are only used for logging. public static final int DIC_USER_TYPED = 0; public static final int DIC_MAIN = 1; public static final int DIC_USER = 2; - public static final int DIC_AUTO = 3; + public static final int DIC_USER_UNIGRAM = 3; public static final int DIC_CONTACTS = 4; + public static final int DIC_USER_BIGRAM = 5; // If you add a type of dictionary, increment DIC_TYPE_LAST_ID - public static final int DIC_TYPE_LAST_ID = 4; + // TODO: this value seems unused. Remove it? + public static final int DIC_TYPE_LAST_ID = 5; public static final String DICT_KEY_MAIN = "main"; public static final String DICT_KEY_CONTACTS = "contacts"; - public static final String DICT_KEY_AUTO = "auto"; + // User dictionary, the system-managed one. public static final String DICT_KEY_USER = "user"; + // User unigram dictionary, internal to LatinIME + public static final String DICT_KEY_USER_UNIGRAM = "user_unigram"; + // User bigram dictionary, internal to LatinIME public static final String DICT_KEY_USER_BIGRAM = "user_bigram"; public static final String DICT_KEY_WHITELIST ="whitelist"; @@ -177,7 +183,7 @@ public class Suggest implements Dictionary.WordCallback { /** * Sets an optional user dictionary resource to be loaded. The user dictionary is consulted - * before the main dictionary, if set. + * before the main dictionary, if set. This refers to the system-managed user dictionary. */ public void setUserDictionary(Dictionary userDictionary) { addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_USER, userDictionary); @@ -193,8 +199,8 @@ public class Suggest implements Dictionary.WordCallback { addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_CONTACTS, contactsDictionary); } - public void setAutoDictionary(Dictionary autoDictionary) { - addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_AUTO, autoDictionary); + public void setUserUnigramDictionary(Dictionary userUnigramDictionary) { + addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_USER_UNIGRAM, userUnigramDictionary); } public void setUserBigramDictionary(Dictionary userBigramDictionary) { @@ -335,8 +341,8 @@ public class Suggest implements Dictionary.WordCallback { } else if (wordComposer.size() > 1) { // At second character typed, search the unigrams (scores being affected by bigrams) for (final String key : mUnigramDictionaries.keySet()) { - // Skip AutoDictionary and WhitelistDictionary to lookup - if (key.equals(DICT_KEY_AUTO) || key.equals(DICT_KEY_WHITELIST)) + // Skip UserUnigramDictionary and WhitelistDictionary to lookup + if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = mUnigramDictionaries.get(key); dictionary.getWords(wordComposer, this); diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java new file mode 100644 index 000000000..382d64030 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -0,0 +1,250 @@ +/* + * 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.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.os.AsyncTask; +import android.provider.BaseColumns; +import android.util.Log; + +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.Set; + +/** + * This class (inherited from the old AutoDictionary) is used for user history + * based dictionary. It stores words that the user typed to supply a provision + * for suggesting and re-ordering of candidates. + */ +public class UserUnigramDictionary 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; + // 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; + + private LatinIME mIme; + // Locale for which this user unigram dictionary is storing words + private String mLocale; + + private HashMap mPendingWrites = new HashMap(); + private final Object mPendingWritesLock = new Object(); + + // TODO: we should probably change the database name + 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 database */ + private static final String USER_UNIGRAM_DICT_TABLE_NAME = "words"; + + private static HashMap sDictProjectionMap; + + static { + sDictProjectionMap = new HashMap(); + 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 static DatabaseHelper sOpenHelper = null; + + public UserUnigramDictionary(Context context, LatinIME ime, String locale, int dicTypeId) { + super(context, dicTypeId); + mIme = ime; + mLocale = locale; + if (sOpenHelper == null) { + sOpenHelper = new DatabaseHelper(getContext()); + } + if (mLocale != null && mLocale.length() > 1) { + loadDictionary(); + } + } + + @Override + public synchronized boolean isValidWord(CharSequence word) { + final int frequency = getWordFrequency(word); + return frequency >= VALIDITY_THRESHOLD; + } + + @Override + public void close() { + flushPendingWrites(); + // Don't close the database as locale changes will require it to be reopened anyway + // Also, the database is written to somewhat frequently, so it needs to be kept alive + // throughout the life of the process. + // mOpenHelper.close(); + super.close(); + } + + @Override + public void loadDictionaryAsync() { + // Load the words that correspond to the current input locale + Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale }); + try { + 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(); + } + } + } finally { + cursor.close(); + } + } + + @Override + public void addWord(String newWord, int addFrequency) { + String word = newWord; + 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); + + synchronized (mPendingWritesLock) { + // Write a null frequency if it is to be deleted from the db + mPendingWrites.put(word, freq == 0 ? null : new Integer(freq)); + } + } + + /** + * Schedules a background thread to write any pending words to the database. + */ + public void flushPendingWrites() { + synchronized (mPendingWritesLock) { + // Nothing pending? Return + if (mPendingWrites.isEmpty()) return; + // Create a background thread to write the pending entries + new UpdateDbTask(getContext(), sOpenHelper, mPendingWrites, mLocale).execute(); + // Create a new map for writing new entries into while the old one is written to db + mPendingWrites = new HashMap(); + } + } + + /** + * 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 " + USER_UNIGRAM_DICT_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("UserUnigramDictionary", "Upgrading database from version " + oldVersion + " to " + + newVersion + ", which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS " + USER_UNIGRAM_DICT_TABLE_NAME); + onCreate(db); + } + } + + private Cursor query(String selection, String[] selectionArgs) { + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + qb.setTables(USER_UNIGRAM_DICT_TABLE_NAME); + qb.setProjectionMap(sDictProjectionMap); + + // Get the database and run the query + SQLiteDatabase db = sOpenHelper.getReadableDatabase(); + Cursor c = qb.query(db, null, selection, selectionArgs, null, null, + DEFAULT_SORT_ORDER); + return c; + } + + /** + * Async task to write pending words to the database so that it stays in sync with + * the in-memory trie. + */ + private static class UpdateDbTask extends AsyncTask { + private final HashMap mMap; + private final DatabaseHelper mDbHelper; + private final String mLocale; + + public UpdateDbTask(@SuppressWarnings("unused") Context context, DatabaseHelper openHelper, + HashMap pendingWrites, String locale) { + mMap = pendingWrites; + mLocale = locale; + mDbHelper = openHelper; + } + + @Override + protected Void doInBackground(Void... v) { + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + // Write all the entries to the db + Set> mEntries = mMap.entrySet(); + for (Entry entry : mEntries) { + Integer freq = entry.getValue(); + db.delete(USER_UNIGRAM_DICT_TABLE_NAME, COLUMN_WORD + "=? AND " + COLUMN_LOCALE + + "=?", new String[] { entry.getKey(), mLocale }); + if (freq != null) { + db.insert(USER_UNIGRAM_DICT_TABLE_NAME, null, + getContentValues(entry.getKey(), freq, mLocale)); + } + } + return null; + } + + 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; + } + } +} -- cgit v1.2.3-83-g751a