Merge "Load UserDictionary and AutoDictionary in a background thread."
commit
21daa53245
|
@ -96,11 +96,14 @@ public class AutoDictionary extends ExpandableDictionary {
|
|||
return frequency >= VALIDITY_THRESHOLD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mOpenHelper.close();
|
||||
super.close();
|
||||
}
|
||||
|
||||
private void loadDictionary() {
|
||||
@Override
|
||||
public void loadDictionaryAsync() {
|
||||
// Load the words that correspond to the current input locale
|
||||
Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale });
|
||||
if (cursor.moveToFirst()) {
|
||||
|
@ -183,15 +186,6 @@ public class AutoDictionary extends ExpandableDictionary {
|
|||
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);
|
||||
|
|
|
@ -35,15 +35,8 @@ public class ContactsDictionary extends ExpandableDictionary {
|
|||
|
||||
private ContentObserver mObserver;
|
||||
|
||||
private boolean mRequiresReload;
|
||||
|
||||
private long mLastLoadedContacts;
|
||||
|
||||
private boolean mUpdatingContacts;
|
||||
|
||||
// Use this lock before touching mUpdatingContacts & mRequiresDownload
|
||||
private Object mUpdatingLock = new Object();
|
||||
|
||||
public ContactsDictionary(Context context) {
|
||||
super(context);
|
||||
// Perform a managed query. The Activity will handle closing and requerying the cursor
|
||||
|
@ -53,15 +46,10 @@ public class ContactsDictionary extends ExpandableDictionary {
|
|||
cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean self) {
|
||||
synchronized (mUpdatingLock) {
|
||||
mRequiresReload = true;
|
||||
}
|
||||
setRequiresReload(true);
|
||||
}
|
||||
});
|
||||
|
||||
synchronized (mUpdatingLock) {
|
||||
loadDictionaryAsyncLocked();
|
||||
}
|
||||
loadDictionary();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
|
@ -69,41 +57,26 @@ public class ContactsDictionary extends ExpandableDictionary {
|
|||
getContext().getContentResolver().unregisterContentObserver(mObserver);
|
||||
mObserver = null;
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
private synchronized void loadDictionaryAsyncLocked() {
|
||||
@Override
|
||||
public void startDictionaryLoadingTaskLocked() {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
if (mLastLoadedContacts == 0
|
||||
|| now - mLastLoadedContacts > 30 * 60 * 1000 /* 30 minutes */) {
|
||||
if (!mUpdatingContacts) {
|
||||
mUpdatingContacts = true;
|
||||
mRequiresReload = false;
|
||||
new LoadContactsTask().execute();
|
||||
}
|
||||
super.startDictionaryLoadingTaskLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void getWords(final WordComposer codes, final WordCallback callback,
|
||||
int[] nextLettersFrequencies) {
|
||||
synchronized (mUpdatingLock) {
|
||||
// If we need to update, start off a background task
|
||||
if (mRequiresReload) loadDictionaryAsyncLocked();
|
||||
// Currently updating contacts, don't return any results.
|
||||
if (mUpdatingContacts) return;
|
||||
public void loadDictionaryAsync() {
|
||||
Cursor cursor = getContext().getContentResolver()
|
||||
.query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
|
||||
if (cursor != null) {
|
||||
addWords(cursor);
|
||||
}
|
||||
super.getWords(codes, callback, nextLettersFrequencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isValidWord(CharSequence word) {
|
||||
synchronized (mUpdatingLock) {
|
||||
// If we need to update, start off a background task
|
||||
if (mRequiresReload) loadDictionaryAsyncLocked();
|
||||
if (mUpdatingContacts) return false;
|
||||
}
|
||||
|
||||
return super.isValidWord(word);
|
||||
mLastLoadedContacts = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
private void addWords(Cursor cursor) {
|
||||
|
@ -150,27 +123,5 @@ public class ContactsDictionary extends ExpandableDictionary {
|
|||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
private class LoadContactsTask extends AsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(Void... v) {
|
||||
Cursor cursor = getContext().getContentResolver()
|
||||
.query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
|
||||
if (cursor != null) {
|
||||
addWords(cursor);
|
||||
}
|
||||
mLastLoadedContacts = SystemClock.uptimeMillis();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
// TODO Auto-generated method stub
|
||||
synchronized (mUpdatingLock) {
|
||||
mUpdatingContacts = false;
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import com.android.inputmethod.latin.Dictionary.WordCallback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.SystemClock;
|
||||
|
||||
/**
|
||||
* Base class for an in-memory dictionary that can grow dynamically and can
|
||||
|
@ -32,6 +36,13 @@ public class ExpandableDictionary extends Dictionary {
|
|||
public static final int MAX_WORD_LENGTH = 32;
|
||||
private static final char QUOTE = '\'';
|
||||
|
||||
private boolean mRequiresReload;
|
||||
|
||||
private boolean mUpdatingDictionary;
|
||||
|
||||
// Use this lock before touching mUpdatingDictionary & mRequiresDownload
|
||||
private Object mUpdatingLock = new Object();
|
||||
|
||||
static class Node {
|
||||
char code;
|
||||
int frequency;
|
||||
|
@ -70,6 +81,34 @@ public class ExpandableDictionary extends Dictionary {
|
|||
mCodes = new int[MAX_WORD_LENGTH][];
|
||||
}
|
||||
|
||||
public void loadDictionary() {
|
||||
synchronized (mUpdatingLock) {
|
||||
startDictionaryLoadingTaskLocked();
|
||||
}
|
||||
}
|
||||
|
||||
public void startDictionaryLoadingTaskLocked() {
|
||||
if (!mUpdatingDictionary) {
|
||||
mUpdatingDictionary = true;
|
||||
mRequiresReload = false;
|
||||
new LoadDictionaryTask().execute();
|
||||
}
|
||||
}
|
||||
|
||||
public void setRequiresReload(boolean reload) {
|
||||
synchronized (mUpdatingLock) {
|
||||
mRequiresReload = reload;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getRequiresReload() {
|
||||
return mRequiresReload;
|
||||
}
|
||||
|
||||
/** Override to load your dictionary here, on a background thread. */
|
||||
public void loadDictionaryAsync() {
|
||||
}
|
||||
|
||||
Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
@ -119,6 +158,13 @@ public class ExpandableDictionary extends Dictionary {
|
|||
@Override
|
||||
public void getWords(final WordComposer codes, final WordCallback callback,
|
||||
int[] nextLettersFrequencies) {
|
||||
synchronized (mUpdatingLock) {
|
||||
// If we need to update, start off a background task
|
||||
if (mRequiresReload) startDictionaryLoadingTaskLocked();
|
||||
// Currently updating contacts, don't return any results.
|
||||
if (mUpdatingDictionary) return;
|
||||
}
|
||||
|
||||
mInputLength = codes.size();
|
||||
mNextLettersFrequencies = nextLettersFrequencies;
|
||||
if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
|
||||
|
@ -135,6 +181,11 @@ public class ExpandableDictionary extends Dictionary {
|
|||
|
||||
@Override
|
||||
public synchronized boolean isValidWord(CharSequence word) {
|
||||
synchronized (mUpdatingLock) {
|
||||
// If we need to update, start off a background task
|
||||
if (mRequiresReload) startDictionaryLoadingTaskLocked();
|
||||
if (mUpdatingDictionary) return false;
|
||||
}
|
||||
final int freq = getWordFrequencyRec(mRoots, word, 0, word.length());
|
||||
return freq > -1;
|
||||
}
|
||||
|
@ -277,6 +328,24 @@ public class ExpandableDictionary extends Dictionary {
|
|||
mRoots = new NodeArray();
|
||||
}
|
||||
|
||||
private class LoadDictionaryTask extends AsyncTask<Void, Void, Void> {
|
||||
@Override
|
||||
protected Void doInBackground(Void... v) {
|
||||
loadDictionaryAsync();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
// TODO Auto-generated method stub
|
||||
synchronized (mUpdatingLock) {
|
||||
mUpdatingDictionary = false;
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static char toLowerCase(char c) {
|
||||
if (c < BASE_CHARS.length) {
|
||||
c = BASE_CHARS[c];
|
||||
|
|
|
@ -16,16 +16,11 @@
|
|||
|
||||
package com.android.inputmethod.latin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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,8 +35,6 @@ public class UserDictionary extends ExpandableDictionary {
|
|||
private static final int INDEX_FREQUENCY = 2;
|
||||
|
||||
private ContentObserver mObserver;
|
||||
|
||||
private boolean mRequiresReload;
|
||||
private String mLocale;
|
||||
|
||||
public UserDictionary(Context context, String locale) {
|
||||
|
@ -54,26 +47,27 @@ public class UserDictionary extends ExpandableDictionary {
|
|||
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean self) {
|
||||
mRequiresReload = true;
|
||||
setRequiresReload(true);
|
||||
}
|
||||
});
|
||||
|
||||
loadDictionary();
|
||||
}
|
||||
|
||||
|
||||
public synchronized void close() {
|
||||
if (mObserver != null) {
|
||||
getContext().getContentResolver().unregisterContentObserver(mObserver);
|
||||
mObserver = null;
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
private synchronized void loadDictionary() {
|
||||
|
||||
@Override
|
||||
public void loadDictionaryAsync() {
|
||||
Cursor cursor = getContext().getContentResolver()
|
||||
.query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)",
|
||||
new String[] { mLocale }, null);
|
||||
addWords(cursor);
|
||||
mRequiresReload = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +80,8 @@ public class UserDictionary extends ExpandableDictionary {
|
|||
*/
|
||||
@Override
|
||||
public synchronized void addWord(String word, int frequency) {
|
||||
if (mRequiresReload) loadDictionary();
|
||||
// Force load the dictionary here synchronously
|
||||
if (getRequiresReload()) loadDictionaryAsync();
|
||||
// Safeguard against adding long words. Can cause stack overflow.
|
||||
if (word.length() >= getMaxWordLength()) return;
|
||||
|
||||
|
@ -101,19 +96,17 @@ public class UserDictionary extends ExpandableDictionary {
|
|||
|
||||
getContext().getContentResolver().insert(Words.CONTENT_URI, values);
|
||||
// In case the above does a synchronous callback of the change observer
|
||||
mRequiresReload = false;
|
||||
setRequiresReload(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void getWords(final WordComposer codes, final WordCallback callback,
|
||||
int[] nextLettersFrequencies) {
|
||||
if (mRequiresReload) loadDictionary();
|
||||
super.getWords(codes, callback, nextLettersFrequencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isValidWord(CharSequence word) {
|
||||
if (mRequiresReload) loadDictionary();
|
||||
return super.isValidWord(word);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue