From ecd2ac93bc321fdd932930c43851a92859d4775d Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Sat, 24 Mar 2012 15:13:40 +0900 Subject: Add an expandable binary dictionary that can be modified at runtime and works with native algorithms. Bug: 6188977 Change-Id: Iec5c4e7d1d3918ac645187bd32dc3f82a95fec1e --- .../latin/ExpandableBinaryDictionary.java | 393 +++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java new file mode 100644 index 000000000..53e8b74de --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.content.Context; +import android.os.SystemClock; +import android.util.Log; + +import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; +import com.android.inputmethod.latin.makedict.FusionDictionary; +import com.android.inputmethod.latin.makedict.FusionDictionary.Node; +import com.android.inputmethod.latin.makedict.UnsupportedFormatException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Abstract base class for an expandable dictionary that can be created and updated dynamically + * during runtime. When updated it automatically generates a new binary dictionary to handle future + * queries in native code. This binary dictionary is written to internal storage, and potentially + * shared across multiple ExpandableBinaryDictionary instances. Updates to each dictionary filename + * are controlled across multiple instances to ensure that only one instance can update the same + * dictionary at the same time. + */ +abstract public class ExpandableBinaryDictionary extends Dictionary { + + /** Used for Log actions from this class */ + private static final String TAG = ExpandableBinaryDictionary.class.getSimpleName(); + + /** Whether to print debug output to log */ + private static boolean DEBUG = false; + + /** + * The maximum length of a word in this dictionary. This is the same value as the binary + * dictionary. + */ + protected static final int MAX_WORD_LENGTH = BinaryDictionary.MAX_WORD_LENGTH; + + /** + * A static map of locks, each of which controls access to a single binary dictionary file. They + * ensure that only one instance can update the same dictionary at the same time. The key for + * this map is the filename and the value is the shared dictionary controller associated with + * that filename. + */ + private static final HashMap sSharedDictionaryControllers = + new HashMap(); + + /** The application context. */ + protected final Context mContext; + + /** + * The binary dictionary generated dynamically from the fusion dictionary. This is used to + * answer unigram and bigram queries. + */ + private BinaryDictionary mBinaryDictionary; + + /** The expandable fusion dictionary used to generate the binary dictionary. */ + private FusionDictionary mFusionDictionary; + + /** The dictionary type id. */ + public final int mDicTypeId; + + /** + * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple + * dictionary instances with the same filename is supported, with access controlled by + * DictionaryController. + */ + private final String mFilename; + + /** Controls access to the shared binary dictionary file across multiple instances. */ + private final DictionaryController mSharedDictionaryController; + + /** Controls access to the local binary dictionary for this instance. */ + private final DictionaryController mLocalDictionaryController = new DictionaryController(); + + /** + * Abstract method for loading the unigrams and bigrams of a given dictionary in a background + * thread. + */ + protected abstract void loadDictionaryAsync(); + + /** + * Gets the shared dictionary controller for the given filename. + */ + private static synchronized DictionaryController getSharedDictionaryController( + String filename) { + DictionaryController controller = sSharedDictionaryControllers.get(filename); + if (controller == null) { + controller = new DictionaryController(); + sSharedDictionaryControllers.put(filename, controller); + } + return controller; + } + + /** + * Creates a new expandable binary dictionary. + * + * @param context The application context of the parent. + * @param filename The filename for this binary dictionary. Multiple dictionaries with the same + * filename is supported. + * @param dictType The type of this dictionary. + */ + public ExpandableBinaryDictionary( + final Context context, final String filename, final int dictType) { + mDicTypeId = dictType; + mFilename = filename; + mContext = context; + mBinaryDictionary = null; + mSharedDictionaryController = getSharedDictionaryController(filename); + clearFusionDictionary(); + } + + /** + * Closes and cleans up the binary dictionary. + */ + @Override + public void close() { + // Ensure that no other threads are accessing the local binary dictionary. + mLocalDictionaryController.lock(); + try { + if (mBinaryDictionary != null) { + mBinaryDictionary.close(); + mBinaryDictionary = null; + } + } finally { + mLocalDictionaryController.unlock(); + } + } + + /** + * Clears the fusion dictionary on the Java side. Note: Does not modify the binary dictionary on + * the native side. + */ + public void clearFusionDictionary() { + mFusionDictionary = new FusionDictionary(new Node(), new FusionDictionary.DictionaryOptions( + new HashMap(), false, false)); + } + + /** + * Adds a word unigram to the fusion dictionary. Call updateBinaryDictionary when all changes + * are done to update the binary dictionary. + */ + // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries, + // considering performance regression. + protected void addWord(final String word, final int frequency) { + mFusionDictionary.add(word, frequency, null, null); + } + + /** + * Sets a word bigram in the fusion dictionary. Call updateBinaryDictionary when all changes are + * done to update the binary 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); + } + + @Override + public void getWords(final WordComposer codes, final WordCallback callback, + final ProximityInfo proximityInfo) { + asyncReloadDictionaryIfRequired(); + getWordsInner(codes, callback, proximityInfo); + } + + protected final void getWordsInner(final WordComposer codes, final WordCallback callback, + final ProximityInfo proximityInfo) { + // Ensure that there are no concurrent calls to getWords. If there are, do nothing and + // return. + if (mLocalDictionaryController.tryLock()) { + try { + if (mBinaryDictionary != null) { + mBinaryDictionary.getWords(codes, callback, proximityInfo); + } + } finally { + mLocalDictionaryController.unlock(); + } + } + } + + @Override + public void getBigrams(final WordComposer codes, final CharSequence previousWord, + final WordCallback callback) { + asyncReloadDictionaryIfRequired(); + getBigramsInner(codes, previousWord, callback); + } + + protected void getBigramsInner(final WordComposer codes, final CharSequence previousWord, + final WordCallback callback) { + if (mLocalDictionaryController.tryLock()) { + try { + if (mBinaryDictionary != null) { + mBinaryDictionary.getBigrams(codes, previousWord, callback); + } + } finally { + mLocalDictionaryController.unlock(); + } + } + } + + @Override + public boolean isValidWord(final CharSequence word) { + asyncReloadDictionaryIfRequired(); + return isValidWordInner(word); + } + + protected boolean isValidWordInner(final CharSequence word) { + if (mLocalDictionaryController.tryLock()) { + try { + if (mBinaryDictionary != null) { + return mBinaryDictionary.isValidWord(word); + } + } finally { + mLocalDictionaryController.unlock(); + } + } + return false; + } + + /** + * Load the current binary dictionary from internal storage in a background thread. If no binary + * dictionary exists, this method will generate one. + */ + protected void loadDictionary() { + mLocalDictionaryController.mLastUpdateRequestTime = SystemClock.uptimeMillis(); + asyncReloadDictionaryIfRequired(); + } + + /** + * Loads the current binary dictionary from internal storage. Assumes the dictionary file + * exists. + */ + protected void loadBinaryDictionary() { + if (DEBUG) { + Log.d(TAG, "Loading binary dictionary: request=" + + mSharedDictionaryController.mLastUpdateRequestTime + " update=" + + mSharedDictionaryController.mLastUpdateTime); + } + + final File file = new File(mContext.getFilesDir(), mFilename); + final String filename = file.getAbsolutePath(); + final long length = file.length(); + + // Build the new binary dictionary + final BinaryDictionary newBinaryDictionary = + new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */, + null); + + if (mBinaryDictionary != null) { + // 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(); + oldBinaryDictionary.close(); + } else { + mBinaryDictionary = newBinaryDictionary; + } + } + + /** + * Generates and writes a new binary dictionary based on the contents of the fusion dictionary. + */ + private void generateBinaryDictionary() { + if (DEBUG) { + Log.d(TAG, "Generating binary dictionary: request=" + + mSharedDictionaryController.mLastUpdateRequestTime + " update=" + + mSharedDictionaryController.mLastUpdateTime); + } + + loadDictionaryAsync(); + + final File file = new File(mContext.getFilesDir(), mFilename); + FileOutputStream out = null; + try { + out = new FileOutputStream(file); + BinaryDictInputOutput.writeDictionaryBinary(out, mFusionDictionary, 1); + out.flush(); + out.close(); + 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 + } + } + } + } + + /** + * Sets whether or not the dictionary is out of date and requires a reload. + */ + protected void setRequiresReload(final boolean reload) { + final long time = reload ? SystemClock.uptimeMillis() : 0; + mSharedDictionaryController.mLastUpdateRequestTime = time; + mLocalDictionaryController.mLastUpdateRequestTime = time; + if (DEBUG) { + Log.d(TAG, "Reload request: request=" + time + " update=" + + mSharedDictionaryController.mLastUpdateTime); + } + } + + /** + * Reloads the dictionary if required. Reload will occur asynchronously in a separate thread. + */ + void asyncReloadDictionaryIfRequired() { + new AsyncReloadDictionaryTask().start(); + } + + /** + * Reloads the dictionary if required. Access is controlled on a per dictionary file basis and + * supports concurrent calls from multiple instances that share the same dictionary file. + */ + protected final void syncReloadDictionaryIfRequired() { + if (mBinaryDictionary != null && !mLocalDictionaryController.isOutOfDate()) { + return; + } + + // Ensure that only one thread attempts to read or write to the shared binary dictionary + // file at the same time. + mSharedDictionaryController.lock(); + try { + final long time = SystemClock.uptimeMillis(); + 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. + mSharedDictionaryController.mLastUpdateTime = time; + mLocalDictionaryController.mLastUpdateTime = time; + generateBinaryDictionary(); + loadBinaryDictionary(); + } else if (mLocalDictionaryController.isOutOfDate()) { + // Otherwise, if only the local dictionary for this instance is out of date, load + // the shared dictionary from file. + mLocalDictionaryController.mLastUpdateTime = time; + loadBinaryDictionary(); + } + } finally { + mSharedDictionaryController.unlock(); + } + } + + private boolean dictionaryFileExists() { + final File file = new File(mContext.getFilesDir(), mFilename); + return file.exists(); + } + + /** + * Thread class for asynchronously reloading and rewriting the binary dictionary. + */ + private class AsyncReloadDictionaryTask extends Thread { + @Override + public void run() { + syncReloadDictionaryIfRequired(); + } + } + + /** + * Lock for controlling access to a given binary dictionary and for tracking whether the + * dictionary is out of date. Can be shared across multiple dictionary instances that access the + * same filename. + */ + private static class DictionaryController extends ReentrantLock { + private volatile long mLastUpdateTime = 0; + private volatile long mLastUpdateRequestTime = 0; + + private boolean isOutOfDate() { + return (mLastUpdateRequestTime > mLastUpdateTime); + } + } +} -- cgit v1.2.3-83-g751a From ac27e4544b5b5ff7b4f365a4bde5c288d511ae13 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Tue, 17 Apr 2012 12:43:53 +0900 Subject: Pass the previous word to getSuggestions This is a preparative change to bug#6313806 Change-Id: I1be9ec49b21005c1f45ce459fa93712bc74ef3f0 --- .../src/com/android/inputmethod/latin/BinaryDictionary.java | 13 ++++++++----- java/src/com/android/inputmethod/latin/Dictionary.java | 4 +++- .../com/android/inputmethod/latin/DictionaryCollection.java | 6 +++--- .../inputmethod/latin/ExpandableBinaryDictionary.java | 11 ++++++----- .../com/android/inputmethod/latin/ExpandableDictionary.java | 9 +++++---- java/src/com/android/inputmethod/latin/Suggest.java | 2 +- .../latin/SynchronouslyLoadedContactsBinaryDictionary.java | 5 +++-- .../latin/SynchronouslyLoadedContactsDictionary.java | 5 +++-- .../latin/SynchronouslyLoadedUserDictionary.java | 5 +++-- java/src/com/android/inputmethod/latin/UserDictionary.java | 5 +++-- .../latin/spellcheck/AndroidSpellCheckerService.java | 2 +- 11 files changed, 39 insertions(+), 28 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 2d958e17d..f4c8e61ed 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -135,11 +135,12 @@ public class BinaryDictionary extends Dictionary { } } - // proximityInfo may not be null. + // proximityInfo and/or prevWordForBigrams may not be null. @Override - public void getWords(final WordComposer codes, final WordCallback callback, - final ProximityInfo proximityInfo) { - final int count = getSuggestions(codes, proximityInfo, mOutputChars, mScores); + public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, + final WordCallback callback, final ProximityInfo proximityInfo) { + final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, + mScores); for (int j = 0; j < count; ++j) { if (mScores[j] < 1) break; @@ -161,7 +162,8 @@ public class BinaryDictionary extends Dictionary { // proximityInfo may not be null. /* package for test */ int getSuggestions(final WordComposer codes, - final ProximityInfo proximityInfo, char[] outputChars, int[] scores) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo, + char[] outputChars, int[] scores) { if (!isValidDictionary()) return -1; final int codesSize = codes.size(); @@ -175,6 +177,7 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); + // TODO: pass the previous word to native code return getSuggestionsNative( mNativeDict, proximityInfo.getNativeProximityInfo(), codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize, diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 9d26a2343..a405aa409 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -61,11 +61,13 @@ public abstract class Dictionary { * Searches for words in the dictionary that match the characters in the composer. Matched * words are added through the callback object. * @param composer the key sequence to match + * @param prevWordForBigrams the previous word, or null if none * @param callback the callback object to send matched words to as possible candidates * @param proximityInfo the object for key proximity. May be ignored by some implementations. * @see WordCallback#addWord(char[], int, int, int, int, int) */ - abstract public void getWords(final WordComposer composer, final WordCallback callback, + abstract public void getWords(final WordComposer composer, + final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo); /** diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 5de770a4a..37deb0c5d 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -50,10 +50,10 @@ public class DictionaryCollection extends Dictionary { } @Override - public void getWords(final WordComposer composer, final WordCallback callback, - final ProximityInfo proximityInfo) { + public void getWords(final WordComposer composer, final CharSequence prevWordForBigrams, + final WordCallback callback, final ProximityInfo proximityInfo) { for (final Dictionary dict : mDictionaries) - dict.getWords(composer, callback, proximityInfo); + dict.getWords(composer, prevWordForBigrams, callback, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 53e8b74de..7d2ccdf5f 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -173,20 +173,21 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } @Override - public void getWords(final WordComposer codes, final WordCallback callback, - final ProximityInfo proximityInfo) { + public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, + final WordCallback callback, final ProximityInfo proximityInfo) { asyncReloadDictionaryIfRequired(); - getWordsInner(codes, callback, proximityInfo); + getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } - protected final void getWordsInner(final WordComposer codes, final WordCallback callback, + protected final void getWordsInner(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { // Ensure that there are no concurrent calls to getWords. If there are, do nothing and // return. if (mLocalDictionaryController.tryLock()) { try { if (mBinaryDictionary != null) { - mBinaryDictionary.getWords(codes, callback, proximityInfo); + mBinaryDictionary.getWords(codes, prevWordForBigrams, callback, proximityInfo); } } finally { mLocalDictionaryController.unlock(); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 46d11fa37..fe21ebe87 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -192,8 +192,8 @@ public class ExpandableDictionary extends Dictionary { } @Override - public void getWords(final WordComposer codes, final WordCallback callback, - final ProximityInfo proximityInfo) { + public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, + final WordCallback callback, final ProximityInfo proximityInfo) { synchronized (mUpdatingLock) { // If we need to update, start off a background task if (mRequiresReload) startDictionaryLoadingTaskLocked(); @@ -203,10 +203,11 @@ public class ExpandableDictionary extends Dictionary { if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { return; } - getWordsInner(codes, callback, proximityInfo); + getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } - protected final void getWordsInner(final WordComposer codes, final WordCallback callback, + protected final void getWordsInner(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, @SuppressWarnings("unused") final ProximityInfo proximityInfo) { mInputLength = codes.size(); if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 51ebfdad6..86753e2cc 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -340,7 +340,7 @@ public class Suggest implements Dictionary.WordCallback { if (key.equals(DICT_KEY_USER_HISTORY_UNIGRAM) || key.equals(DICT_KEY_WHITELIST)) continue; final Dictionary dictionary = mUnigramDictionaries.get(key); - dictionary.getWords(wordComposerForLookup, this, proximityInfo); + dictionary.getWords(wordComposerForLookup, prevWordForBigram, this, proximityInfo); } } diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index 80825a887..188259ff8 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -30,10 +30,11 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD } @Override - public synchronized void getWords(final WordComposer codes, final WordCallback callback, + public synchronized void getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - getWordsInner(codes, callback, proximityInfo); + getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsDictionary.java index 444c7f5f0..a8b871cdf 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsDictionary.java @@ -29,10 +29,11 @@ public class SynchronouslyLoadedContactsDictionary extends ContactsDictionary { } @Override - public synchronized void getWords(final WordComposer codes, final WordCallback callback, + public synchronized void getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { blockingReloadDictionaryIfRequired(); - getWordsInner(codes, callback, proximityInfo); + getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java index e52b46ac0..50e8b249e 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java @@ -32,10 +32,11 @@ public class SynchronouslyLoadedUserDictionary extends UserDictionary { } @Override - public synchronized void getWords(final WordComposer codes, final WordCallback callback, + public synchronized void getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { blockingReloadDictionaryIfRequired(); - getWordsInner(codes, callback, proximityInfo); + getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java index 51b993343..6beeaace9 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -174,9 +174,10 @@ public class UserDictionary extends ExpandableDictionary { } @Override - public synchronized void getWords(final WordComposer codes, final WordCallback callback, + public synchronized void getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { - super.getWords(codes, callback, proximityInfo); + super.getWords(codes, prevWordForBigrams, callback, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 44dac30d7..34e214da7 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -588,7 +588,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService try { dictInfo = mDictionaryPool.takeOrGetNull(); if (null == dictInfo) return getNotInDictEmptySuggestions(); - dictInfo.mDictionary.getWords(composer, suggestionsGatherer, + dictInfo.mDictionary.getWords(composer, null, suggestionsGatherer, dictInfo.mProximityInfo); isInDict = dictInfo.mDictionary.isValidWord(text); if (!isInDict && CAPITALIZE_NONE != capitalizeType) { -- cgit v1.2.3-83-g751a From a9b2be8a8140d78a468b2a7b839b50e555a4312b Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Tue, 24 Apr 2012 09:59:11 -0700 Subject: Change expandable binary dict write to a temp file first. Bug: 6380724 Change-Id: Ic1d0d902dc45ecb41a1792f33a60ab85e606fcef --- .../com/android/inputmethod/latin/ExpandableBinaryDictionary.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 7d2ccdf5f..9dcffd4e2 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -288,13 +288,16 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { 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(file); + out = new FileOutputStream(tempFile); BinaryDictInputOutput.writeDictionaryBinary(out, mFusionDictionary, 1); out.flush(); out.close(); + tempFile.renameTo(file); clearFusionDictionary(); } catch (IOException e) { Log.e(TAG, "IO exception while writing file: " + e); -- cgit v1.2.3-83-g751a From 44c64f46a143623dd793facd889c8d6eab5e230c Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 20 Apr 2012 19:58:01 +0900 Subject: Ignore bigrams that are not also listed as unigrams This is a cherry pick of I14b67e51 on jb-dev Bug: 6340915 Change-Id: Iaa512abe1b19ca640ea201f9761fd7f1416270ed --- .../latin/ExpandableBinaryDictionary.java | 2 +- .../latin/makedict/BinaryDictInputOutput.java | 12 +++++-- .../latin/makedict/FusionDictionary.java | 41 ++++++++++------------ .../latin/makedict/XmlDictInputOutput.java | 27 ++++++++------ .../latin/BinaryDictInputOutputTest.java | 10 +++--- 5 files changed, 51 insertions(+), 41 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 9dcffd4e2..3d89226c0 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -159,7 +159,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries, // considering performance regression. protected void addWord(final String word, final int frequency) { - mFusionDictionary.add(word, frequency, null, null); + mFusionDictionary.add(word, frequency, null /* shortcutTargets */); } /** diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index cc98010fb..88da7b0d8 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -1317,8 +1317,16 @@ public class BinaryDictInputOutput { 0 != (optionsFlags & GERMAN_UMLAUT_PROCESSING_FLAG), 0 != (optionsFlags & FRENCH_LIGATURE_PROCESSING_FLAG))); if (null != dict) { - for (Word w : dict) { - newDict.add(w.mWord, w.mFrequency, w.mShortcutTargets, w.mBigrams); + for (final Word w : dict) { + newDict.add(w.mWord, w.mFrequency, w.mShortcutTargets); + } + for (final Word w : dict) { + // By construction a binary dictionary may not have bigrams pointing to + // words that are not also registered as unigrams so we don't have to avoid + // them explicitly here. + for (final WeightedString bigram : w.mBigrams) { + newDict.setBigram(w.mWord, bigram.mWord, bigram.mFrequency); + } } } diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index 40bcfc3aa..c293b2ba4 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -286,7 +286,7 @@ public class FusionDictionary implements Iterable { for (WeightedString word : words) { final CharGroup t = findWordInTree(mRoot, word.mWord); if (null == t) { - add(getCodePoints(word.mWord), 0, null, null); + add(getCodePoints(word.mWord), 0, null); } } } @@ -305,12 +305,8 @@ public class FusionDictionary implements Iterable { * @param bigrams a list of bigrams, or null. */ public void add(final String word, final int frequency, - final ArrayList shortcutTargets, - final ArrayList bigrams) { - if (null != bigrams) { - addNeutralWords(bigrams); - } - add(getCodePoints(word), frequency, shortcutTargets, bigrams); + final ArrayList shortcutTargets) { + add(getCodePoints(word), frequency, shortcutTargets); } /** @@ -344,7 +340,7 @@ public class FusionDictionary implements Iterable { final CharGroup charGroup2 = findWordInTree(mRoot, word2); if (charGroup2 == null) { // TODO: refactor with the identical code in addNeutralWords - add(getCodePoints(word2), 0, null, null); + add(getCodePoints(word2), 0, null); } charGroup.addBigram(word2, frequency); } else { @@ -355,17 +351,15 @@ public class FusionDictionary implements Iterable { /** * Add a word to this dictionary. * - * The shortcuts and bigrams, if any, have to be in the dictionary already. If they aren't, + * The shortcuts, if any, have to be in the dictionary already. If they aren't, * an exception is thrown. * * @param word the word, as an int array. * @param frequency the frequency of the word, in the range [0..255]. * @param shortcutTargets an optional list of shortcut targets for this word (null if none). - * @param bigrams an optional list of bigrams for this word (null if none). */ private void add(final int[] word, final int frequency, - final ArrayList shortcutTargets, - final ArrayList bigrams) { + final ArrayList shortcutTargets) { assert(frequency >= 0 && frequency <= 255); Node currentNode = mRoot; int charIndex = 0; @@ -390,7 +384,7 @@ public class FusionDictionary implements Iterable { final int insertionIndex = findInsertionIndex(currentNode, word[charIndex]); final CharGroup newGroup = new CharGroup( Arrays.copyOfRange(word, charIndex, word.length), - shortcutTargets, bigrams, frequency); + shortcutTargets, null /* bigrams */, frequency); currentNode.mData.add(insertionIndex, newGroup); checkStack(currentNode); } else { @@ -400,21 +394,21 @@ public class FusionDictionary implements Iterable { // The new word is a prefix of an existing word, but the node on which it // should end already exists as is. Since the old CharNode was not a terminal, // make it one by filling in its frequency and other attributes - currentGroup.update(frequency, shortcutTargets, bigrams); + currentGroup.update(frequency, shortcutTargets, null); } else { // The new word matches the full old word and extends past it. // We only have to create a new node and add it to the end of this. final CharGroup newNode = new CharGroup( Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length), - shortcutTargets, bigrams, frequency); + shortcutTargets, null /* bigrams */, frequency); currentGroup.mChildren = new Node(); currentGroup.mChildren.mData.add(newNode); } } else { if (0 == differentCharIndex) { // Exact same word. Update the frequency if higher. This will also add the - // new bigrams to the existing bigram list if it already exists. - currentGroup.update(frequency, shortcutTargets, bigrams); + // new shortcuts to the existing shortcut list if it already exists. + currentGroup.update(frequency, shortcutTargets, null); } else { // Partial prefix match only. We have to replace the current node with a node // containing the current prefix and create two new ones for the tails. @@ -429,14 +423,14 @@ public class FusionDictionary implements Iterable { if (charIndex + differentCharIndex >= word.length) { newParent = new CharGroup( Arrays.copyOfRange(currentGroup.mChars, 0, differentCharIndex), - shortcutTargets, bigrams, frequency, newChildren); + shortcutTargets, null /* bigrams */, frequency, newChildren); } else { newParent = new CharGroup( Arrays.copyOfRange(currentGroup.mChars, 0, differentCharIndex), - null, null, -1, newChildren); - final CharGroup newWord = new CharGroup( - Arrays.copyOfRange(word, charIndex + differentCharIndex, - word.length), shortcutTargets, bigrams, frequency); + null /* shortcutTargets */, null /* bigrams */, -1, newChildren); + final CharGroup newWord = new CharGroup(Arrays.copyOfRange(word, + charIndex + differentCharIndex, word.length), + shortcutTargets, null /* bigrams */, frequency); final int addIndex = word[charIndex + differentCharIndex] > currentGroup.mChars[differentCharIndex] ? 1 : 0; newChildren.mData.add(addIndex, newWord); @@ -494,7 +488,8 @@ public class FusionDictionary implements Iterable { */ private static int findInsertionIndex(final Node node, int character) { final ArrayList data = node.mData; - final CharGroup reference = new CharGroup(new int[] { character }, null, null, 0); + final CharGroup reference = new CharGroup(new int[] { character }, + null /* shortcutTargets */, null /* bigrams */, 0); int result = Collections.binarySearch(data, reference, CHARGROUP_COMPARATOR); return result >= 0 ? result : -result - 1; } diff --git a/tools/makedict/src/com/android/inputmethod/latin/makedict/XmlDictInputOutput.java b/tools/makedict/src/com/android/inputmethod/latin/makedict/XmlDictInputOutput.java index d1d2a9ca4..d86719a1d 100644 --- a/tools/makedict/src/com/android/inputmethod/latin/makedict/XmlDictInputOutput.java +++ b/tools/makedict/src/com/android/inputmethod/latin/makedict/XmlDictInputOutput.java @@ -72,19 +72,15 @@ public class XmlDictInputOutput { int mFreq; // the currently read freq String mWord; // the current word final HashMap> mShortcutsMap; - final HashMap> mBigramsMap; /** * Create the handler. * * @param shortcuts the shortcuts as a map. This may be empty, but may not be null. - * @param bigrams the bigrams as a map. This may be empty, but may not be null. */ - public UnigramHandler(final HashMap> shortcuts, - final HashMap> bigrams) { + public UnigramHandler(final HashMap> shortcuts) { mDictionary = null; mShortcutsMap = shortcuts; - mBigramsMap = bigrams; mWord = ""; mState = START; mFreq = 0; @@ -94,7 +90,6 @@ public class XmlDictInputOutput { final FusionDictionary dict = mDictionary; mDictionary = null; mShortcutsMap.clear(); - mBigramsMap.clear(); mWord = ""; mState = START; mFreq = 0; @@ -143,7 +138,7 @@ public class XmlDictInputOutput { @Override public void endElement(String uri, String localName, String qName) { if (WORD == mState) { - mDictionary.add(mWord, mFreq, mShortcutsMap.get(mWord), mBigramsMap.get(mWord)); + mDictionary.add(mWord, mFreq, mShortcutsMap.get(mWord)); mState = START; } } @@ -191,6 +186,7 @@ public class XmlDictInputOutput { } } + // This may return an empty map, but will never return null. public HashMap> getAssocMap() { return mAssocMap; } @@ -211,6 +207,7 @@ public class XmlDictInputOutput { BIGRAM_FREQ_ATTRIBUTE); } + // As per getAssocMap(), this never returns null. public HashMap> getBigramMap() { return getAssocMap(); } @@ -231,6 +228,7 @@ public class XmlDictInputOutput { TARGET_PRIORITY_ATTRIBUTE); } + // As per getAssocMap(), this never returns null. public HashMap> getShortcutMap() { return getAssocMap(); } @@ -260,10 +258,19 @@ public class XmlDictInputOutput { if (null != shortcuts) parser.parse(shortcuts, shortcutHandler); final UnigramHandler unigramHandler = - new UnigramHandler(shortcutHandler.getShortcutMap(), - bigramHandler.getBigramMap()); + new UnigramHandler(shortcutHandler.getShortcutMap()); parser.parse(unigrams, unigramHandler); - return unigramHandler.getFinalDictionary(); + final FusionDictionary dict = unigramHandler.getFinalDictionary(); + final HashMap> bigramMap = bigramHandler.getBigramMap(); + for (final String firstWord : bigramMap.keySet()) { + if (!dict.hasWord(firstWord)) continue; + final ArrayList bigramList = bigramMap.get(firstWord); + for (final WeightedString bigram : bigramList) { + if (!dict.hasWord(bigram.mWord)) continue; + dict.setBigram(firstWord, bigram.mWord, bigram.mFrequency); + } + } + return dict; } /** diff --git a/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java b/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java index 191eb804d..24042f120 100644 --- a/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java +++ b/tools/makedict/tests/com/android/inputmethod/latin/BinaryDictInputOutputTest.java @@ -43,11 +43,11 @@ public class BinaryDictInputOutputTest extends TestCase { final FusionDictionary dict = new FusionDictionary(new Node(), new DictionaryOptions(new HashMap(), false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); - dict.add("foo", 1, null, null); - dict.add("fta", 1, null, null); - dict.add("ftb", 1, null, null); - dict.add("bar", 1, null, null); - dict.add("fool", 1, null, null); + dict.add("foo", 1, null); + dict.add("fta", 1, null); + dict.add("ftb", 1, null); + dict.add("bar", 1, null); + dict.add("fool", 1, null); final ArrayList result = BinaryDictInputOutput.flattenTree(dict.mRoot); assertEquals(4, result.size()); while (!result.isEmpty()) { -- cgit v1.2.3-83-g751a From 4d289d39aeae21064f63d958974816ceee3e9fde Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Thu, 26 Apr 2012 23:50:21 -0700 Subject: Contacts dictionary rebuilds only when contact names have changed. Bug: 6396600 Change-Id: Iad693ec4bab6351793d624e5c5b0a9f5c12a60e3 --- .../inputmethod/latin/BinaryDictionary.java | 11 ++ .../latin/ContactsBinaryDictionary.java | 137 +++++++++++++++++++-- .../latin/ExpandableBinaryDictionary.java | 79 +++++++++--- ..._android_inputmethod_latin_BinaryDictionary.cpp | 15 +++ native/jni/src/bigram_dictionary.cpp | 22 +++- native/jni/src/bigram_dictionary.h | 1 + native/jni/src/dictionary.cpp | 5 + native/jni/src/dictionary.h | 1 + 8 files changed, 241 insertions(+), 30 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index a644ec0d9..cc20f4294 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -17,6 +17,7 @@ package com.android.inputmethod.latin; import android.content.Context; +import android.text.TextUtils; import com.android.inputmethod.keyboard.ProximityInfo; @@ -84,6 +85,7 @@ public class BinaryDictionary extends Dictionary { int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords); private native void closeNative(long dict); private native boolean isValidWordNative(long dict, int[] word, int wordLength); + private native boolean isValidBigramNative(long dict, int[] word1, int[] word2); private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, int[] yCoordinates, int[] inputCodes, int codesSize, int[] prevWordForBigrams, boolean useFullEditDistance, char[] outputChars, int[] scores); @@ -204,6 +206,15 @@ public class BinaryDictionary extends Dictionary { return isValidWordNative(mNativeDict, chars, chars.length); } + // TODO: Add a batch process version (isValidBigramMultiple?) to avoid excessive numbers of jni + // calls when checking for changes in an entire dictionary. + public boolean isValidBigram(CharSequence word1, CharSequence word2) { + if (TextUtils.isEmpty(word1) || TextUtils.isEmpty(word2)) return false; + int[] chars1 = StringUtils.toCodePointArray(word1.toString()); + int[] chars2 = StringUtils.toCodePointArray(word2.toString()); + return isValidBigramNative(mNativeDict, chars1, chars2); + } + @Override public synchronized void close() { closeInternal(); diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 65f97e987..22787c218 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -18,6 +18,7 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; +import android.os.SystemClock; import android.provider.BaseColumns; import android.provider.ContactsContract.Contacts; import android.text.TextUtils; @@ -30,18 +31,27 @@ import java.util.Locale; public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private static final String[] PROJECTION = {BaseColumns._ID, Contacts.DISPLAY_NAME,}; + private static final String[] PROJECTION_ID_ONLY = {BaseColumns._ID}; private static final String TAG = ContactsBinaryDictionary.class.getSimpleName(); private static final String NAME = "contacts"; + private static boolean DEBUG = false; + /** * Frequency for contacts information into the dictionary */ private static final int FREQUENCY_FOR_CONTACTS = 40; private static final int FREQUENCY_FOR_CONTACTS_BIGRAM = 90; + /** The maximum number of contacts that this dictionary supports. */ + private static final int MAX_CONTACT_COUNT = 10000; + private static final int INDEX_NAME = 1; + /** The number of contacts in the most recent dictionary rebuild. */ + static private int sContactCountAtLastRebuild = 0; + private ContentObserver mObserver; /** @@ -98,6 +108,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { if (cursor != null) { try { if (cursor.moveToFirst()) { + sContactCountAtLastRebuild = getContactCount(); addWords(cursor); } } finally { @@ -125,15 +136,28 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private void addWords(Cursor cursor) { clearFusionDictionary(); - while (!cursor.isAfterLast()) { + int count = 0; + while (!cursor.isAfterLast() && count < MAX_CONTACT_COUNT) { String name = cursor.getString(INDEX_NAME); - if (name != null && -1 == name.indexOf('@')) { + if (isValidName(name)) { addName(name); + ++count; } cursor.moveToNext(); } } + private int getContactCount() { + // TODO: consider switching to a rawQuery("select count(*)...") on the database if + // performance is a bottleneck. + final Cursor cursor = mContext.getContentResolver().query( + Contacts.CONTENT_URI, PROJECTION_ID_ONLY, null, null, null); + if (cursor != null) { + return cursor.getCount(); + } + return 0; + } + /** * Adds the words in a name (e.g., firstname/lastname) to the binary dictionary along with their * bigrams depending on locale. @@ -144,16 +168,9 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { // TODO: Better tokenization for non-Latin writing systems for (int i = 0; i < len; i++) { if (Character.isLetter(name.codePointAt(i))) { - int j; - for (j = i + 1; j < len; j++) { - final int codePoint = name.codePointAt(j); - if (!(codePoint == Keyboard.CODE_DASH || codePoint == Keyboard.CODE_SINGLE_QUOTE - || Character.isLetter(codePoint))) { - break; - } - } - String word = name.substring(i, j); - i = j - 1; + int end = getWordEndPosition(name, len, i); + String word = name.substring(i, end); + i = end - 1; // Don't add single letter words, possibly confuses // capitalization of i. final int wordLen = word.codePointCount(0, word.length()); @@ -169,4 +186,100 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { } } } + + /** + * Returns the index of the last letter in the word, starting from position startIndex. + */ + private static int getWordEndPosition(String string, int len, int startIndex) { + int end; + int cp = 0; + for (end = startIndex + 1; end < len; end += Character.charCount(cp)) { + cp = string.codePointAt(end); + if (!(cp == Keyboard.CODE_DASH || cp == Keyboard.CODE_SINGLE_QUOTE + || Character.isLetter(cp))) { + break; + } + } + return end; + } + + @Override + protected boolean hasContentChanged() { + final long startTime = SystemClock.uptimeMillis(); + final int contactCount = getContactCount(); + if (contactCount > MAX_CONTACT_COUNT) { + // If there are too many contacts then return false. In this rare case it is impossible + // to include all of them anyways and the cost of rebuilding the dictionary is too high. + // TODO: Sort and check only the MAX_CONTACT_COUNT most recent contacts? + return false; + } + if (contactCount != sContactCountAtLastRebuild) { + return true; + } + // Check all contacts since it's not possible to find out which names have changed. + // This is needed because it's possible to receive extraneous onChange events even when no + // name has changed. + Cursor cursor = mContext.getContentResolver().query( + Contacts.CONTENT_URI, PROJECTION, null, null, null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + while (!cursor.isAfterLast()) { + String name = cursor.getString(INDEX_NAME); + if (isValidName(name) && !isNameInDictionary(name)) { + if (DEBUG) { + Log.d(TAG, "Contact name missing: " + name + " (runtime = " + + (SystemClock.uptimeMillis() - startTime) + " ms)"); + } + return true; + } + cursor.moveToNext(); + } + } + } finally { + cursor.close(); + } + } + if (DEBUG) { + Log.d(TAG, "No contacts changed. (runtime = " + (SystemClock.uptimeMillis() - startTime) + + " ms)"); + } + return false; + } + + private static boolean isValidName(String name) { + if (name != null && -1 == name.indexOf('@')) { + return true; + } + return false; + } + + /** + * Checks if the words in a name are in the current binary dictionary. + */ + private boolean isNameInDictionary(String name) { + int len = name.codePointCount(0, name.length()); + 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 = word.codePointCount(0, word.length()); + if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { + if (!TextUtils.isEmpty(prevWord) && mUseFirstLastBigrams) { + if (!super.isValidBigramLocked(prevWord, word)) { + return false; + } + } else { + if (!super.isValidWordLocked(word)) { + return false; + } + } + prevWord = word; + } + } + } + return true; + } } diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 3d89226c0..22d8f24f1 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -95,6 +95,13 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ protected abstract void loadDictionaryAsync(); + /** + * Indicates that the source dictionary content has 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. Note that the shared binary dictionary is locked when this is called. + */ + protected abstract boolean hasContentChanged(); + /** * Gets the shared dictionary controller for the given filename. */ @@ -148,8 +155,9 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * the native side. */ public void clearFusionDictionary() { - mFusionDictionary = new FusionDictionary(new Node(), new FusionDictionary.DictionaryOptions( - new HashMap(), false, false)); + mFusionDictionary = new FusionDictionary(new Node(), + new FusionDictionary.DictionaryOptions(new HashMap(), false, + false)); } /** @@ -224,9 +232,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { protected boolean isValidWordInner(final CharSequence word) { if (mLocalDictionaryController.tryLock()) { try { - if (mBinaryDictionary != null) { - return mBinaryDictionary.isValidWord(word); - } + return isValidWordLocked(word); } finally { mLocalDictionaryController.unlock(); } @@ -234,6 +240,32 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { return false; } + protected boolean isValidWordLocked(final CharSequence word) { + if (mBinaryDictionary == null) return false; + return mBinaryDictionary.isValidWord(word); + } + + protected boolean isValidBigram(final CharSequence word1, final CharSequence word2) { + if (mBinaryDictionary == null) return false; + return mBinaryDictionary.isValidBigram(word1, word2); + } + + protected boolean isValidBigramInner(final CharSequence word1, final CharSequence word2) { + if (mLocalDictionaryController.tryLock()) { + try { + return isValidBigramLocked(word1, word2); + } finally { + mLocalDictionaryController.unlock(); + } + } + return false; + } + + protected boolean isValidBigramLocked(final CharSequence word1, final CharSequence word2) { + if (mBinaryDictionary == null) return false; + return mBinaryDictionary.isValidBigram(word1, word2); + } + /** * Load the current binary dictionary from internal storage in a background thread. If no binary * dictionary exists, this method will generate one. @@ -315,12 +347,16 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } /** - * Sets whether or not the dictionary is out of date and requires a reload. + * Marks that the dictionary is out of date and requires a reload. + * + * @param requiresRebuild Indicates that the source dictionary content has changed and a rebuild + * of the binary file is required. If not true, the next reload process will only read + * the current binary dictionary from file. */ - protected void setRequiresReload(final boolean reload) { - final long time = reload ? SystemClock.uptimeMillis() : 0; - mSharedDictionaryController.mLastUpdateRequestTime = time; + protected void setRequiresReload(final boolean requiresRebuild) { + final long time = SystemClock.uptimeMillis(); mLocalDictionaryController.mLastUpdateRequestTime = time; + mSharedDictionaryController.mLastUpdateRequestTime = time; if (DEBUG) { Log.d(TAG, "Reload request: request=" + time + " update=" + mSharedDictionaryController.mLastUpdateTime); @@ -351,21 +387,30 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { 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. - mSharedDictionaryController.mLastUpdateTime = time; - mLocalDictionaryController.mLastUpdateTime = time; - generateBinaryDictionary(); - loadBinaryDictionary(); - } else if (mLocalDictionaryController.isOutOfDate()) { - // Otherwise, if only the local dictionary for this instance is out of date, load - // the shared dictionary from file. - mLocalDictionaryController.mLastUpdateTime = time; + if (hasContentChanged()) { + // If the source content has changed, rebuild the binary dictionary. + mSharedDictionaryController.mLastUpdateTime = time; + generateBinaryDictionary(); + 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(); } + mLocalDictionaryController.mLastUpdateTime = time; } finally { mSharedDictionaryController.unlock(); } } + // TODO: cache the file's existence so that we avoid doing a disk access each time. private boolean dictionaryFileExists() { final File file = new File(mContext.getFilesDir(), mFilename); return file.exists(); diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index de9dbf9fd..b8f4ec77a 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -182,6 +182,20 @@ static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject objec return result; } +static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jobject object, jlong dict, + jintArray wordArray1, jintArray wordArray2) { + Dictionary *dictionary = (Dictionary*)dict; + if (!dictionary) return (jboolean) false; + jint *word1 = env->GetIntArrayElements(wordArray1, 0); + jint *word2 = env->GetIntArrayElements(wordArray2, 0); + jsize length1 = word1 ? env->GetArrayLength(wordArray1) : 0; + jsize length2 = word2 ? env->GetArrayLength(wordArray2) : 0; + jboolean result = dictionary->isValidBigram(word1, length1, word2, length2); + env->ReleaseIntArrayElements(wordArray2, word2, JNI_ABORT); + env->ReleaseIntArrayElements(wordArray1, word1, JNI_ABORT); + return result; +} + static jdouble latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object, jcharArray before, jint beforeLength, jcharArray after, jint afterLength, jint score) { jchar *beforeChars = env->GetCharArrayElements(before, 0); @@ -239,6 +253,7 @@ static JNINativeMethod sMethods[] = { {"getSuggestionsNative", "(JJ[I[I[II[IZ[C[I)I", (void*)latinime_BinaryDictionary_getSuggestions}, {"isValidWordNative", "(J[II)Z", (void*)latinime_BinaryDictionary_isValidWord}, + {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, {"getBigramsNative", "(J[II[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams}, {"calcNormalizedScoreNative", "([CI[CII)D", (void*)latinime_BinaryDictionary_calcNormalizedScore}, diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index 07031086c..7ed4dc439 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -128,7 +128,7 @@ int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, in ++bigramCount; } } - } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags)); + } while (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags); return bigramCount; } @@ -189,5 +189,25 @@ bool BigramDictionary::checkFirstCharacter(unsigned short *word) { return false; } +bool BigramDictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2, + int length2) { + const uint8_t* const root = DICT; + int pos = getBigramListPositionForWord(word1, length1); + // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams + if (0 == pos) return false; + int nextWordPos = BinaryFormat::getTerminalPosition(root, word2, length2); + if (NOT_VALID_WORD == nextWordPos) return false; + int bigramFlags; + do { + bigramFlags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); + const int bigramPos = BinaryFormat::getAttributeAddressAndForwardPointer(root, bigramFlags, + &pos); + if (bigramPos == nextWordPos) { + return true; + } + } while (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags); + return false; +} + // TODO: Move functions related to bigram to here } // namespace latinime diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h index 7328d5828..b8763a515 100644 --- a/native/jni/src/bigram_dictionary.h +++ b/native/jni/src/bigram_dictionary.h @@ -33,6 +33,7 @@ class BigramDictionary { int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength); void fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength, std::map *map, uint8_t *filter); + bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2); ~BigramDictionary(); private: bool addWordBigram(unsigned short *word, int length, int frequency); diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp index 9dc207223..8ea7c49fa 100644 --- a/native/jni/src/dictionary.cpp +++ b/native/jni/src/dictionary.cpp @@ -58,4 +58,9 @@ bool Dictionary::isValidWord(const int32_t *word, int length) { return mUnigramDictionary->isValidWord(word, length); } +bool Dictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2, + int length2) { + return mBigramDictionary->isValidBigram(word1, length1, word2, length2); +} + } // namespace latinime diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index bce86d1ad..87891ee4d 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -53,6 +53,7 @@ class Dictionary { } bool isValidWord(const int32_t *word, int length); + bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2); void *getDict() { return (void *)mDict; } int getDictSize() { return mDictSize; } int getMmapFd() { return mMmapFd; } -- cgit v1.2.3-83-g751a From f6adff6227a15af105dbf39c57213a24bf16780b Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Mon, 23 Apr 2012 10:45:48 -0700 Subject: Change to a binary version of the expandable user dictionary. Bug: 6435677 Change-Id: If83409f699608d443796e64a3c65692ae81b98e6 --- .../latin/ContactsBinaryDictionary.java | 8 +- .../latin/ExpandableBinaryDictionary.java | 17 +- .../com/android/inputmethod/latin/LatinIME.java | 21 +- ...ynchronouslyLoadedContactsBinaryDictionary.java | 1 - .../SynchronouslyLoadedUserBinaryDictionary.java | 47 +++++ .../latin/SynchronouslyLoadedUserDictionary.java | 9 + .../inputmethod/latin/UserBinaryDictionary.java | 211 +++++++++++++++++++++ .../android/inputmethod/latin/UserDictionary.java | 4 + .../spellcheck/AndroidSpellCheckerService.java | 7 +- 9 files changed, 311 insertions(+), 14 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java create mode 100644 java/src/com/android/inputmethod/latin/UserBinaryDictionary.java (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 22787c218..4b77473d9 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -60,7 +60,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { private final boolean mUseFirstLastBigrams; public ContactsBinaryDictionary(final Context context, final int dicTypeId, Locale locale) { - super(context, getFilenameWithLocale(locale), dicTypeId); + super(context, getFilenameWithLocale(NAME, locale.toString()), dicTypeId); mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale); registerObserver(context); @@ -69,10 +69,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { loadDictionary(); } - private static String getFilenameWithLocale(Locale locale) { - return NAME + "." + locale.toString() + ".dict"; - } - private synchronized void registerObserver(final Context context) { // Perform a managed query. The Activity will handle closing and requerying the cursor // when needed. @@ -175,7 +171,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { // capitalization of i. final int wordLen = word.codePointCount(0, word.length()); if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { - super.addWord(word, FREQUENCY_FOR_CONTACTS); + super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS); if (!TextUtils.isEmpty(prevWord)) { if (mUseFirstLastBigrams) { super.setBigram(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM); diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 22d8f24f1..08f585485 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -22,11 +22,13 @@ import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.makedict.BinaryDictInputOutput; 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 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; @@ -133,6 +135,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { clearFusionDictionary(); } + protected static String getFilenameWithLocale(final String name, final String localeStr) { + return name + "." + localeStr + ".dict"; + } + /** * Closes and cleans up the binary dictionary. */ @@ -166,8 +172,15 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries, // considering performance regression. - protected void addWord(final String word, final int frequency) { - mFusionDictionary.add(word, frequency, null /* shortcutTargets */); + protected void addWord(final String word, final String shortcutTarget, final int frequency) { + if (shortcutTarget == null) { + mFusionDictionary.add(word, frequency, null); + } else { + // TODO: Do this in the subclass, with this class taking an arraylist. + final ArrayList shortcutTargets = new ArrayList(); + shortcutTargets.add(new WeightedString(shortcutTarget, frequency)); + mFusionDictionary.add(word, frequency, shortcutTargets); + } } /** diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 261755f53..a9ef91f1b 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -106,6 +106,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen /** Whether to use the binary version of the contacts dictionary */ public static final boolean USE_BINARY_CONTACTS_DICTIONARY = true; + /** Whether to use the binary version of the user dictionary */ + public static final boolean USE_BINARY_USER_DICTIONARY = true; + // TODO: migrate this to SettingsValues private int mSuggestionVisibility; private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE @@ -158,7 +161,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private boolean mShouldSwitchToLastSubtype = true; private boolean mIsMainDictionaryAvailable; - private UserDictionary mUserDictionary; + // TODO: revert this back to the concrete class after transition. + private Dictionary mUserDictionary; private UserHistoryDictionary mUserHistoryDictionary; private boolean mIsUserDictionaryAvailable; @@ -476,9 +480,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); - mUserDictionary = new UserDictionary(this, localeStr); + if (USE_BINARY_USER_DICTIONARY) { + mUserDictionary = new UserBinaryDictionary(this, localeStr); + mIsUserDictionaryAvailable = ((UserBinaryDictionary)mUserDictionary).isEnabled(); + } else { + mUserDictionary = new UserDictionary(this, localeStr); + mIsUserDictionaryAvailable = ((UserDictionary)mUserDictionary).isEnabled(); + } mSuggest.setUserDictionary(mUserDictionary); - mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); resetContactsDictionary(oldContactsDictionary); @@ -1121,7 +1130,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public boolean addWordToDictionary(String word) { - mUserDictionary.addWordToUserDictionary(word, 128); + if (USE_BINARY_USER_DICTIONARY) { + ((UserBinaryDictionary)mUserDictionary).addWordToUserDictionary(word, 128); + } else { + ((UserDictionary)mUserDictionary).addWordToUserDictionary(word, 128); + } // Suggestion strip should be updated after the operation of adding word to the // user dictionary mHandler.postUpdateSuggestions(); diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index 188259ff8..4994e5902 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -26,7 +26,6 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD public SynchronouslyLoadedContactsBinaryDictionary(final Context context) { // TODO: add locale information. super(context, Suggest.DIC_CONTACTS, null); - mClosed = false; } @Override diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java new file mode 100644 index 000000000..1606a34e0 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin; + +import android.content.Context; + +import com.android.inputmethod.keyboard.ProximityInfo; + +public class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionary { + + public SynchronouslyLoadedUserBinaryDictionary(final Context context, final String locale) { + this(context, locale, false); + } + + public SynchronouslyLoadedUserBinaryDictionary(final Context context, final String locale, + final boolean alsoUseMoreRestrictiveLocales) { + super(context, locale, alsoUseMoreRestrictiveLocales); + } + + @Override + public synchronized void getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, + final ProximityInfo proximityInfo) { + syncReloadDictionaryIfRequired(); + getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + } + + @Override + public synchronized boolean isValidWord(CharSequence word) { + syncReloadDictionaryIfRequired(); + return isValidWordInner(word); + } +} diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java index b78be89b8..23a49c192 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java @@ -21,6 +21,7 @@ import android.content.Context; import com.android.inputmethod.keyboard.ProximityInfo; public class SynchronouslyLoadedUserDictionary extends UserDictionary { + private boolean mClosed; public SynchronouslyLoadedUserDictionary(final Context context, final String locale) { this(context, locale, false); @@ -44,4 +45,12 @@ public class SynchronouslyLoadedUserDictionary extends UserDictionary { blockingReloadDictionaryIfRequired(); return super.isValidWord(word); } + + // Protect against multiple closing + @Override + public synchronized void close() { + if (mClosed) return; + mClosed = true; + super.close(); + } } diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java new file mode 100644 index 000000000..6fa1a25a1 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin; + +import android.content.ContentProviderClient; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.ContentObserver; +import android.database.Cursor; +import android.provider.UserDictionary.Words; +import android.text.TextUtils; + +import java.util.Arrays; + +/** + * An expandable dictionary that stores the words in the user unigram dictionary. + * + * Largely a copy of UserDictionary, will replace that class in the future. + */ +public class UserBinaryDictionary extends ExpandableBinaryDictionary { + + // TODO: use Words.SHORTCUT when it's public in the SDK + final static String SHORTCUT = "shortcut"; + private static final String[] PROJECTION_QUERY = { + Words.WORD, + SHORTCUT, + Words.FREQUENCY, + }; + + private static final String NAME = "userunigram"; + + // This is not exported by the framework so we pretty much have to write it here verbatim + private static final String ACTION_USER_DICTIONARY_INSERT = + "com.android.settings.USER_DICTIONARY_INSERT"; + + private ContentObserver mObserver; + final private String mLocale; + final private boolean mAlsoUseMoreRestrictiveLocales; + + public UserBinaryDictionary(final Context context, final String locale) { + this(context, locale, false); + } + + public UserBinaryDictionary(final Context context, final String locale, + final boolean alsoUseMoreRestrictiveLocales) { + super(context, getFilenameWithLocale(NAME, locale), Suggest.DIC_USER); + if (null == locale) throw new NullPointerException(); // Catch the error earlier + mLocale = locale; + mAlsoUseMoreRestrictiveLocales = alsoUseMoreRestrictiveLocales; + // Perform a managed query. The Activity will handle closing and re-querying the cursor + // when needed. + ContentResolver cres = context.getContentResolver(); + + mObserver = new ContentObserver(null) { + @Override + public void onChange(boolean self) { + setRequiresReload(true); + } + }; + cres.registerContentObserver(Words.CONTENT_URI, true, mObserver); + + loadDictionary(); + } + + @Override + public synchronized void close() { + if (mObserver != null) { + mContext.getContentResolver().unregisterContentObserver(mObserver); + mObserver = null; + } + super.close(); + } + + @Override + public void loadDictionaryAsync() { + // Split the locale. For example "en" => ["en"], "de_DE" => ["de", "DE"], + // "en_US_foo_bar_qux" => ["en", "US", "foo_bar_qux"] because of the limit of 3. + // This is correct for locale processing. + // For this example, we'll look at the "en_US_POSIX" case. + final String[] localeElements = + TextUtils.isEmpty(mLocale) ? new String[] {} : mLocale.split("_", 3); + final int length = localeElements.length; + + final StringBuilder request = new StringBuilder("(locale is NULL)"); + String localeSoFar = ""; + // At start, localeElements = ["en", "US", "POSIX"] ; localeSoFar = "" ; + // and request = "(locale is NULL)" + for (int i = 0; i < length; ++i) { + // i | localeSoFar | localeElements + // 0 | "" | ["en", "US", "POSIX"] + // 1 | "en_" | ["en", "US", "POSIX"] + // 2 | "en_US_" | ["en", "en_US", "POSIX"] + localeElements[i] = localeSoFar + localeElements[i]; + localeSoFar = localeElements[i] + "_"; + // i | request + // 0 | "(locale is NULL)" + // 1 | "(locale is NULL) or (locale=?)" + // 2 | "(locale is NULL) or (locale=?) or (locale=?)" + request.append(" or (locale=?)"); + } + // At the end, localeElements = ["en", "en_US", "en_US_POSIX"]; localeSoFar = en_US_POSIX_" + // and request = "(locale is NULL) or (locale=?) or (locale=?) or (locale=?)" + + final String[] requestArguments; + // If length == 3, we already have all the arguments we need (common prefix is meaningless + // inside variants + if (mAlsoUseMoreRestrictiveLocales && length < 3) { + request.append(" or (locale like ?)"); + // The following creates an array with one more (null) position + final String[] localeElementsWithMoreRestrictiveLocalesIncluded = + Arrays.copyOf(localeElements, length + 1); + localeElementsWithMoreRestrictiveLocalesIncluded[length] = + localeElements[length - 1] + "_%"; + requestArguments = localeElementsWithMoreRestrictiveLocalesIncluded; + // If for example localeElements = ["en"] + // then requestArguments = ["en", "en_%"] + // and request = (locale is NULL) or (locale=?) or (locale like ?) + // If localeElements = ["en", "en_US"] + // then requestArguments = ["en", "en_US", "en_US_%"] + } else { + requestArguments = localeElements; + } + final Cursor cursor = mContext.getContentResolver().query( + Words.CONTENT_URI, PROJECTION_QUERY, request.toString(), requestArguments, null); + try { + addWords(cursor); + } finally { + if (null != cursor) cursor.close(); + } + } + + public boolean isEnabled() { + final ContentResolver cr = mContext.getContentResolver(); + final ContentProviderClient client = cr.acquireContentProviderClient(Words.CONTENT_URI); + if (client != null) { + client.release(); + return true; + } else { + return false; + } + } + + /** + * Adds a word to the user dictionary and makes it persistent. + * + * This will call upon the system interface to do the actual work through the intent readied by + * the system to this effect. + * + * @param word the word to add. If the word is capitalized, then the dictionary will + * recognize it as a capitalized word when searched. + * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered + * the highest. + * @TODO use a higher or float range for frequency + */ + public synchronized void addWordToUserDictionary(final String word, final int frequency) { + // TODO: do something for the UI. With the following, any sufficiently long word will + // look like it will go to the user dictionary but it won't. + // Safeguard against adding long words. Can cause stack overflow. + if (word.length() >= MAX_WORD_LENGTH) return; + + // TODO: Add an argument to the intent to specify the frequency. + Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT); + intent.putExtra(Words.WORD, word); + intent.putExtra(Words.LOCALE, mLocale); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + } + + private void addWords(Cursor cursor) { + clearFusionDictionary(); + if (cursor == null) return; + if (cursor.moveToFirst()) { + final int indexWord = cursor.getColumnIndex(Words.WORD); + final int indexShortcut = cursor.getColumnIndex(SHORTCUT); + final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY); + while (!cursor.isAfterLast()) { + String word = cursor.getString(indexWord); + String shortcut = cursor.getString(indexShortcut); + int frequency = cursor.getInt(indexFrequency); + // Safeguard against adding really long words. + if (word.length() < MAX_WORD_LENGTH) { + super.addWord(word, null, frequency); + } + if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) { + super.addWord(shortcut, word, frequency); + } + cursor.moveToNext(); + } + } + } + + @Override + protected boolean hasContentChanged() { + return true; + } +} diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java index 218bac72a..ea57db57c 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -29,6 +29,10 @@ import com.android.inputmethod.keyboard.ProximityInfo; import java.util.Arrays; +/** + * An expandable dictionary that stores the words in the user unigram dictionary. + * To be deprecated: functionality being transferred to UserBinaryDictionary. +*/ public class UserDictionary extends ExpandableDictionary { // TODO: use Words.SHORTCUT when it's public in the SDK diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index d7c8e3850..9807d2892 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -40,6 +40,7 @@ import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary; +import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary; import com.android.inputmethod.latin.WhitelistDictionary; import com.android.inputmethod.latin.WordComposer; @@ -403,7 +404,11 @@ public class AndroidSpellCheckerService extends SpellCheckerService final String localeStr = locale.toString(); Dictionary userDictionary = mUserDictionaries.get(localeStr); if (null == userDictionary) { - userDictionary = new SynchronouslyLoadedUserDictionary(this, localeStr, true); + if (LatinIME.USE_BINARY_USER_DICTIONARY) { + userDictionary = new SynchronouslyLoadedUserBinaryDictionary(this, localeStr, true); + } else { + userDictionary = new SynchronouslyLoadedUserDictionary(this, localeStr, true); + } mUserDictionaries.put(localeStr, userDictionary); } dictionaryCollection.addDictionary(userDictionary); -- cgit v1.2.3-83-g751a From 1ed017ef0e271ed3f3c212def6cc6ba95b14e780 Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Fri, 25 May 2012 11:16:30 -0700 Subject: Fix performance issue when there are no contacts in the dictionary dictionary. Bug: 6551480 Change-Id: I8681a1bd82423c612af2d012f9b872501d8c201d --- .../latin/ContactsBinaryDictionary.java | 4 +++ .../latin/ExpandableBinaryDictionary.java | 42 +++++++++++++++------- 2 files changed, 34 insertions(+), 12 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 0a09c845e..34308dfb3 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -214,6 +214,10 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { return false; } if (contactCount != sContactCountAtLastRebuild) { + if (DEBUG) { + Log.d(TAG, "Contact count changed: " + sContactCountAtLastRebuild + " to " + + contactCount); + } return true; } // Check all contacts since it's not possible to find out which names have changed. diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 08f585485..c65404cbc 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -294,7 +294,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ protected void loadBinaryDictionary() { if (DEBUG) { - Log.d(TAG, "Loading binary dictionary: request=" + Log.d(TAG, "Loading binary dictionary: " + mFilename + " request=" + mSharedDictionaryController.mLastUpdateRequestTime + " update=" + mSharedDictionaryController.mLastUpdateTime); } @@ -326,7 +326,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { */ private void generateBinaryDictionary() { if (DEBUG) { - Log.d(TAG, "Generating binary dictionary: request=" + Log.d(TAG, "Generating binary dictionary: " + mFilename + " request=" + mSharedDictionaryController.mLastUpdateRequestTime + " update=" + mSharedDictionaryController.mLastUpdateTime); } @@ -371,7 +371,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { mLocalDictionaryController.mLastUpdateRequestTime = time; mSharedDictionaryController.mLastUpdateRequestTime = time; if (DEBUG) { - Log.d(TAG, "Reload request: request=" + time + " update=" + Log.d(TAG, "Reload request: " + mFilename + ": request=" + time + " update=" + mSharedDictionaryController.mLastUpdateTime); } } @@ -380,28 +380,46 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * Reloads the dictionary if required. Reload will occur asynchronously in a separate thread. */ void asyncReloadDictionaryIfRequired() { + if (!isReloadRequired()) return; + if (DEBUG) { + Log.d(TAG, "Starting AsyncReloadDictionaryTask: " + mFilename); + } new AsyncReloadDictionaryTask().start(); } /** - * Reloads the dictionary if required. Access is controlled on a per dictionary file basis and - * supports concurrent calls from multiple instances that share the same dictionary file. + * Reloads the dictionary if required. */ protected final void syncReloadDictionaryIfRequired() { - if (mBinaryDictionary != null && !mLocalDictionaryController.isOutOfDate()) { - return; - } + if (!isReloadRequired()) return; + syncReloadDictionaryInternal(); + } + + /** + * Returns whether a dictionary reload is required. + */ + private boolean isReloadRequired() { + return mBinaryDictionary == null || mLocalDictionaryController.isOutOfDate(); + } + /** + * Reloads the dictionary. Access is controlled on a per dictionary file basis and supports + * concurrent calls from multiple instances that share the same dictionary file. + */ + 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(); try { final long time = SystemClock.uptimeMillis(); - if (mSharedDictionaryController.isOutOfDate() || !dictionaryFileExists()) { + 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()) { - // If the source content has changed, rebuild the binary dictionary. + 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(); loadBinaryDictionary(); @@ -435,7 +453,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { private class AsyncReloadDictionaryTask extends Thread { @Override public void run() { - syncReloadDictionaryIfRequired(); + syncReloadDictionaryInternal(); } } -- cgit v1.2.3-83-g751a From 73680097996ea2ddbca3f84144a00ce3ba66b763 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Mon, 25 Jun 2012 17:44:54 +0900 Subject: Change JNI for Gesture Change-Id: I774a0052038d16677f60f7efa11fd266cb5f3088 --- .../inputmethod/latin/BinaryDictionary.java | 45 +++++++++++++--------- .../com/android/inputmethod/latin/Dictionary.java | 5 ++- .../inputmethod/latin/DictionaryFactory.java | 6 +-- .../latin/ExpandableBinaryDictionary.java | 2 +- .../inputmethod/latin/ExpandableDictionary.java | 5 ++- .../src/com/android/inputmethod/latin/Suggest.java | 4 +- java/src/com/android/inputmethod/latin/Utils.java | 2 +- .../spellcheck/AndroidSpellCheckerService.java | 4 +- ..._android_inputmethod_latin_BinaryDictionary.cpp | 25 ++++++++---- native/jni/src/dictionary.h | 14 ++++--- 10 files changed, 68 insertions(+), 44 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index d0613bd72..b7a510021 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -40,6 +40,7 @@ public class BinaryDictionary extends Dictionary { */ public static final int MAX_WORD_LENGTH = 48; public static final int MAX_WORDS = 18; + public static final int MAX_SPACES = 16; private static final String TAG = "BinaryDictionary"; private static final int MAX_BIGRAMS = 60; @@ -51,6 +52,7 @@ public class BinaryDictionary extends Dictionary { private final int[] mInputCodes = new int[MAX_WORD_LENGTH]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; + private final int[] mSpaceIndices = new int[MAX_SPACES]; private final int[] mScores = new int[MAX_WORDS]; private final int[] mBigramScores = new int[MAX_BIGRAMS]; @@ -65,14 +67,12 @@ public class BinaryDictionary extends Dictionary { * @param offset the offset of the dictionary data within the file. * @param length the length of the binary data. * @param useFullEditDistance whether to use the full edit distance in suggestions + * @param dicTypeId the dictionary type id of the dictionary */ public BinaryDictionary(final Context context, final String filename, final long offset, final long length, - final boolean useFullEditDistance, final Locale locale) { - // Note: at the moment a binary dictionary is always of the "main" type. - // Initializing this here will help transitioning out of the scheme where - // the Suggest class knows everything about every single dictionary. - mDicTypeId = Suggest.DIC_MAIN; + final boolean useFullEditDistance, final Locale locale, final int dicTypeId) { + mDicTypeId = dicTypeId; mUseFullEditDistance = useFullEditDistance; loadDictionary(filename, offset, length); } @@ -87,8 +87,10 @@ public class BinaryDictionary extends Dictionary { private native int getFrequencyNative(long dict, int[] word, int wordLength); private native boolean isValidBigramNative(long dict, int[] word1, int[] word2); private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, - int[] yCoordinates, int[] inputCodes, int codesSize, int[] prevWordForBigrams, - boolean useFullEditDistance, char[] outputChars, int[] scores); + int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodes, int codesSize, + int commitPoint, boolean isGesture, int dicTypeId, + int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, + int[] scores, int[] outputIndices); private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, int maxWordLength, int maxBigrams); @@ -131,7 +133,7 @@ public class BinaryDictionary extends Dictionary { ++len; } if (len > 0) { - callback.addWord(mOutputChars_bigrams, start, len, mBigramScores[j], + callback.addWord(mOutputChars_bigrams, null, start, len, mBigramScores[j], mDicTypeId, Dictionary.BIGRAM); } } @@ -141,9 +143,9 @@ public class BinaryDictionary extends Dictionary { @Override public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { - final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, - mScores); + final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, + mScores, mSpaceIndices); for (int j = 0; j < count; ++j) { if (mScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; @@ -152,7 +154,7 @@ public class BinaryDictionary extends Dictionary { ++len; } if (len > 0) { - callback.addWord(mOutputChars, start, len, mScores[j], mDicTypeId, + callback.addWord(mOutputChars, null, start, len, mScores[j], mDicTypeId, Dictionary.UNIGRAM); } } @@ -165,7 +167,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo may not be null. /* package for test */ int getSuggestions(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo, - char[] outputChars, int[] scores) { + char[] outputChars, int[] scores, int[] spaceIndices) { if (!isValidDictionary()) return -1; final int codesSize = codes.size(); @@ -179,14 +181,21 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); - final int[] prevWordCodePointArray = null == prevWordForBigrams + // TODO: toLowerCase in the native code + final int[] prevWordCodePointArray = (null == prevWordForBigrams) ? null : StringUtils.toCodePointArray(prevWordForBigrams.toString()); - // TODO: pass the previous word to native code - return getSuggestionsNative( - mNativeDict, proximityInfo.getNativeProximityInfo(), - codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize, - prevWordCodePointArray, mUseFullEditDistance, outputChars, scores); + int[] emptyArray = new int[codesSize]; + Arrays.fill(emptyArray, 0); + + //final int commitPoint = codes.getCommitPoint(); + //codes.clearCommitPoint(); + + return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + codes.getXCoordinates(), codes.getYCoordinates(), emptyArray, emptyArray, mInputCodes, + codesSize, 0 /* unused */, false, mDicTypeId, + prevWordCodePointArray, mUseFullEditDistance, + outputChars, scores, spaceIndices); } public static float calcNormalizedScore(String before, String after, int score) { diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 9c3d46e70..c75e55d80 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -41,6 +41,7 @@ public abstract class Dictionary { * Adds a word to a list of suggestions. The word is expected to be ordered based on * the provided score. * @param word the character array containing the word + * @param spaceIndices the indices of inserted spaces * @param wordOffset starting offset of the word in the character array * @param wordLength length of valid characters in the character array * @param score the score of occurrence. This is normalized between 1 and 255, but @@ -49,8 +50,8 @@ public abstract class Dictionary { * @param dataType tells type of this data, either UNIGRAM or BIGRAM * @return true if the word was added, false if no more words are required */ - boolean addWord(char[] word, int wordOffset, int wordLength, int score, int dicTypeId, - int dataType); + boolean addWord(char[] word, int[] spaceIndices, int wordOffset, int wordLength, int score, + int dicTypeId, int dataType); } /** diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index a22d73af7..6d77c4dd2 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -59,7 +59,7 @@ public class DictionaryFactory { for (final AssetFileAddress f : assetFileList) { final BinaryDictionary binaryDictionary = new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, - useFullEditDistance, locale); + useFullEditDistance, locale, Suggest.DIC_MAIN); if (binaryDictionary.isValidDictionary()) { dictList.add(binaryDictionary); } @@ -112,7 +112,7 @@ public class DictionaryFactory { return null; } return new BinaryDictionary(context, sourceDir, afd.getStartOffset(), afd.getLength(), - false /* useFullEditDistance */, locale); + false /* useFullEditDistance */, locale, Suggest.DIC_MAIN); } catch (android.content.res.Resources.NotFoundException e) { Log.e(TAG, "Could not find the resource"); return null; @@ -140,7 +140,7 @@ public class DictionaryFactory { long startOffset, long length, final boolean useFullEditDistance, Locale locale) { if (dictionary.isFile()) { return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length, - useFullEditDistance, locale); + useFullEditDistance, locale, Suggest.DIC_MAIN); } else { Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); return null; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index c65404cbc..41d4aa061 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -306,7 +306,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // Build the new binary dictionary final BinaryDictionary newBinaryDictionary = new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */, - null); + null, mDicTypeId); if (mBinaryDictionary != null) { // Ensure all threads accessing the current dictionary have finished before swapping in diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index f5886aa12..c989614fb 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -660,8 +660,9 @@ public class ExpandableDictionary extends Dictionary { } while (node != null); if (freq >= 0) { - callback.addWord(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index, - freq, mDicTypeId, Dictionary.BIGRAM); + callback.addWord(mLookedUpString, null, index, + BinaryDictionary.MAX_WORD_LENGTH - index, freq, mDicTypeId, + Dictionary.BIGRAM); } } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 892245402..0938bd127 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -439,8 +439,8 @@ public class Suggest implements Dictionary.WordCallback { // TODO: Use codepoint instead of char @Override - public boolean addWord(final char[] word, final int offset, final int length, int score, - final int dicTypeId, final int dataType) { + public boolean addWord(final char[] word, int[] indices, final int offset, final int length, + int score, final int dicTypeId, final int dataType) { int dataTypeForLog = dataType; final ArrayList suggestions; final int prefMaxSuggestions; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a44b1f9ad..19ac71876 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -537,7 +537,7 @@ public class Utils { final Dictionary.WordCallback callback) { for (SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); - callback.addWord(suggestionStr.toCharArray(), 0, suggestionStr.length(), + callback.addWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(), suggestion.mScore, dicTypeId, dataType); } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 7fffc31c0..0bbf2acb1 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -238,8 +238,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService } @Override - synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, - int dicTypeId, int dataType) { + synchronized public boolean addWord(char[] word, int[] spaceIndices, int wordOffset, + int wordLength, int score, int dicTypeId, int dataType) { final int positionIndex = Arrays.binarySearch(mScores, 0, mLength, score); // binarySearch returns the index if the element exists, and - - 1 // if it doesn't. See documentation for binarySearch. diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index d10dc962e..3fa45da55 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -128,28 +128,37 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, jlong proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, - jintArray inputArray, jint arraySize, jintArray prevWordForBigrams, - jboolean useFullEditDistance, jcharArray outputArray, jintArray frequencyArray) { - Dictionary *dictionary = (Dictionary*)dict; + jintArray timesArray, jintArray pointerIdArray, jintArray inputArray, jint arraySize, + jint commitPoint, jboolean isGesture, jint dicTypeId, + jintArray prevWordForBigrams, jboolean useFullEditDistance, jcharArray outputArray, + jintArray frequencyArray, jintArray spaceIndexArray) { + Dictionary *dictionary = (Dictionary*) dict; if (!dictionary) return 0; ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, 0); int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, 0); + int *times = env->GetIntArrayElements(timesArray, 0); + int *pointerIds = env->GetIntArrayElements(pointerIdArray, 0); int *frequencies = env->GetIntArrayElements(frequencyArray, 0); int *inputCodes = env->GetIntArrayElements(inputArray, 0); jchar *outputChars = env->GetCharArrayElements(outputArray, 0); + int *spaceIndices = env->GetIntArrayElements(spaceIndexArray, 0); jint *prevWordChars = prevWordForBigrams ? env->GetIntArrayElements(prevWordForBigrams, 0) : 0; jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; - int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes, - arraySize, prevWordChars, prevWordLength, useFullEditDistance, - (unsigned short*) outputChars, frequencies); + int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, + inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, + dicTypeId, useFullEditDistance, (unsigned short*) outputChars, + frequencies, spaceIndices); if (prevWordChars) { env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); } + env->ReleaseIntArrayElements(spaceIndexArray, spaceIndices, 0); env->ReleaseCharArrayElements(outputArray, outputChars, 0); env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); + env->ReleaseIntArrayElements(pointerIdArray, pointerIds, 0); + env->ReleaseIntArrayElements(timesArray, times, 0); env->ReleaseIntArrayElements(yCoordinatesArray, yCoordinates, 0); env->ReleaseIntArrayElements(xCoordinatesArray, xCoordinates, 0); return count; @@ -251,8 +260,8 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { static JNINativeMethod sMethods[] = { {"openNative", "(Ljava/lang/String;JJIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, - {"getSuggestionsNative", "(JJ[I[I[II[IZ[C[I)I", - (void*)latinime_BinaryDictionary_getSuggestions}, + {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZI[IZ[C[I[I)I", + (void*) latinime_BinaryDictionary_getSuggestions}, {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, {"getBigramsNative", "(J[II[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams}, diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index fd69f79e3..76b25e59a 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -34,15 +34,19 @@ class Dictionary { int fullWordMultiplier, int maxWordLength, int maxWords); int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, - int *codes, int codesSize, const int32_t* prevWordChars, const int prevWordLength, - bool useFullEditDistance, unsigned short *outWords, int *frequencies) const { + int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, + int prevWordLength, int commitPoint, bool isGesture, int dicTypeId, + bool useFullEditDistance, unsigned short *outWords, + int *frequencies, int *spaceIndices) { + int result = 0; std::map bigramMap; uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE]; mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars, prevWordLength, &bigramMap, bigramFilter); - return mUnigramDictionary->getSuggestions(proximityInfo, - xcoordinates, ycoordinates, codes, codesSize, &bigramMap, - bigramFilter, useFullEditDistance, outWords, frequencies); + result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, + ycoordinates, codes, codesSize, &bigramMap, bigramFilter, + useFullEditDistance, outWords, frequencies); + return result; } int getBigrams(const int32_t *word, int length, int *codes, int codesSize, -- cgit v1.2.3-83-g751a From d82898c5a91f8aa69d5dc594b7a9290b8be1247a Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 13 Jun 2012 06:57:40 +0900 Subject: Change the return type of getWords and getBigrams (A8) This only returns stuff, but it doesn't change yet how the data is really passed. It merely adds a way of getting the same data. Later, the old way will be removed. Change-Id: If3a064de362175fc5a6781b7a97b65d8730aaf3c --- .../inputmethod/latin/BinaryDictionary.java | 13 ++++--- .../latin/ContactsBinaryDictionary.java | 6 --- .../com/android/inputmethod/latin/Dictionary.java | 13 ++++--- .../inputmethod/latin/DictionaryCollection.java | 43 ++++++++++++++++++---- .../latin/ExpandableBinaryDictionary.java | 27 ++++++++------ .../inputmethod/latin/ExpandableDictionary.java | 16 +++++--- ...ynchronouslyLoadedContactsBinaryDictionary.java | 6 ++- .../SynchronouslyLoadedUserBinaryDictionary.java | 7 +++- 8 files changed, 86 insertions(+), 45 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 16a563bcb..6b6ec2b45 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -107,9 +107,9 @@ public class BinaryDictionary extends Dictionary { } @Override - public void getBigrams(final WordComposer codes, final CharSequence previousWord, - final WordCallback callback) { - if (mNativeDict == 0) return; + public ArrayList getBigrams(final WordComposer codes, + final CharSequence previousWord, final WordCallback callback) { + if (mNativeDict == 0) return null; int[] codePoints = StringUtils.toCodePointArray(previousWord.toString()); Arrays.fill(mOutputChars_bigrams, (char) 0); @@ -142,12 +142,14 @@ public class BinaryDictionary extends Dictionary { } } Utils.addAllSuggestions(mDicTypeId, Dictionary.BIGRAM, suggestions, callback); + return suggestions; } // proximityInfo and/or prevWordForBigrams may not be null. @Override - public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, - final WordCallback callback, final ProximityInfo proximityInfo) { + public ArrayList getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, + final ProximityInfo proximityInfo) { final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, mScores, mSpaceIndices); @@ -167,6 +169,7 @@ public class BinaryDictionary extends Dictionary { } } Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback); + return suggestions; } /* package for test */ boolean isValidDictionary() { diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 10e511eaf..2a02603ca 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -120,12 +120,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { } } - @Override - public void getBigrams(final WordComposer codes, final CharSequence previousWord, - final WordCallback callback) { - super.getBigrams(codes, previousWord, callback); - } - private boolean useFirstLastBigramsForLocale(Locale locale) { // TODO: Add firstname/lastname bigram rules for other languages. if (locale != null && locale.getLanguage().equals(Locale.ENGLISH.getLanguage())) { diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index c75e55d80..55913b8eb 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -17,6 +17,9 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +import java.util.ArrayList; /** * Abstract base class for a dictionary that can do a fuzzy search for words based on a set of key @@ -61,9 +64,10 @@ public abstract class Dictionary { * @param prevWordForBigrams the previous word, or null if none * @param callback the callback object to send matched words to as possible candidates * @param proximityInfo the object for key proximity. May be ignored by some implementations. + * @return the list of suggestions * @see WordCallback#addWord(char[], int, int, int, int, int) */ - abstract public void getWords(final WordComposer composer, + abstract public ArrayList getWords(final WordComposer composer, final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo); @@ -73,11 +77,10 @@ public abstract class Dictionary { * @param composer the key sequence to match * @param previousWord the word before * @param callback the callback object to send possible word following previous word + * @return the list of suggestions */ - public void getBigrams(final WordComposer composer, final CharSequence previousWord, - final WordCallback callback) { - // empty base implementation - } + public abstract ArrayList getBigrams(final WordComposer composer, + final CharSequence previousWord, final WordCallback callback); /** * Checks if the given word occurs in the dictionary diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 26c2e637e..6b424f88f 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -17,9 +17,11 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import android.util.Log; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.concurrent.CopyOnWriteArrayList; @@ -50,17 +52,42 @@ public class DictionaryCollection extends Dictionary { } @Override - public void getWords(final WordComposer composer, final CharSequence prevWordForBigrams, - final WordCallback callback, final ProximityInfo proximityInfo) { - for (final Dictionary dict : mDictionaries) - dict.getWords(composer, prevWordForBigrams, callback, proximityInfo); + public ArrayList getWords(final WordComposer composer, + final CharSequence prevWordForBigrams, final WordCallback callback, + final ProximityInfo proximityInfo) { + final CopyOnWriteArrayList dictionaries = mDictionaries; + if (dictionaries.isEmpty()) return null; + // To avoid creating unnecessary objects, we get the list out of the first + // dictionary and add the rest to it if not null, hence the get(0) + ArrayList suggestions = dictionaries.get(0).getWords(composer, + prevWordForBigrams, callback, proximityInfo); + if (null == suggestions) suggestions = new ArrayList(); + final int length = dictionaries.size(); + for (int i = 0; i < length; ++ i) { + final ArrayList sugg = dictionaries.get(i).getWords(composer, + prevWordForBigrams, callback, proximityInfo); + if (null != sugg) suggestions.addAll(sugg); + } + return suggestions; } @Override - public void getBigrams(final WordComposer composer, final CharSequence previousWord, - final WordCallback callback) { - for (final Dictionary dict : mDictionaries) - dict.getBigrams(composer, previousWord, callback); + public ArrayList getBigrams(final WordComposer composer, + final CharSequence previousWord, final WordCallback callback) { + final CopyOnWriteArrayList dictionaries = mDictionaries; + if (dictionaries.isEmpty()) return null; + // To avoid creating unnecessary objects, we get the list out of the first + // dictionary and add the rest to it if not null, hence the get(0) + ArrayList suggestions = dictionaries.get(0).getBigrams(composer, + previousWord, callback); + if (null == suggestions) suggestions = new ArrayList(); + final int length = dictionaries.size(); + for (int i = 0; i < length; ++ i) { + final ArrayList sugg = + dictionaries.get(i).getBigrams(composer, previousWord, callback); + if (null != sugg) suggestions.addAll(sugg); + } + return suggestions; } @Override diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 41d4aa061..732bc1802 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -19,6 +19,7 @@ import android.os.SystemClock; 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.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.Node; @@ -194,13 +195,14 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { } @Override - public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, - final WordCallback callback, final ProximityInfo proximityInfo) { + public ArrayList getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, + final ProximityInfo proximityInfo) { asyncReloadDictionaryIfRequired(); - getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } - protected final void getWordsInner(final WordComposer codes, + protected final ArrayList getWordsInner(final WordComposer codes, final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { // Ensure that there are no concurrent calls to getWords. If there are, do nothing and @@ -208,32 +210,35 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { if (mLocalDictionaryController.tryLock()) { try { if (mBinaryDictionary != null) { - mBinaryDictionary.getWords(codes, prevWordForBigrams, callback, proximityInfo); + return mBinaryDictionary.getWords(codes, prevWordForBigrams, callback, + proximityInfo); } } finally { mLocalDictionaryController.unlock(); } } + return null; } @Override - public void getBigrams(final WordComposer codes, final CharSequence previousWord, - final WordCallback callback) { + public ArrayList getBigrams(final WordComposer codes, + final CharSequence previousWord, final WordCallback callback) { asyncReloadDictionaryIfRequired(); - getBigramsInner(codes, previousWord, callback); + return getBigramsInner(codes, previousWord, callback); } - protected void getBigramsInner(final WordComposer codes, final CharSequence previousWord, - final WordCallback callback) { + protected ArrayList getBigramsInner(final WordComposer codes, + final CharSequence previousWord, final WordCallback callback) { if (mLocalDictionaryController.tryLock()) { try { if (mBinaryDictionary != null) { - mBinaryDictionary.getBigrams(codes, previousWord, callback); + return mBinaryDictionary.getBigrams(codes, previousWord, callback); } } finally { mLocalDictionaryController.unlock(); } } + return null; } @Override diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index d1eec6b7c..7d131a664 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -248,20 +248,22 @@ public class ExpandableDictionary extends Dictionary { } @Override - public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, - final WordCallback callback, final ProximityInfo proximityInfo) { + public ArrayList getWords(final WordComposer codes, + final CharSequence prevWordForBigrams, final WordCallback callback, + final ProximityInfo proximityInfo) { 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; + if (mUpdatingDictionary) return null; } if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { - return; + return null; } final ArrayList suggestions = getWordsInner(codes, prevWordForBigrams, proximityInfo); Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback); + return suggestions; } protected final ArrayList getWordsInner(final WordComposer codes, @@ -611,13 +613,15 @@ public class ExpandableDictionary extends Dictionary { } @Override - public void getBigrams(final WordComposer codes, final CharSequence previousWord, - final WordCallback callback) { + public ArrayList getBigrams(final WordComposer codes, + final CharSequence previousWord, final WordCallback callback) { if (!reloadDictionaryIfRequired()) { final ArrayList suggestions = new ArrayList(); runBigramReverseLookUp(previousWord, suggestions); Utils.addAllSuggestions(mDicTypeId, Dictionary.BIGRAM, suggestions, callback); + return suggestions; } + return null; } /** diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index 673b54500..d706022bd 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -19,7 +19,9 @@ package com.android.inputmethod.latin; import android.content.Context; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import java.util.ArrayList; import java.util.Locale; public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryDictionary { @@ -30,11 +32,11 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD } @Override - public synchronized void getWords(final WordComposer codes, + public synchronized ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java index 1606a34e0..984e2e707 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java @@ -19,6 +19,9 @@ package com.android.inputmethod.latin; import android.content.Context; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +import java.util.ArrayList; public class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionary { @@ -32,11 +35,11 @@ public class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionar } @Override - public synchronized void getWords(final WordComposer codes, + public synchronized ArrayList getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); } @Override -- cgit v1.2.3-83-g751a From 60eed92dc37e59403142ac35bdf676ae7ceac298 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 21 Jun 2012 13:31:44 +0900 Subject: Remove the callback argument to getWords() (A15) Bug: 6252660 Bug: 6166228 Bug: 2704000 Bug: 6225530 Change-Id: I919bf70a1213ab5d7c7a9e5715bd72a6e257148b --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 3 +-- java/src/com/android/inputmethod/latin/Dictionary.java | 8 +++----- .../com/android/inputmethod/latin/DictionaryCollection.java | 7 +++---- .../android/inputmethod/latin/ExpandableBinaryDictionary.java | 11 ++++------- .../com/android/inputmethod/latin/ExpandableDictionary.java | 3 +-- java/src/com/android/inputmethod/latin/Suggest.java | 5 ++--- .../latin/SynchronouslyLoadedContactsBinaryDictionary.java | 5 ++--- .../latin/SynchronouslyLoadedUserBinaryDictionary.java | 5 ++--- 8 files changed, 18 insertions(+), 29 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 9b950d260..5603b3fb1 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -147,8 +147,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo and/or prevWordForBigrams may not be null. @Override public ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, mScores, mSpaceIndices); diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 55913b8eb..e999e5c61 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -59,17 +59,15 @@ public abstract class Dictionary { /** * Searches for words in the dictionary that match the characters in the composer. Matched - * words are added through the callback object. - * @param composer the key sequence to match + * words are returned as an ArrayList. + * @param composer the key sequence to match with coordinate info, as a WordComposer * @param prevWordForBigrams the previous word, or null if none - * @param callback the callback object to send matched words to as possible candidates * @param proximityInfo the object for key proximity. May be ignored by some implementations. * @return the list of suggestions * @see WordCallback#addWord(char[], int, int, int, int, int) */ abstract public ArrayList getWords(final WordComposer composer, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo); + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo); /** * Searches for pairs in the bigram dictionary that matches the previous word and all the diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 6b424f88f..0a2f5aa76 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -53,19 +53,18 @@ public class DictionaryCollection extends Dictionary { @Override public ArrayList getWords(final WordComposer composer, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { final CopyOnWriteArrayList dictionaries = mDictionaries; if (dictionaries.isEmpty()) return null; // To avoid creating unnecessary objects, we get the list out of the first // dictionary and add the rest to it if not null, hence the get(0) ArrayList suggestions = dictionaries.get(0).getWords(composer, - prevWordForBigrams, callback, proximityInfo); + prevWordForBigrams, proximityInfo); if (null == suggestions) suggestions = new ArrayList(); final int length = dictionaries.size(); for (int i = 0; i < length; ++ i) { final ArrayList sugg = dictionaries.get(i).getWords(composer, - prevWordForBigrams, callback, proximityInfo); + prevWordForBigrams, proximityInfo); if (null != sugg) suggestions.addAll(sugg); } return suggestions; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 732bc1802..4cb4c14e1 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -196,22 +196,19 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @Override public ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { asyncReloadDictionaryIfRequired(); - return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + return getWordsInner(codes, prevWordForBigrams, proximityInfo); } protected final ArrayList getWordsInner(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { // Ensure that there are no concurrent calls to getWords. If there are, do nothing and // return. if (mLocalDictionaryController.tryLock()) { try { if (mBinaryDictionary != null) { - return mBinaryDictionary.getWords(codes, prevWordForBigrams, callback, - proximityInfo); + return mBinaryDictionary.getWords(codes, prevWordForBigrams, proximityInfo); } } finally { mLocalDictionaryController.unlock(); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index e48e9e974..653fb760b 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -249,8 +249,7 @@ public class ExpandableDictionary extends Dictionary { @Override public ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { synchronized (mUpdatingLock) { // If we need to update, start off a background task if (mRequiresReload) startDictionaryLoadingTaskLocked(); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 1ae6557e1..29ecbe9ba 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -292,9 +292,8 @@ public class Suggest implements Dictionary.WordCallback { continue; final int dicTypeId = sDictKeyToDictIndex.get(key); final Dictionary dictionary = mUnigramDictionaries.get(key); - final ArrayList suggestions = - dictionary.getWords(wordComposerForLookup, prevWordForBigram, this, - proximityInfo); + final ArrayList suggestions = dictionary.getWords( + wordComposerForLookup, prevWordForBigram, proximityInfo); for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); oldAddWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(), diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index d706022bd..74f27e3cc 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -33,10 +33,9 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD @Override public synchronized ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + return getWordsInner(codes, prevWordForBigrams, proximityInfo); } @Override diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java index 984e2e707..5b2a6edec 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserBinaryDictionary.java @@ -36,10 +36,9 @@ public class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDictionar @Override public synchronized ArrayList getWords(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { syncReloadDictionaryIfRequired(); - return getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + return getWordsInner(codes, prevWordForBigrams, proximityInfo); } @Override -- cgit v1.2.3-83-g751a From 2f1b6c9ea438841fc2a7262a0593739c3dc82782 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 21 Jun 2012 13:40:51 +0900 Subject: Remove the callback argument to getBigrams() (A16) Bug: 6252660 Bug: 6166228 Bug: 2704000 Bug: 6225530 Change-Id: I7457ac04f8cd4019fb86c986725aae3de1b1a65e --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 2 +- java/src/com/android/inputmethod/latin/Dictionary.java | 6 ++---- java/src/com/android/inputmethod/latin/DictionaryCollection.java | 6 +++--- .../com/android/inputmethod/latin/ExpandableBinaryDictionary.java | 8 ++++---- java/src/com/android/inputmethod/latin/ExpandableDictionary.java | 2 +- java/src/com/android/inputmethod/latin/Suggest.java | 5 ++--- .../inputmethod/latin/spellcheck/AndroidSpellCheckerService.java | 2 +- 7 files changed, 14 insertions(+), 17 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 5603b3fb1..f44e6328b 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -108,7 +108,7 @@ public class BinaryDictionary extends Dictionary { @Override public ArrayList getBigrams(final WordComposer codes, - final CharSequence previousWord, final WordCallback callback) { + final CharSequence previousWord) { if (mNativeDict == 0) return null; int[] codePoints = StringUtils.toCodePointArray(previousWord.toString()); diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index e999e5c61..e6d3cfbbc 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -70,15 +70,13 @@ public abstract class Dictionary { final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo); /** - * Searches for pairs in the bigram dictionary that matches the previous word and all the - * possible words following are added through the callback object. + * Searches for pairs in the bigram dictionary that matches the previous word. * @param composer the key sequence to match * @param previousWord the word before - * @param callback the callback object to send possible word following previous word * @return the list of suggestions */ public abstract ArrayList getBigrams(final WordComposer composer, - final CharSequence previousWord, final WordCallback callback); + final CharSequence previousWord); /** * Checks if the given word occurs in the dictionary diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 0a2f5aa76..169e70745 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -72,18 +72,18 @@ public class DictionaryCollection extends Dictionary { @Override public ArrayList getBigrams(final WordComposer composer, - final CharSequence previousWord, final WordCallback callback) { + final CharSequence previousWord) { final CopyOnWriteArrayList dictionaries = mDictionaries; if (dictionaries.isEmpty()) return null; // To avoid creating unnecessary objects, we get the list out of the first // dictionary and add the rest to it if not null, hence the get(0) ArrayList suggestions = dictionaries.get(0).getBigrams(composer, - previousWord, callback); + previousWord); if (null == suggestions) suggestions = new ArrayList(); final int length = dictionaries.size(); for (int i = 0; i < length; ++ i) { final ArrayList sugg = - dictionaries.get(i).getBigrams(composer, previousWord, callback); + dictionaries.get(i).getBigrams(composer, previousWord); if (null != sugg) suggestions.addAll(sugg); } return suggestions; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 4cb4c14e1..c076fa0f9 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -219,17 +219,17 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @Override public ArrayList getBigrams(final WordComposer codes, - final CharSequence previousWord, final WordCallback callback) { + final CharSequence previousWord) { asyncReloadDictionaryIfRequired(); - return getBigramsInner(codes, previousWord, callback); + return getBigramsInner(codes, previousWord); } protected ArrayList getBigramsInner(final WordComposer codes, - final CharSequence previousWord, final WordCallback callback) { + final CharSequence previousWord) { if (mLocalDictionaryController.tryLock()) { try { if (mBinaryDictionary != null) { - return mBinaryDictionary.getBigrams(codes, previousWord, callback); + return mBinaryDictionary.getBigrams(codes, previousWord); } } finally { mLocalDictionaryController.unlock(); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 653fb760b..f19d77be2 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -612,7 +612,7 @@ public class ExpandableDictionary extends Dictionary { @Override public ArrayList getBigrams(final WordComposer codes, - final CharSequence previousWord, final WordCallback callback) { + final CharSequence previousWord) { if (!reloadDictionaryIfRequired()) { final ArrayList suggestions = new ArrayList(); runBigramReverseLookUp(previousWord, suggestions); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 29ecbe9ba..3729c99e4 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -263,10 +263,9 @@ public class Suggest implements Dictionary.WordCallback { final int dicTypeId = sDictKeyToDictIndex.get(key); final Dictionary dictionary = mBigramDictionaries.get(key); final ArrayList suggestions = - dictionary.getBigrams(wordComposer, prevWordForBigram, this); + dictionary.getBigrams(wordComposer, prevWordForBigram); if (null != lowerPrevWord) { - suggestions.addAll(dictionary.getBigrams(wordComposer, lowerPrevWord, - this)); + suggestions.addAll(dictionary.getBigrams(wordComposer, lowerPrevWord)); } for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index acaf3d235..129f74f60 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -789,7 +789,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService dictInfo = mDictionaryPool.takeOrGetNull(); if (null == dictInfo) return getNotInDictEmptySuggestions(); final ArrayList suggestions = dictInfo.mDictionary.getWords( - composer, prevWord, suggestionsGatherer, dictInfo.mProximityInfo); + composer, prevWord, dictInfo.mProximityInfo); for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); suggestionsGatherer.oldAddWord(suggestionStr.toCharArray(), null, 0, -- cgit v1.2.3-83-g751a From 05efe576f976f5fa280f8d523f2935c15cbb9bd1 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 27 Jun 2012 17:31:09 +0900 Subject: Cleanup the dictionary type. Stop storing an int in each of the different class types, and just store a string in the top class. Change-Id: I2af1832743e6fe78e5c1364f6d9cc21252bf5831 --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 12 +++++------- .../android/inputmethod/latin/ContactsBinaryDictionary.java | 4 ++-- java/src/com/android/inputmethod/latin/Dictionary.java | 6 ++++++ .../com/android/inputmethod/latin/DictionaryCollection.java | 9 ++++++--- .../src/com/android/inputmethod/latin/DictionaryFactory.java | 11 ++++++----- .../inputmethod/latin/ExpandableBinaryDictionary.java | 11 ++++------- .../com/android/inputmethod/latin/ExpandableDictionary.java | 5 ++--- java/src/com/android/inputmethod/latin/LatinIME.java | 5 ++--- .../latin/SynchronouslyLoadedContactsBinaryDictionary.java | 2 +- .../com/android/inputmethod/latin/UserBinaryDictionary.java | 2 +- .../com/android/inputmethod/latin/UserHistoryDictionary.java | 8 ++++---- .../com/android/inputmethod/latin/WhitelistDictionary.java | 2 +- .../jni/com_android_inputmethod_latin_BinaryDictionary.cpp | 6 +++--- native/jni/src/dictionary.h | 4 ++-- native/jni/src/gesture/impl/gesture_decoder_impl.h | 2 +- native/jni/src/gesture/incremental_decoder_interface.h | 2 +- 16 files changed, 47 insertions(+), 44 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index f44e6328b..8d5bc1595 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -49,7 +49,6 @@ public class BinaryDictionary extends Dictionary { private static final int TYPED_LETTER_MULTIPLIER = 2; - private int mDicTypeId; private long mNativeDict; private final int[] mInputCodes = new int[MAX_WORD_LENGTH]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; @@ -69,12 +68,12 @@ public class BinaryDictionary extends Dictionary { * @param offset the offset of the dictionary data within the file. * @param length the length of the binary data. * @param useFullEditDistance whether to use the full edit distance in suggestions - * @param dicTypeId the dictionary type id of the dictionary + * @param dictType the dictionary type, as a human-readable string */ public BinaryDictionary(final Context context, final String filename, final long offset, final long length, - final boolean useFullEditDistance, final Locale locale, final int dicTypeId) { - mDicTypeId = dicTypeId; + final boolean useFullEditDistance, final Locale locale, final String dictType) { + super(dictType); mUseFullEditDistance = useFullEditDistance; loadDictionary(filename, offset, length); } @@ -90,7 +89,7 @@ public class BinaryDictionary extends Dictionary { private native boolean isValidBigramNative(long dict, int[] word1, int[] word2); private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodes, int codesSize, - int commitPoint, boolean isGesture, int dicTypeId, + int commitPoint, boolean isGesture, int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, int[] scores, int[] outputIndices); private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength, @@ -202,8 +201,7 @@ public class BinaryDictionary extends Dictionary { return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), codes.getXCoordinates(), codes.getYCoordinates(), emptyArray, emptyArray, mInputCodes, - codesSize, 0 /* unused */, false, mDicTypeId, - prevWordCodePointArray, mUseFullEditDistance, + codesSize, 0 /* unused */, false, prevWordCodePointArray, mUseFullEditDistance, outputChars, scores, spaceIndices); } diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java index 620c553af..fbcaddae8 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -62,8 +62,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary { */ private final boolean mUseFirstLastBigrams; - public ContactsBinaryDictionary(final Context context, final int dicTypeId, Locale locale) { - super(context, getFilenameWithLocale(NAME, locale.toString()), dicTypeId); + public ContactsBinaryDictionary(final Context context, Locale locale) { + super(context, getFilenameWithLocale(NAME, locale.toString()), Suggest.DICT_KEY_CONTACTS); mLocale = locale; mUseFirstLastBigrams = useFirstLastBigramsForLocale(locale); registerObserver(context); diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 00896c364..ba1298356 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -33,6 +33,12 @@ public abstract class Dictionary { public static final int NOT_A_PROBABILITY = -1; + protected final String mDictType; + + public Dictionary(final String dictType) { + mDictType = dictType; + } + /** * Searches for words in the dictionary that match the characters in the composer. Matched * words are returned as an ArrayList. diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 169e70745..dcc53c59f 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -33,11 +33,13 @@ public class DictionaryCollection extends Dictionary { private final String TAG = DictionaryCollection.class.getSimpleName(); protected final CopyOnWriteArrayList mDictionaries; - public DictionaryCollection() { + public DictionaryCollection(final String dictType) { + super(dictType); mDictionaries = new CopyOnWriteArrayList(); } - public DictionaryCollection(Dictionary... dictionaries) { + public DictionaryCollection(final String dictType, Dictionary... dictionaries) { + super(dictType); if (null == dictionaries) { mDictionaries = new CopyOnWriteArrayList(); } else { @@ -46,7 +48,8 @@ public class DictionaryCollection extends Dictionary { } } - public DictionaryCollection(Collection dictionaries) { + public DictionaryCollection(final String dictType, Collection dictionaries) { + super(dictType); mDictionaries = new CopyOnWriteArrayList(dictionaries); mDictionaries.removeAll(Collections.singleton(null)); } diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 6d77c4dd2..7ccfe05cf 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -49,7 +49,8 @@ public class DictionaryFactory { final Locale locale, final boolean useFullEditDistance) { if (null == locale) { Log.e(TAG, "No locale defined for dictionary"); - return new DictionaryCollection(createBinaryDictionary(context, locale)); + return new DictionaryCollection(Suggest.DICT_KEY_MAIN, + createBinaryDictionary(context, locale)); } final LinkedList dictList = new LinkedList(); @@ -59,7 +60,7 @@ public class DictionaryFactory { for (final AssetFileAddress f : assetFileList) { final BinaryDictionary binaryDictionary = new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, - useFullEditDistance, locale, Suggest.DIC_MAIN); + useFullEditDistance, locale, Suggest.DICT_KEY_MAIN); if (binaryDictionary.isValidDictionary()) { dictList.add(binaryDictionary); } @@ -69,7 +70,7 @@ public class DictionaryFactory { // If the list is empty, that means we should not use any dictionary (for example, the user // explicitly disabled the main dictionary), so the following is okay. dictList is never // null, but if for some reason it is, DictionaryCollection handles it gracefully. - return new DictionaryCollection(dictList); + return new DictionaryCollection(Suggest.DICT_KEY_MAIN, dictList); } /** @@ -112,7 +113,7 @@ public class DictionaryFactory { return null; } return new BinaryDictionary(context, sourceDir, afd.getStartOffset(), afd.getLength(), - false /* useFullEditDistance */, locale, Suggest.DIC_MAIN); + false /* useFullEditDistance */, locale, Suggest.DICT_KEY_MAIN); } catch (android.content.res.Resources.NotFoundException e) { Log.e(TAG, "Could not find the resource"); return null; @@ -140,7 +141,7 @@ public class DictionaryFactory { long startOffset, long length, final boolean useFullEditDistance, Locale locale) { if (dictionary.isFile()) { return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length, - useFullEditDistance, locale, Suggest.DIC_MAIN); + useFullEditDistance, locale, Suggest.DICT_KEY_MAIN); } else { Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); return null; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index c076fa0f9..1cda9f257 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -76,9 +76,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { /** The expandable fusion dictionary used to generate the binary dictionary. */ private FusionDictionary mFusionDictionary; - /** The dictionary type id. */ - public final int mDicTypeId; - /** * The name of this dictionary, used as the filename for storing the binary dictionary. Multiple * dictionary instances with the same filename is supported, with access controlled by @@ -124,11 +121,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * @param context The application context of the parent. * @param filename The filename for this binary dictionary. Multiple dictionaries with the same * filename is supported. - * @param dictType The type of this dictionary. + * @param dictType the dictionary type, as a human-readable string */ public ExpandableBinaryDictionary( - final Context context, final String filename, final int dictType) { - mDicTypeId = dictType; + final Context context, final String filename, final String dictType) { + super(dictType); mFilename = filename; mContext = context; mBinaryDictionary = null; @@ -308,7 +305,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // Build the new binary dictionary final BinaryDictionary newBinaryDictionary = new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */, - null, mDicTypeId); + null, mDictType); if (mBinaryDictionary != null) { // Ensure all threads accessing the current dictionary have finished before swapping in diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index f19d77be2..e86a657e9 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -38,7 +38,6 @@ public class ExpandableDictionary extends Dictionary { private Context mContext; private char[] mWordBuilder = new char[BinaryDictionary.MAX_WORD_LENGTH]; - private int mDicTypeId; private int mMaxDepth; private int mInputLength; @@ -152,11 +151,11 @@ public class ExpandableDictionary extends Dictionary { private int[][] mCodes; - public ExpandableDictionary(Context context, int dicTypeId) { + public ExpandableDictionary(final Context context, final String dictType) { + super(dictType); mContext = context; clearDictionary(); mCodes = new int[BinaryDictionary.MAX_WORD_LENGTH][]; - mDicTypeId = dicTypeId; } public void loadDictionary() { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 25b8fd566..f6ba78674 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -499,8 +499,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // If the locale has changed then recreate the contacts dictionary. This // allows locale dependent rules for handling bigram name predictions. oldContactsDictionary.close(); - dictionaryToUse = new ContactsBinaryDictionary( - this, Suggest.DIC_CONTACTS, locale); + dictionaryToUse = new ContactsBinaryDictionary(this, locale); } else { // Make sure the old contacts dictionary is opened. If it is already open, // this is a no-op, so it's safe to call it anyways. @@ -508,7 +507,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen dictionaryToUse = oldContactsDictionary; } } else { - dictionaryToUse = new ContactsBinaryDictionary(this, Suggest.DIC_CONTACTS, locale); + dictionaryToUse = new ContactsBinaryDictionary(this, locale); } } diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java index 74f27e3cc..9b20bd690 100644 --- a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedContactsBinaryDictionary.java @@ -28,7 +28,7 @@ public class SynchronouslyLoadedContactsBinaryDictionary extends ContactsBinaryD private boolean mClosed; public SynchronouslyLoadedContactsBinaryDictionary(final Context context, final Locale locale) { - super(context, Suggest.DIC_CONTACTS, locale); + super(context, locale); } @Override diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index 5bcdb57b5..54c53df0c 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -69,7 +69,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { public UserBinaryDictionary(final Context context, final String locale, final boolean alsoUseMoreRestrictiveLocales) { - super(context, getFilenameWithLocale(NAME, locale), Suggest.DIC_USER); + super(context, getFilenameWithLocale(NAME, locale), Suggest.DICT_KEY_USER); if (null == locale) throw new NullPointerException(); // Catch the error earlier mLocale = locale; mAlsoUseMoreRestrictiveLocales = alsoUseMoreRestrictiveLocales; diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 5095f6582..d14006651 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -128,14 +128,14 @@ public class UserHistoryDictionary extends ExpandableDictionary { } } final UserHistoryDictionary dict = - new UserHistoryDictionary(context, locale, dictTypeId, sp); + new UserHistoryDictionary(context, locale, sp); sLangDictCache.put(locale, new SoftReference(dict)); return dict; } - private UserHistoryDictionary(final Context context, final String locale, final int dicTypeId, - SharedPreferences sp) { - super(context, dicTypeId); + private UserHistoryDictionary(final Context context, final String locale, + final SharedPreferences sp) { + super(context, Suggest.DICT_KEY_USER_HISTORY); mLocale = locale; mPrefs = sp; if (sOpenHelper == null) { diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java index a0de2f970..dc5706521 100644 --- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java +++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java @@ -37,7 +37,7 @@ public class WhitelistDictionary extends ExpandableDictionary { // TODO: Conform to the async load contact of ExpandableDictionary public WhitelistDictionary(final Context context, final Locale locale) { - super(context, Suggest.DIC_WHITELIST); + super(context, Suggest.DICT_KEY_WHITELIST); // TODO: Move whitelist dictionary into main dictionary. final RunInLocale job = new RunInLocale() { @Override diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index 3fa45da55..bee0662ee 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -129,7 +129,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, jlong proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdArray, jintArray inputArray, jint arraySize, - jint commitPoint, jboolean isGesture, jint dicTypeId, + jint commitPoint, jboolean isGesture, jintArray prevWordForBigrams, jboolean useFullEditDistance, jcharArray outputArray, jintArray frequencyArray, jintArray spaceIndexArray) { Dictionary *dictionary = (Dictionary*) dict; @@ -148,7 +148,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, - dicTypeId, useFullEditDistance, (unsigned short*) outputChars, + useFullEditDistance, (unsigned short*) outputChars, frequencies, spaceIndices); if (prevWordChars) { env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); @@ -260,7 +260,7 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { static JNINativeMethod sMethods[] = { {"openNative", "(Ljava/lang/String;JJIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, - {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZI[IZ[C[I[I)I", + {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZ[IZ[C[I[I)I", (void*) latinime_BinaryDictionary_getSuggestions}, {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index 708cb0909..8b4769431 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -36,14 +36,14 @@ class Dictionary { int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, - int prevWordLength, int commitPoint, bool isGesture, int dicTypeId, + int prevWordLength, int commitPoint, bool isGesture, bool useFullEditDistance, unsigned short *outWords, int *frequencies, int *spaceIndices) { int result = 0; if (isGesture) { mGestureDecoder->setPrevWord(prevWordChars, prevWordLength); result = mGestureDecoder->getSuggestions(proximityInfo, xcoordinates, ycoordinates, - times, pointerIds, codes, codesSize, commitPoint, dicTypeId == 1 /* main */, + times, pointerIds, codes, codesSize, commitPoint, outWords, frequencies, spaceIndices); } else { std::map bigramMap; diff --git a/native/jni/src/gesture/impl/gesture_decoder_impl.h b/native/jni/src/gesture/impl/gesture_decoder_impl.h index be4e8b3c2..0ca89941c 100644 --- a/native/jni/src/gesture/impl/gesture_decoder_impl.h +++ b/native/jni/src/gesture/impl/gesture_decoder_impl.h @@ -30,7 +30,7 @@ class GestureDecoderImpl : public IncrementalDecoder { } int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, - int *pointerIds, int *codes, int inputSize, int commitPoint, bool isMainDict, + int *pointerIds, int *codes, int inputSize, int commitPoint, unsigned short *outWords, int *frequencies, int *outputIndices) { return 0; } diff --git a/native/jni/src/gesture/incremental_decoder_interface.h b/native/jni/src/gesture/incremental_decoder_interface.h index c5404a40c..565f89c90 100644 --- a/native/jni/src/gesture/incremental_decoder_interface.h +++ b/native/jni/src/gesture/incremental_decoder_interface.h @@ -28,7 +28,7 @@ class IncrementalDecoderInterface { public: virtual int getSuggestions(ProximityInfo *pInfo, int *inputXs, int *inputYs, int *times, - int *pointerIds, int *codes, int inputSize, int commitPoint, bool isMainDict, + int *pointerIds, int *codes, int inputSize, int commitPoint, unsigned short *outWords, int *frequencies, int *outputIndices) = 0; virtual void reset() = 0; virtual void setDict(const UnigramDictionary *dict, const BigramDictionary *bigram, -- cgit v1.2.3-83-g751a