Check whether contacts have changed using hashCode().

Bug: 13755213
Change-Id: Ie2f7b7f9dc8bd3fce395618877d9f234287dcb21
main
Keisuke Kuroyanagi 2014-05-08 12:25:32 +09:00
parent 04348c3637
commit 9898ee6267
4 changed files with 39 additions and 71 deletions

View File

@ -31,9 +31,12 @@ import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.personalization.AccountUtils; import com.android.inputmethod.latin.personalization.AccountUtils;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ExecutorUtils;
import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.StringUtils;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -60,7 +63,10 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
private static final int INDEX_NAME = 1; private static final int INDEX_NAME = 1;
/** The number of contacts in the most recent dictionary rebuild. */ /** The number of contacts in the most recent dictionary rebuild. */
static private int sContactCountAtLastRebuild = 0; private int mContactCountAtLastRebuild = 0;
/** The hash code of ArrayList of contacts names in the most recent dictionary rebuild. */
private int mHashCodeAtLastRebuild = 0;
private ContentObserver mObserver; private ContentObserver mObserver;
@ -96,7 +102,14 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
new ContentObserver(null) { new ContentObserver(null) {
@Override @Override
public void onChange(boolean self) { public void onChange(boolean self) {
setNeedsToReload(); ExecutorUtils.getExecutor("Check Contacts").execute(new Runnable() {
@Override
public void run() {
if (haveContentsChanged()) {
setNeedsToRecreate();
}
}
});
} }
}); });
} }
@ -143,7 +156,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
return; return;
} }
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
sContactCountAtLastRebuild = getContactCount(); mContactCountAtLastRebuild = getContactCount();
addWordsLocked(cursor); addWordsLocked(cursor);
} }
} catch (final SQLiteException e) { } catch (final SQLiteException e) {
@ -167,9 +180,11 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
private void addWordsLocked(final Cursor cursor) { private void addWordsLocked(final Cursor cursor) {
int count = 0; int count = 0;
final ArrayList<String> names = CollectionUtils.newArrayList();
while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) { while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) {
String name = cursor.getString(INDEX_NAME); String name = cursor.getString(INDEX_NAME);
if (isValidName(name)) { if (isValidName(name)) {
names.add(name);
addNameLocked(name); addNameLocked(name);
++count; ++count;
} else { } else {
@ -179,6 +194,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
} }
cursor.moveToNext(); cursor.moveToNext();
} }
mHashCodeAtLastRebuild = names.hashCode();
} }
private int getContactCount() { private int getContactCount() {
@ -258,8 +274,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
return end; return end;
} }
@Override private boolean haveContentsChanged() {
protected boolean haveContentsChanged() {
final long startTime = SystemClock.uptimeMillis(); final long startTime = SystemClock.uptimeMillis();
final int contactCount = getContactCount(); final int contactCount = getContactCount();
if (contactCount > MAX_CONTACT_COUNT) { if (contactCount > MAX_CONTACT_COUNT) {
@ -268,9 +283,9 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
// TODO: Sort and check only the MAX_CONTACT_COUNT most recent contacts? // TODO: Sort and check only the MAX_CONTACT_COUNT most recent contacts?
return false; return false;
} }
if (contactCount != sContactCountAtLastRebuild) { if (contactCount != mContactCountAtLastRebuild) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Contact count changed: " + sContactCountAtLastRebuild + " to " Log.d(TAG, "Contact count changed: " + mContactCountAtLastRebuild + " to "
+ contactCount); + contactCount);
} }
return true; return true;
@ -283,20 +298,20 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
if (null == cursor) { if (null == cursor) {
return false; return false;
} }
final ArrayList<String> names = CollectionUtils.newArrayList();
try { try {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) { while (!cursor.isAfterLast()) {
String name = cursor.getString(INDEX_NAME); String name = cursor.getString(INDEX_NAME);
if (isValidName(name) && !isNameInDictionaryLocked(name)) { if (isValidName(name)) {
if (DEBUG) { names.add(name);
Log.d(TAG, "Contact name missing: " + name + " (runtime = "
+ (SystemClock.uptimeMillis() - startTime) + " ms)");
}
return true;
} }
cursor.moveToNext(); cursor.moveToNext();
} }
} }
if (names.hashCode() != mHashCodeAtLastRebuild) {
return true;
}
} finally { } finally {
cursor.close(); cursor.close();
} }
@ -313,33 +328,4 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
} }
return false; return false;
} }
/**
* Checks if the words in a name are in the current binary dictionary.
*/
private boolean isNameInDictionaryLocked(final String name) {
int len = StringUtils.codePointCount(name);
String prevWord = null;
for (int i = 0; i < len; i++) {
if (Character.isLetter(name.codePointAt(i))) {
int end = getWordEndPosition(name, len, i);
String word = name.substring(i, end);
i = end - 1;
final int wordLen = StringUtils.codePointCount(word);
if (wordLen < MAX_WORD_LENGTH && wordLen > 1) {
if (!TextUtils.isEmpty(prevWord) && mUseFirstLastBigrams) {
if (!isValidBigramLocked(prevWord, word)) {
return false;
}
} else {
if (!isValidWordLocked(word)) {
return false;
}
}
prevWord = word;
}
}
}
return true;
}
} }

