diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java | 180 |
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; |