mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
am c8ac8da4
: Merge "Prepare ExpandableBinaryDictionary to make it updatable"
* commit 'c8ac8da4e46ffb73c175d882af86d135084abe95': Prepare ExpandableBinaryDictionary to make it updatable
This commit is contained in:
commit
aafcd7b583
@ -42,8 +42,10 @@ abstract public class AbstractDictionaryWriter extends Dictionary {
|
||||
abstract public void addUnigramWord(final String word, final String shortcutTarget,
|
||||
final int frequency, final boolean isNotAWord);
|
||||
|
||||
// TODO: Remove lastModifiedTime after making binary dictionary support forgetting curve.
|
||||
abstract public void addBigramWords(final String word0, final String word1,
|
||||
final int frequency, final boolean isValid);
|
||||
final int frequency, final boolean isValid,
|
||||
final long lastModifiedTime);
|
||||
|
||||
abstract public void removeBigramWords(final String word0, final String word1);
|
||||
|
||||
|
@ -70,7 +70,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
|
||||
private final boolean mUseFirstLastBigrams;
|
||||
|
||||
public ContactsBinaryDictionary(final Context context, final Locale locale) {
|
||||
super(context, getFilenameWithLocale(NAME, locale.toString()), Dictionary.TYPE_CONTACTS);
|
||||
super(context, getFilenameWithLocale(NAME, locale.toString()), Dictionary.TYPE_CONTACTS,
|
||||
false /* isUpdatable */);
|
||||
mLocale = locale;
|
||||
mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale);
|
||||
registerObserver(context);
|
||||
@ -208,7 +209,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
|
||||
false /* isNotAWord */);
|
||||
if (!TextUtils.isEmpty(prevWord)) {
|
||||
if (mUseFirstLastBigrams) {
|
||||
super.setBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM);
|
||||
super.addBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM,
|
||||
0 /* lastModifiedTime */);
|
||||
}
|
||||
}
|
||||
prevWord = word;
|
||||
|
@ -75,7 +75,7 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
|
||||
|
||||
@Override
|
||||
public void addBigramWords(final String word0, final String word1, final int frequency,
|
||||
final boolean isValid) {
|
||||
final boolean isValid, final long lastModifiedTime) {
|
||||
mFusionDictionary.setBigram(word0, word1, frequency);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.inputmethod.annotations.UsedForTesting;
|
||||
import com.android.inputmethod.keyboard.ProximityInfo;
|
||||
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
|
||||
import com.android.inputmethod.latin.utils.CollectionUtils;
|
||||
@ -78,6 +79,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
*/
|
||||
private final String mFilename;
|
||||
|
||||
/** Whether to support dynamically updating the dictionary */
|
||||
private final boolean mIsUpdatable;
|
||||
|
||||
/** Controls access to the shared binary dictionary file across multiple instances. */
|
||||
private final DictionaryController mSharedDictionaryController;
|
||||
|
||||
@ -113,6 +117,16 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
return controller;
|
||||
}
|
||||
|
||||
private static AbstractDictionaryWriter getDictionaryWriter(final Context context,
|
||||
final String dictType, final boolean isUpdatable) {
|
||||
if (isUpdatable) {
|
||||
// TODO: Employ dynamically updatable DictionaryWriter.
|
||||
return new DictionaryWriter(context, dictType);
|
||||
} else {
|
||||
return new DictionaryWriter(context, dictType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new expandable binary dictionary.
|
||||
*
|
||||
@ -120,15 +134,18 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
* @param filename The filename for this binary dictionary. Multiple dictionaries with the same
|
||||
* filename is supported.
|
||||
* @param dictType the dictionary type, as a human-readable string
|
||||
* @param isUpdatable whether to support dynamically updating the dictionary. Please note that
|
||||
* dynamic dictionary has negative effects on memory space and computation time.
|
||||
*/
|
||||
public ExpandableBinaryDictionary(
|
||||
final Context context, final String filename, final String dictType) {
|
||||
public ExpandableBinaryDictionary(final Context context, final String filename,
|
||||
final String dictType, final boolean isUpdatable) {
|
||||
super(dictType);
|
||||
mFilename = filename;
|
||||
mContext = context;
|
||||
mIsUpdatable = isUpdatable;
|
||||
mBinaryDictionary = null;
|
||||
mSharedDictionaryController = getSharedDictionaryController(filename);
|
||||
mDictionaryWriter = new DictionaryWriter(context, dictType);
|
||||
mDictionaryWriter = getDictionaryWriter(context, dictType, isUpdatable);
|
||||
}
|
||||
|
||||
protected static String getFilenameWithLocale(final String name, final String localeStr) {
|
||||
@ -140,6 +157,16 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
closeBinaryDictionary();
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
mDictionaryWriter.close();
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected void closeBinaryDictionary() {
|
||||
// Ensure that no other threads are accessing the local binary dictionary.
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
@ -147,7 +174,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
mBinaryDictionary.close();
|
||||
mBinaryDictionary = null;
|
||||
}
|
||||
mDictionaryWriter.close();
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
@ -162,35 +188,70 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a word bigram in the dictionary. Used for loading a dictionary.
|
||||
* Adds a word bigram in the dictionary. Used for loading a dictionary.
|
||||
*/
|
||||
protected void setBigram(final String prevWord, final String word, final int frequency) {
|
||||
mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
|
||||
protected void addBigram(final String prevWord, final String word, final int frequency,
|
||||
final long lastModifiedTime) {
|
||||
mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */,
|
||||
lastModifiedTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically adds a word unigram to the dictionary.
|
||||
* Dynamically adds a word unigram to the dictionary. May overwrite an existing entry.
|
||||
*/
|
||||
protected void addWordDynamically(final String word, final String shortcutTarget,
|
||||
final int frequency, final boolean isNotAWord) {
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
if (!mIsUpdatable) {
|
||||
Log.w(TAG, "addWordDynamically is called for non-updatable dictionary: " + mFilename);
|
||||
return;
|
||||
}
|
||||
// TODO: Use a queue to reflect what needs to be reflected.
|
||||
if (mLocalDictionaryController.writeLock().tryLock()) {
|
||||
try {
|
||||
mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically sets a word bigram in the dictionary.
|
||||
* Dynamically adds a word bigram in the dictionary. May overwrite an existing entry.
|
||||
*/
|
||||
protected void setBigramDynamically(final String prevWord, final String word,
|
||||
final int frequency) {
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
protected void addBigramDynamically(final String word0, final String word1,
|
||||
final int frequency, final boolean isValid) {
|
||||
if (!mIsUpdatable) {
|
||||
Log.w(TAG, "addBigramDynamically is called for non-updatable dictionary: "
|
||||
+ mFilename);
|
||||
return;
|
||||
}
|
||||
// TODO: Use a queue to reflect what needs to be reflected.
|
||||
if (mLocalDictionaryController.writeLock().tryLock()) {
|
||||
try {
|
||||
mDictionaryWriter.addBigramWords(word0, word1, frequency, isValid,
|
||||
0 /* lastTouchedTime */);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically remove a word bigram in the dictionary.
|
||||
*/
|
||||
protected void removeBigramDynamically(final String word0, final String word1) {
|
||||
if (!mIsUpdatable) {
|
||||
Log.w(TAG, "removeBigramDynamically is called for non-updatable dictionary: "
|
||||
+ mFilename);
|
||||
return;
|
||||
}
|
||||
// TODO: Use a queue to reflect what needs to be reflected.
|
||||
if (mLocalDictionaryController.writeLock().tryLock()) {
|
||||
try {
|
||||
mDictionaryWriter.removeBigramWords(word0, word1);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,7 +341,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
|
||||
// Build the new binary dictionary
|
||||
final BinaryDictionary newBinaryDictionary = new BinaryDictionary(filename, 0, length,
|
||||
true /* useFullEditDistance */, null, mDictType, false /* isUpdatable */);
|
||||
true /* useFullEditDistance */, null, mDictType, mIsUpdatable);
|
||||
|
||||
if (mBinaryDictionary != null) {
|
||||
// Ensure all threads accessing the current dictionary have finished before swapping in
|
||||
@ -305,9 +366,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
abstract protected boolean needsToReloadBeforeWriting();
|
||||
|
||||
/**
|
||||
* Generates and writes a new binary dictionary based on the contents of the fusion dictionary.
|
||||
* Writes a new binary dictionary based on the contents of the fusion dictionary.
|
||||
*/
|
||||
private void generateBinaryDictionary() {
|
||||
private void writeBinaryDictionary() {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Generating binary dictionary: " + mFilename + " request="
|
||||
+ mSharedDictionaryController.mLastUpdateRequestTime + " update="
|
||||
@ -370,41 +431,47 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
private final void syncReloadDictionaryInternal() {
|
||||
// Ensure that only one thread attempts to read or write to the shared binary dictionary
|
||||
// file at the same time.
|
||||
mSharedDictionaryController.writeLock().lock();
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
final long time = SystemClock.uptimeMillis();
|
||||
final boolean dictionaryFileExists = dictionaryFileExists();
|
||||
if (mSharedDictionaryController.isOutOfDate() || !dictionaryFileExists) {
|
||||
// If the shared dictionary file does not exist or is out of date, the first
|
||||
// instance that acquires the lock will generate a new one.
|
||||
if (hasContentChanged() || !dictionaryFileExists) {
|
||||
// If the source content has changed or the dictionary does not exist, rebuild
|
||||
// the binary dictionary. Empty dictionaries are supported (in the case where
|
||||
// loadDictionaryAsync() adds nothing) in order to provide a uniform framework.
|
||||
mSharedDictionaryController.mLastUpdateTime = time;
|
||||
generateBinaryDictionary();
|
||||
mSharedDictionaryController.writeLock().lock();
|
||||
try {
|
||||
final long time = SystemClock.uptimeMillis();
|
||||
final boolean dictionaryFileExists = dictionaryFileExists();
|
||||
if (mSharedDictionaryController.isOutOfDate() || !dictionaryFileExists) {
|
||||
// If the shared dictionary file does not exist or is out of date, the first
|
||||
// instance that acquires the lock will generate a new one.
|
||||
if (hasContentChanged() || !dictionaryFileExists) {
|
||||
// If the source content has changed or the dictionary does not exist,
|
||||
// rebuild the binary dictionary. Empty dictionaries are supported (in the
|
||||
// case where loadDictionaryAsync() adds nothing) in order to provide a
|
||||
// uniform framework.
|
||||
mSharedDictionaryController.mLastUpdateTime = time;
|
||||
writeBinaryDictionary();
|
||||
loadBinaryDictionary();
|
||||
} else {
|
||||
// If not, the reload request was unnecessary so revert
|
||||
// LastUpdateRequestTime to LastUpdateTime.
|
||||
mSharedDictionaryController.mLastUpdateRequestTime =
|
||||
mSharedDictionaryController.mLastUpdateTime;
|
||||
}
|
||||
} else if (mBinaryDictionary == null || mLocalDictionaryController.mLastUpdateTime
|
||||
< mSharedDictionaryController.mLastUpdateTime) {
|
||||
// Otherwise, if the local dictionary is older than the shared dictionary, load
|
||||
// the shared dictionary.
|
||||
loadBinaryDictionary();
|
||||
} else {
|
||||
// If not, the reload request was unnecessary so revert LastUpdateRequestTime
|
||||
// to LastUpdateTime.
|
||||
mSharedDictionaryController.mLastUpdateRequestTime =
|
||||
mSharedDictionaryController.mLastUpdateTime;
|
||||
}
|
||||
} else if (mBinaryDictionary == null || mLocalDictionaryController.mLastUpdateTime
|
||||
< mSharedDictionaryController.mLastUpdateTime) {
|
||||
// Otherwise, if the local dictionary is older than the shared dictionary, load the
|
||||
// shared dictionary.
|
||||
loadBinaryDictionary();
|
||||
if (mBinaryDictionary != null && !mBinaryDictionary.isValidDictionary()) {
|
||||
// Binary dictionary is not valid. Regenerate the dictionary file.
|
||||
mSharedDictionaryController.mLastUpdateTime = time;
|
||||
writeBinaryDictionary();
|
||||
loadBinaryDictionary();
|
||||
}
|
||||
mLocalDictionaryController.mLastUpdateTime = time;
|
||||
} finally {
|
||||
mSharedDictionaryController.writeLock().unlock();
|
||||
}
|
||||
if (mBinaryDictionary != null && !mBinaryDictionary.isValidDictionary()) {
|
||||
// Binary dictionary is not valid. Regenerate the dictionary file.
|
||||
mSharedDictionaryController.mLastUpdateTime = time;
|
||||
generateBinaryDictionary();
|
||||
loadBinaryDictionary();
|
||||
}
|
||||
mLocalDictionaryController.mLastUpdateTime = time;
|
||||
} finally {
|
||||
mSharedDictionaryController.writeLock().unlock();
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,4 +504,45 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||
return (mLastUpdateRequestTime > mLastUpdateTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically adds a word unigram to the dictionary for testing with blocking-lock.
|
||||
*/
|
||||
@UsedForTesting
|
||||
protected void addWordDynamicallyForTests(final String word, final String shortcutTarget,
|
||||
final int frequency, final boolean isNotAWord) {
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
addWordDynamically(word, shortcutTarget, frequency, isNotAWord);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically adds a word bigram in the dictionary for testing with blocking-lock.
|
||||
*/
|
||||
@UsedForTesting
|
||||
protected void addBigramDynamicallyForTests(final String word0, final String word1,
|
||||
final int frequency, final boolean isValid) {
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
addBigramDynamically(word0, word1, frequency, isValid);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically remove a word bigram in the dictionary for testing with blocking-lock.
|
||||
*/
|
||||
@UsedForTesting
|
||||
protected void removeBigramDynamicallyForTests(final String word0, final String word1) {
|
||||
mLocalDictionaryController.writeLock().lock();
|
||||
try {
|
||||
removeBigramDynamically(word0, word1);
|
||||
} finally {
|
||||
mLocalDictionaryController.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
|
||||
|
||||
public UserBinaryDictionary(final Context context, final String locale,
|
||||
final boolean alsoUseMoreRestrictiveLocales) {
|
||||
super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_USER);
|
||||
super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_USER,
|
||||
false /* isUpdatable */);
|
||||
if (null == locale) throw new NullPointerException(); // Catch the error earlier
|
||||
if (SubtypeLocaleUtils.NO_LANGUAGE.equals(locale)) {
|
||||
// If we don't have a locale, insert into the "all locales" user dictionary.
|
||||
|
@ -36,7 +36,9 @@ public class PersonalizationDictionary extends ExpandableBinaryDictionary {
|
||||
|
||||
// Singleton
|
||||
private PersonalizationDictionary(final Context context, final String locale) {
|
||||
super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_PERSONALIZATION);
|
||||
// TODO: Make isUpdatable true.
|
||||
super(context, getFilenameWithLocale(NAME, locale), Dictionary.TYPE_PERSONALIZATION,
|
||||
false /* isUpdatable */);
|
||||
mLocale = locale;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user