View File

@ -92,8 +92,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/** Indicates whether a task for reloading the dictionary has been scheduled. */ /** Indicates whether a task for reloading the dictionary has been scheduled. */
private final AtomicBoolean mIsReloading; private final AtomicBoolean mIsReloading;
/** Indicates whether the current dictionary needs to be reloaded. */ /** Indicates whether the current dictionary needs to be recreated. */
private boolean mNeedsToReload; private boolean mNeedsToRecreate;
private final ReentrantReadWriteLock mLock; private final ReentrantReadWriteLock mLock;
@ -107,13 +107,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/ */
protected abstract void loadInitialContentsLocked(); protected abstract void loadInitialContentsLocked();
/**
* Indicates that the source dictionary contents have changed and a rebuild of the binary file
* is required. If it returns false, the next reload will only read the current binary
* dictionary from file.
*/
protected abstract boolean haveContentsChanged();
private boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) { private boolean matchesExpectedBinaryDictFormatVersionForThisType(final int formatVersion) {
return formatVersion == FormatSpec.VERSION4; return formatVersion == FormatSpec.VERSION4;
} }
@ -147,7 +140,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
mDictFile = getDictFile(context, dictName, dictFile); mDictFile = getDictFile(context, dictName, dictFile);
mBinaryDictionary = null; mBinaryDictionary = null;
mIsReloading = new AtomicBoolean(); mIsReloading = new AtomicBoolean();
mNeedsToReload = false; mNeedsToRecreate = false;
mLock = new ReentrantReadWriteLock(); mLock = new ReentrantReadWriteLock();
} }
@ -486,11 +479,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
} }
/** /**
* Marks that the dictionary needs to be reloaded. * Marks that the dictionary needs to be recreated.
* *
*/ */
protected void setNeedsToReload() { protected void setNeedsToRecreate() {
mNeedsToReload = true; mNeedsToRecreate = true;
} }
/** /**
@ -508,7 +501,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* Returns whether a dictionary reload is required. * Returns whether a dictionary reload is required.
*/ */
private boolean isReloadRequired() { private boolean isReloadRequired() {
return mBinaryDictionary == null || mNeedsToReload; return mBinaryDictionary == null || mNeedsToRecreate;
} }
/** /**
@ -520,8 +513,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
@Override @Override
public void run() { public void run() {
try { try {
// TODO: Quit checking contents in ExpandableBinaryDictionary. if (!mDictFile.exists() || mNeedsToRecreate) {
if (!mDictFile.exists() || (mNeedsToReload && haveContentsChanged())) {
// If the dictionary file does not exist or contents have been updated, // If the dictionary file does not exist or contents have been updated,
// generate a new one. // generate a new one.
createNewDictionaryLocked(); createNewDictionaryLocked();
@ -533,12 +525,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
&& matchesExpectedBinaryDictFormatVersionForThisType( && matchesExpectedBinaryDictFormatVersionForThisType(
mBinaryDictionary.getFormatVersion()))) { mBinaryDictionary.getFormatVersion()))) {
// Binary dictionary or its format version is not valid. Regenerate // Binary dictionary or its format version is not valid. Regenerate
// the dictionary file. writeBinaryDictionary will remove the // the dictionary file. createNewDictionaryLocked will remove the
// existing files if appropriate. // existing files if appropriate.
createNewDictionaryLocked(); createNewDictionaryLocked();
} }
} }
mNeedsToReload = false; mNeedsToRecreate = false;
} finally { } finally {
mIsReloading.set(false); mIsReloading.set(false);
} }

View File

@ -98,7 +98,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
// devices. On older versions of the platform, the hook above will be called instead. // devices. On older versions of the platform, the hook above will be called instead.
@Override @Override
public void onChange(final boolean self, final Uri uri) { public void onChange(final boolean self, final Uri uri) {
setNeedsToReload(); setNeedsToRecreate();
} }
}; };
cres.registerContentObserver(Words.CONTENT_URI, true, mObserver); cres.registerContentObserver(Words.CONTENT_URI, true, mObserver);
@ -272,9 +272,4 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
} }
} }
} }
@Override
protected boolean haveContentsChanged() {
return true;
}
} }

View File

@ -73,11 +73,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB
return attributeMap; return attributeMap;
} }
@Override
protected boolean haveContentsChanged() {
return false;
}
@Override @Override
protected void loadInitialContentsLocked() { protected void loadInitialContentsLocked() {
// No initial contents. // No initial contents.