aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java')
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java180
1 files changed, 82 insertions, 98 deletions
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 9cdb86c2d..657fc64b4 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -22,20 +22,12 @@ import android.util.Log;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
-import com.android.inputmethod.latin.makedict.FormatSpec;
-import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
-import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
-import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Abstract base class for an expandable dictionary that can be created and updated dynamically
@@ -76,8 +68,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
private BinaryDictionary mBinaryDictionary;
- /** The expandable fusion dictionary used to generate the binary dictionary. */
- private FusionDictionary mFusionDictionary;
+ /** The in-memory dictionary used to generate the binary dictionary. */
+ private AbstractDictionaryWriter mDictionaryWriter;
/**
* The name of this dictionary, used as the filename for storing the binary dictionary. Multiple
@@ -92,10 +84,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/** Controls access to the local binary dictionary for this instance. */
private final DictionaryController mLocalDictionaryController = new DictionaryController();
- private static final int BINARY_DICT_VERSION = 1;
- private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
- new FormatSpec.FormatOptions(BINARY_DICT_VERSION);
-
/**
* Abstract method for loading the unigrams and bigrams of a given dictionary in a background
* thread.
@@ -137,7 +125,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
mContext = context;
mBinaryDictionary = null;
mSharedDictionaryController = getSharedDictionaryController(filename);
- clearFusionDictionary();
+ mDictionaryWriter = new DictionaryWriter(context, dictType);
}
protected static String getFilenameWithLocale(final String name, final String localeStr) {
@@ -150,53 +138,57 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
@Override
public void close() {
// Ensure that no other threads are accessing the local binary dictionary.
- mLocalDictionaryController.lock();
+ mLocalDictionaryController.writeLock().lock();
try {
if (mBinaryDictionary != null) {
mBinaryDictionary.close();
mBinaryDictionary = null;
}
+ mDictionaryWriter.close();
} finally {
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.writeLock().unlock();
}
}
/**
- * Clears the fusion dictionary on the Java side. Note: Does not modify the binary dictionary on
- * the native side.
+ * Adds a word unigram to the dictionary. Used for loading a dictionary.
*/
- public void clearFusionDictionary() {
- final HashMap<String, String> attributes = CollectionUtils.newHashMap();
- mFusionDictionary = new FusionDictionary(new Node(),
- new FusionDictionary.DictionaryOptions(attributes, false, false));
+ protected void addWord(final String word, final String shortcutTarget,
+ final int frequency, final boolean isNotAWord) {
+ mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
}
/**
- * Adds a word unigram to the fusion dictionary. Call updateBinaryDictionary when all changes
- * are done to update the binary dictionary.
+ * Sets a word bigram in the dictionary. Used for loading a dictionary.
*/
- // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries,
- // considering performance regression.
- protected void addWord(final String word, final String shortcutTarget, final int frequency,
- final boolean isNotAWord) {
- if (shortcutTarget == null) {
- mFusionDictionary.add(word, frequency, null, isNotAWord);
- } else {
- // TODO: Do this in the subclass, with this class taking an arraylist.
- final ArrayList<WeightedString> shortcutTargets = CollectionUtils.newArrayList();
- shortcutTargets.add(new WeightedString(shortcutTarget, frequency));
- mFusionDictionary.add(word, frequency, shortcutTargets, isNotAWord);
+ protected void setBigram(final String prevWord, final String word, final int frequency) {
+ mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
+ }
+
+ /**
+ * Dynamically adds a word unigram to the dictionary.
+ */
+ 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();
}
}
/**
- * Sets a word bigram in the fusion dictionary. Call updateBinaryDictionary when all changes are
- * done to update the binary dictionary.
+ * Dynamically sets a word bigram in the dictionary.
*/
- // TODO: Create "cache dictionary" to cache fresh bigrams for frequently updated dictionaries,
- // considering performance regression.
- protected void setBigram(final String prevWord, final String word, final int frequency) {
- mFusionDictionary.setBigram(prevWord, word, frequency);
+ 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();
+ }
}
@Override
@@ -204,14 +196,29 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) {
asyncReloadDictionaryIfRequired();
- if (mLocalDictionaryController.tryLock()) {
+ // Write lock because getSuggestions in native updates session status.
+ if (mLocalDictionaryController.writeLock().tryLock()) {
try {
+ final ArrayList<SuggestedWordInfo> inMemDictSuggestion =
+ mDictionaryWriter.getSuggestions(composer, prevWord, proximityInfo,
+ blockOffensiveWords);
if (mBinaryDictionary != null) {
- return mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo,
- blockOffensiveWords);
+ final ArrayList<SuggestedWordInfo> binarySuggestion =
+ mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo,
+ blockOffensiveWords);
+ if (inMemDictSuggestion == null) {
+ return binarySuggestion;
+ } else if (binarySuggestion == null) {
+ return inMemDictSuggestion;
+ } else {
+ binarySuggestion.addAll(binarySuggestion);
+ return binarySuggestion;
+ }
+ } else {
+ return inMemDictSuggestion;
}
} finally {
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.writeLock().unlock();
}
}
return null;
@@ -224,11 +231,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
protected boolean isValidWordInner(final String word) {
- if (mLocalDictionaryController.tryLock()) {
+ if (mLocalDictionaryController.readLock().tryLock()) {
try {
return isValidWordLocked(word);
} finally {
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.readLock().unlock();
}
}
return false;
@@ -239,22 +246,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return mBinaryDictionary.isValidWord(word);
}
- protected boolean isValidBigram(final String word1, final String word2) {
- if (mBinaryDictionary == null) return false;
- return mBinaryDictionary.isValidBigram(word1, word2);
- }
-
- protected boolean isValidBigramInner(final String word1, final String word2) {
- if (mLocalDictionaryController.tryLock()) {
- try {
- return isValidBigramLocked(word1, word2);
- } finally {
- mLocalDictionaryController.unlock();
- }
- }
- return false;
- }
-
protected boolean isValidBigramLocked(final String word1, final String word2) {
if (mBinaryDictionary == null) return false;
return mBinaryDictionary.isValidBigram(word1, word2);
@@ -273,7 +264,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* Loads the current binary dictionary from internal storage. Assumes the dictionary file
* exists.
*/
- protected void loadBinaryDictionary() {
+ private void loadBinaryDictionary() {
if (DEBUG) {
Log.d(TAG, "Loading binary dictionary: " + mFilename + " request="
+ mSharedDictionaryController.mLastUpdateRequestTime + " update="
@@ -292,9 +283,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// Ensure all threads accessing the current dictionary have finished before swapping in
// the new one.
final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
- mLocalDictionaryController.lock();
- mBinaryDictionary = newBinaryDictionary;
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.writeLock().lock();
+ try {
+ mBinaryDictionary = newBinaryDictionary;
+ } finally {
+ mLocalDictionaryController.writeLock().unlock();
+ }
oldBinaryDictionary.close();
} else {
mBinaryDictionary = newBinaryDictionary;
@@ -302,6 +296,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
/**
+ * Abstract method for checking if it is required to reload the dictionary before writing
+ * a binary dictionary.
+ */
+ abstract protected boolean needsToReloadBeforeWriting();
+
+ /**
* Generates and writes a new binary dictionary based on the contents of the fusion dictionary.
*/
private void generateBinaryDictionary() {
@@ -310,33 +310,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
+ mSharedDictionaryController.mLastUpdateRequestTime + " update="
+ mSharedDictionaryController.mLastUpdateTime);
}
-
- loadDictionaryAsync();
-
- final String tempFileName = mFilename + ".temp";
- final File file = new File(mContext.getFilesDir(), mFilename);
- final File tempFile = new File(mContext.getFilesDir(), tempFileName);
- FileOutputStream out = null;
- try {
- out = new FileOutputStream(tempFile);
- BinaryDictInputOutput.writeDictionaryBinary(out, mFusionDictionary, FORMAT_OPTIONS);
- out.flush();
- out.close();
- tempFile.renameTo(file);
- clearFusionDictionary();
- } catch (IOException e) {
- Log.e(TAG, "IO exception while writing file", e);
- } catch (UnsupportedFormatException e) {
- Log.e(TAG, "Unsupported format", e);
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
+ if (needsToReloadBeforeWriting()) {
+ mDictionaryWriter.clear();
+ loadDictionaryAsync();
}
+ mDictionaryWriter.write(mFilename);
}
/**
@@ -389,7 +367,7 @@ 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.lock();
+ mSharedDictionaryController.writeLock().lock();
try {
final long time = SystemClock.uptimeMillis();
final boolean dictionaryFileExists = dictionaryFileExists();
@@ -415,9 +393,15 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// shared dictionary.
loadBinaryDictionary();
}
+ if (mBinaryDictionary != null && !mBinaryDictionary.isValidDictionary()) {
+ // Binary dictionary is not valid. Regenerate the dictionary file.
+ mSharedDictionaryController.mLastUpdateTime = time;
+ generateBinaryDictionary();
+ loadBinaryDictionary();
+ }
mLocalDictionaryController.mLastUpdateTime = time;
} finally {
- mSharedDictionaryController.unlock();
+ mSharedDictionaryController.writeLock().unlock();
}
}
@@ -442,7 +426,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* dictionary is out of date. Can be shared across multiple dictionary instances that access the
* same filename.
*/
- private static class DictionaryController extends ReentrantLock {
+ private static class DictionaryController extends ReentrantReadWriteLock {
private volatile long mLastUpdateTime = 0;
private volatile long mLastUpdateRequestTime = 0;