aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
-rw-r--r--java/src/com/android/inputmethod/latin/AutoCorrection.java2
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java27
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java49
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java1
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java1
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java32
-rw-r--r--java/src/com/android/inputmethod/latin/WhitelistDictionary.java119
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java23
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java14
9 files changed, 84 insertions, 184 deletions
diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
index 048166807..01ba30077 100644
--- a/java/src/com/android/inputmethod/latin/AutoCorrection.java
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -39,7 +39,6 @@ public class AutoCorrection {
}
final CharSequence lowerCasedWord = word.toString().toLowerCase();
for (final String key : dictionaries.keySet()) {
- if (key.equals(Dictionary.TYPE_WHITELIST)) continue;
final Dictionary dictionary = dictionaries.get(key);
// It's unclear how realistically 'dictionary' can be null, but the monkey is somehow
// managing to get null in here. Presumably the language is changing to a language with
@@ -64,7 +63,6 @@ public class AutoCorrection {
}
int maxFreq = -1;
for (final String key : dictionaries.keySet()) {
- if (key.equals(Dictionary.TYPE_WHITELIST)) continue;
final Dictionary dictionary = dictionaries.get(key);
if (null == dictionary) continue;
final int tempFreq = dictionary.getFrequency(word);
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 726c44cc1..2d9e0ce2c 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -64,18 +64,21 @@ public class BinaryDictionary extends Dictionary {
private final SparseArray<DicTraverseSession> mDicTraverseSessions =
new SparseArray<DicTraverseSession>();
+
+ // TODO: There should be a way to remove used DicTraverseSession objects from
+ // {@code mDicTraverseSessions}.
private DicTraverseSession getTraverseSession(int traverseSessionId) {
- DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId);
- if (traverseSession == null) {
- synchronized(mDicTraverseSessions) {
+ synchronized(mDicTraverseSessions) {
+ DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId);
+ if (traverseSession == null) {
traverseSession = mDicTraverseSessions.get(traverseSessionId);
if (traverseSession == null) {
traverseSession = new DicTraverseSession(mLocale, mNativeDict);
mDicTraverseSessions.put(traverseSessionId, traverseSession);
}
}
+ return traverseSession;
}
- return traverseSession;
}
/**
@@ -209,18 +212,20 @@ public class BinaryDictionary extends Dictionary {
}
@Override
- public synchronized void close() {
- for (int i = 0; i < mDicTraverseSessions.size(); ++i) {
- final int key = mDicTraverseSessions.keyAt(i);
- final DicTraverseSession traverseSession = mDicTraverseSessions.get(key);
- if (traverseSession != null) {
- traverseSession.close();
+ public void close() {
+ synchronized (mDicTraverseSessions) {
+ final int sessionsSize = mDicTraverseSessions.size();
+ for (int index = 0; index < sessionsSize; ++index) {
+ final DicTraverseSession traverseSession = mDicTraverseSessions.valueAt(index);
+ if (traverseSession != null) {
+ traverseSession.close();
+ }
}
}
closeInternal();
}
- private void closeInternal() {
+ private synchronized void closeInternal() {
if (mNativeDict != 0) {
closeNative(mNativeDict);
mNativeDict = 0;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 063243e1b..dd11aaa37 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -16,6 +16,8 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
+
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -23,6 +25,7 @@ import android.content.res.AssetFileDescriptor;
import android.util.Log;
import java.io.File;
+import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
@@ -51,6 +54,9 @@ class BinaryDictionaryGetter {
private static final String MAIN_DICTIONARY_CATEGORY = "main";
public static final String ID_CATEGORY_SEPARATOR = ":";
+ // The key considered to read the version attribute in a dictionary file.
+ private static String VERSION_KEY = "version";
+
// Prevents this from being instantiated
private BinaryDictionaryGetter() {}
@@ -336,6 +342,42 @@ class BinaryDictionaryGetter {
return MAIN_DICTIONARY_CATEGORY.equals(idArray[0]);
}
+ // ## HACK ## we prevent usage of a dictionary before version 18 for English only. The reason
+ // for this is, since those do not include whitelist entries, the new code with an old version
+ // of the dictionary would lose whitelist functionality.
+ private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) {
+ // Only for English - other languages didn't have a whitelist, hence this
+ // ad-hock ## HACK ##
+ if (!Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) return true;
+
+ try {
+ // Read the version of the file
+ final RandomAccessFile raf = new RandomAccessFile(f, "r");
+ final int magic = raf.readInt();
+ if (magic != BinaryDictInputOutput.VERSION_2_MAGIC_NUMBER) {
+ return false;
+ }
+ final int formatVersion = raf.readInt();
+ final int headerSize = raf.readInt();
+ final HashMap<String, String> options = new HashMap<String, String>();
+ BinaryDictInputOutput.populateOptionsFromFile(raf, headerSize, options);
+ final String version = options.get(VERSION_KEY);
+ if (null == version) {
+ // No version in the options : the format is unexpected
+ return false;
+ }
+ // Version 18 is the first one to include the whitelist
+ // Obviously this is a big ## HACK ##
+ return Integer.parseInt(version) >= 18;
+ } catch (java.io.FileNotFoundException e) {
+ return false;
+ } catch (java.io.IOException e) {
+ return false;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
/**
* Returns a list of file addresses for a given locale, trying relevant methods in order.
*
@@ -366,14 +408,15 @@ class BinaryDictionaryGetter {
// cachedWordLists may not be null, see doc for getCachedDictionaryList
for (final File f : cachedWordLists) {
final String wordListId = getWordListIdFromFileName(f.getName());
- if (isMainWordListId(wordListId)) {
+ final boolean canUse = f.canRead() && hackCanUseDictionaryFile(locale, f);
+ if (canUse && isMainWordListId(wordListId)) {
foundMainDict = true;
}
if (!dictPackSettings.isWordListActive(wordListId)) continue;
- if (f.canRead()) {
+ if (canUse) {
fileList.add(AssetFileAddress.makeFromFileName(f.getPath()));
} else {
- Log.e(TAG, "Found a cached dictionary file but cannot read it");
+ Log.e(TAG, "Found a cached dictionary file but cannot read or use it");
}
}
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 2565dfc66..88d0c09dd 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -42,7 +42,6 @@ public abstract class Dictionary {
public static final String TYPE_USER = "user";
// User history dictionary internal to LatinIME.
public static final String TYPE_USER_HISTORY = "history";
- public static final String TYPE_WHITELIST ="whitelist";
protected final String mDictType;
public Dictionary(final String dictType) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index a4c82c9f7..aa2f185e8 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1669,6 +1669,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
Utils.Stats.onSeparator((char)primaryCode, x, y);
+ mHandler.postUpdateShiftState();
return didAutoCorrect;
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 1f43c6d85..e9314084a 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -50,7 +50,6 @@ public class Suggest {
private Dictionary mMainDictionary;
private ContactsBinaryDictionary mContactsDict;
- private WhitelistDictionary mWhiteListDictionary;
private final ConcurrentHashMap<String, Dictionary> mDictionaries =
new ConcurrentHashMap<String, Dictionary>();
@@ -74,21 +73,11 @@ public class Suggest {
mLocale = locale;
mMainDictionary = mainDict;
addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, mainDict);
- initWhitelistAndAutocorrectAndPool(context, locale);
- }
-
- private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) {
- mWhiteListDictionary = new WhitelistDictionary(context, locale);
- addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_WHITELIST, mWhiteListDictionary);
}
private void initAsynchronously(final Context context, final Locale locale,
final SuggestInitializationListener listener) {
resetMainDict(context, locale, listener);
-
- // TODO: read the whitelist and init the pool asynchronously too.
- // initPool should be done asynchronously now that the pool is thread-safe.
- initWhitelistAndAutocorrectAndPool(context, locale);
}
private static void addOrReplaceDictionary(
@@ -216,15 +205,6 @@ public class Suggest {
wordComposerForLookup, prevWordForBigram, proximityInfo));
}
- final CharSequence whitelistedWordFromWhitelistDictionary =
- mWhiteListDictionary.getWhitelistedWord(consideredWord);
- if (whitelistedWordFromWhitelistDictionary != null) {
- // MAX_SCORE ensures this will be considered strong enough to be auto-corrected
- suggestionsSet.add(new SuggestedWordInfo(whitelistedWordFromWhitelistDictionary,
- SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST,
- Dictionary.TYPE_WHITELIST));
- }
-
final CharSequence whitelistedWord;
if (suggestionsSet.isEmpty()) {
whitelistedWord = null;
@@ -234,11 +214,6 @@ public class Suggest {
whitelistedWord = suggestionsSet.first().mWord;
}
- // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
- // but still autocorrected from - in the case the whitelist only capitalizes the word.
- // The whitelist should be case-insensitive, so it's not possible to be consistent with
- // a boolean flag. Right now this is handled with a slight hack in
- // WhitelistDictionary#shouldForciblyAutoCorrectFrom.
final boolean allowsToBeAutoCorrected = (null != whitelistedWord
&& !whitelistedWord.equals(consideredWord))
|| AutoCorrection.isNotAWord(mDictionaries, consideredWord,
@@ -320,9 +295,10 @@ public class Suggest {
// At second character typed, search the unigrams (scores being affected by bigrams)
for (final String key : mDictionaries.keySet()) {
- // Skip UserUnigramDictionary and WhitelistDictionary to lookup
- if (key.equals(Dictionary.TYPE_USER_HISTORY)
- || key.equals(Dictionary.TYPE_WHITELIST)) {
+ // Skip User history dictionary for lookup
+ // TODO: The user history dictionary should just override getSuggestionsWithSessionId
+ // to make sure it doesn't return anything and we should remove this test
+ if (key.equals(Dictionary.TYPE_USER_HISTORY)) {
continue;
}
final Dictionary dictionary = mDictionaries.get(key);
diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
deleted file mode 100644
index 14476dcf0..000000000
--- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2011 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.content.res.Resources;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Locale;
-
-public class WhitelistDictionary extends ExpandableDictionary {
-
- private static final boolean DBG = LatinImeLogger.sDBG;
- private static final String TAG = WhitelistDictionary.class.getSimpleName();
-
- private final HashMap<String, Pair<Integer, String>> mWhitelistWords =
- new HashMap<String, Pair<Integer, String>>();
-
- // TODO: Conform to the async load contact of ExpandableDictionary
- public WhitelistDictionary(final Context context, final Locale locale) {
- super(context, Dictionary.TYPE_WHITELIST);
- // TODO: Move whitelist dictionary into main dictionary.
- final RunInLocale<Void> job = new RunInLocale<Void>() {
- @Override
- protected Void job(Resources res) {
- initWordlist(res.getStringArray(R.array.wordlist_whitelist));
- return null;
- }
- };
- job.runInLocale(context.getResources(), locale);
- }
-
- private void initWordlist(String[] wordlist) {
- mWhitelistWords.clear();
- final int N = wordlist.length;
- if (N % 3 != 0) {
- if (DBG) {
- Log.d(TAG, "The number of the whitelist is invalid.");
- }
- return;
- }
- try {
- for (int i = 0; i < N; i += 3) {
- final int score = Integer.valueOf(wordlist[i]);
- final String before = wordlist[i + 1];
- final String after = wordlist[i + 2];
- if (before != null && after != null) {
- mWhitelistWords.put(
- before.toLowerCase(), new Pair<Integer, String>(score, after));
- addWord(after, null /* shortcut */, score);
- }
- }
- } catch (NumberFormatException e) {
- if (DBG) {
- Log.d(TAG, "The score of the word is invalid.");
- }
- }
- }
-
- public String getWhitelistedWord(String before) {
- if (before == null) return null;
- final String lowerCaseBefore = before.toLowerCase();
- if(mWhitelistWords.containsKey(lowerCaseBefore)) {
- if (DBG) {
- Log.d(TAG, "--- found whitelistedWord: " + lowerCaseBefore);
- }
- return mWhitelistWords.get(lowerCaseBefore).second;
- }
- return null;
- }
-
- @Override
- public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
- final CharSequence prevWord, final ProximityInfo proximityInfo) {
- // Whitelist does not supply any suggestions or predictions.
- return null;
- }
-
- // See LatinIME#updateSuggestions. This breaks in the (queer) case that the whitelist
- // lists that word a should autocorrect to word b, and word c would autocorrect to
- // an upper-cased version of a. In this case, the way this return value is used would
- // remove the first candidate when the user typed the upper-cased version of A.
- // Example : abc -> def and xyz -> Abc
- // A user typing Abc would experience it being autocorrected to something else (not
- // necessarily def).
- // There is no such combination in the whitelist at the time and there probably won't
- // ever be - it doesn't make sense. But still.
- public boolean shouldForciblyAutoCorrectFrom(CharSequence word) {
- if (TextUtils.isEmpty(word)) return false;
- final String correction = getWhitelistedWord(word.toString());
- if (TextUtils.isEmpty(correction)) return false;
- return !correction.equals(word);
- }
-
- // Leave implementation of getWords and isValidWord to the superclass.
- // The words have been added to the ExpandableDictionary with addWord() inside initWordlist.
-}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 7f042335a..b23b7db34 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -124,7 +124,7 @@ public class BinaryDictInputOutput {
*/
private static final int VERSION_1_MAGIC_NUMBER = 0x78B1;
- private static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
+ public static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
private static final int MINIMUM_SUPPORTED_VERSION = 1;
private static final int MAXIMUM_SUPPORTED_VERSION = 2;
private static final int NOT_A_VERSION_NUMBER = -1;
@@ -1328,6 +1328,21 @@ public class BinaryDictInputOutput {
}
/**
+ * Reads options from a file and populate a map with their contents.
+ *
+ * The file is read at the current file pointer, so the caller must take care the pointer
+ * is in the right place before calling this.
+ */
+ public static void populateOptionsFromFile(final RandomAccessFile source, final long headerSize,
+ final HashMap<String, String> options) throws IOException {
+ while (source.getFilePointer() < headerSize) {
+ final String key = CharEncoding.readString(source);
+ final String value = CharEncoding.readString(source);
+ options.put(key, value);
+ }
+ }
+
+ /**
* Reads a random access file and returns the memory representation of the dictionary.
*
* This high-level method takes a binary file and reads its contents, populating a
@@ -1358,11 +1373,7 @@ public class BinaryDictInputOutput {
} else {
headerSize = (source.readUnsignedByte() << 24) + (source.readUnsignedByte() << 16)
+ (source.readUnsignedByte() << 8) + source.readUnsignedByte();
- while (source.getFilePointer() < headerSize) {
- final String key = CharEncoding.readString(source);
- final String value = CharEncoding.readString(source);
- options.put(key, value);
- }
+ populateOptionsFromFile(source, headerSize, options);
source.seek(headerSize);
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 3bdfe1f27..d05dc021a 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -35,7 +35,6 @@ import com.android.inputmethod.latin.StringUtils;
import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary;
import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary;
import com.android.inputmethod.latin.UserBinaryDictionary;
-import com.android.inputmethod.latin.WhitelistDictionary;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -67,8 +66,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService
Collections.synchronizedMap(new TreeMap<String, DictionaryPool>());
private Map<String, UserBinaryDictionary> mUserDictionaries =
Collections.synchronizedMap(new TreeMap<String, UserBinaryDictionary>());
- private Map<String, Dictionary> mWhitelistDictionaries =
- Collections.synchronizedMap(new TreeMap<String, Dictionary>());
private ContactsBinaryDictionary mContactsDictionary;
// The threshold for a candidate to be offered as a suggestion.
@@ -366,8 +363,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService
final Map<String, UserBinaryDictionary> oldUserDictionaries = mUserDictionaries;
mUserDictionaries =
Collections.synchronizedMap(new TreeMap<String, UserBinaryDictionary>());
- final Map<String, Dictionary> oldWhitelistDictionaries = mWhitelistDictionaries;
- mWhitelistDictionaries = Collections.synchronizedMap(new TreeMap<String, Dictionary>());
new Thread("spellchecker_close_dicts") {
@Override
public void run() {
@@ -377,9 +372,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService
for (Dictionary dict : oldUserDictionaries.values()) {
dict.close();
}
- for (Dictionary dict : oldWhitelistDictionaries.values()) {
- dict.close();
- }
synchronized (mUseContactsLock) {
if (null != mContactsDictionary) {
// The synchronously loaded contacts dictionary should have been in one
@@ -423,12 +415,6 @@ public class AndroidSpellCheckerService extends SpellCheckerService
mUserDictionaries.put(localeStr, userDictionary);
}
dictionaryCollection.addDictionary(userDictionary);
- Dictionary whitelistDictionary = mWhitelistDictionaries.get(localeStr);
- if (null == whitelistDictionary) {
- whitelistDictionary = new WhitelistDictionary(this, locale);
- mWhitelistDictionaries.put(localeStr, whitelistDictionary);
- }
- dictionaryCollection.addDictionary(whitelistDictionary);
synchronized (mUseContactsLock) {
if (mUseContactsDictionary) {
if (null == mContactsDictionary) {