aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java1
-rw-r--r--java/src/com/android/inputmethod/latin/AssetFileAddress.java9
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java2
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java169
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java51
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java245
-rw-r--r--java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java20
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp6
-rw-r--r--native/jni/src/binary_format.h2
-rw-r--r--native/jni/src/correction.cpp8
-rw-r--r--native/jni/src/correction.h6
-rw-r--r--native/jni/src/proximity_info_state.cpp2
-rw-r--r--native/jni/src/proximity_info_state.h4
-rw-r--r--native/jni/src/proximity_info_state_utils.cpp2
-rw-r--r--native/jni/src/suggest_utils.h1
-rw-r--r--native/jni/src/words_priority_queue.h8
-rw-r--r--native/jni/src/words_priority_queue_pool.h6
17 files changed, 294 insertions, 248 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index f28bc9471..fd9edec70 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -32,7 +32,6 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
-import android.view.ViewDebug.HierarchyTraceType;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
diff --git a/java/src/com/android/inputmethod/latin/AssetFileAddress.java b/java/src/com/android/inputmethod/latin/AssetFileAddress.java
index 16296f0e2..47c750f54 100644
--- a/java/src/com/android/inputmethod/latin/AssetFileAddress.java
+++ b/java/src/com/android/inputmethod/latin/AssetFileAddress.java
@@ -35,11 +35,14 @@ final class AssetFileAddress {
mLength = length;
}
+ public static AssetFileAddress makeFromFile(final File file) {
+ if (!file.isFile()) return null;
+ return new AssetFileAddress(file.getAbsolutePath(), 0L, file.length());
+ }
+
public static AssetFileAddress makeFromFileName(final String filename) {
if (null == filename) return null;
- final File f = new File(filename);
- if (!f.isFile()) return null;
- return new AssetFileAddress(filename, 0l, f.length());
+ return makeFromFile(new File(filename));
}
public static AssetFileAddress makeFromFileNameAndOffset(final String filename,
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index d0bd01f6b..443ffa2e9 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -149,7 +149,7 @@ public final class BinaryDictionaryFileDumper {
final int MODE_MAX = NONE;
final Uri.Builder wordListUriBuilder = getProviderUriBuilder(id);
- final String finalFileName = BinaryDictionaryGetter.getCacheFileName(id, locale, context);
+ final String finalFileName = DictionaryInfoUtils.getCacheFileName(id, locale, context);
String tempFileName;
try {
tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 22b5cd55c..5da0f1be8 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -66,109 +66,11 @@ final class BinaryDictionaryGetter {
private BinaryDictionaryGetter() {}
/**
- * Returns whether we may want to use this character as part of a file name.
- *
- * This basically only accepts ascii letters and numbers, and rejects everything else.
- */
- private static boolean isFileNameCharacter(int codePoint) {
- if (codePoint >= 0x30 && codePoint <= 0x39) return true; // Digit
- if (codePoint >= 0x41 && codePoint <= 0x5A) return true; // Uppercase
- if (codePoint >= 0x61 && codePoint <= 0x7A) return true; // Lowercase
- return codePoint == '_'; // Underscore
- }
-
- /**
- * Escapes a string for any characters that may be suspicious for a file or directory name.
- *
- * Concretely this does a sort of URL-encoding except it will encode everything that's not
- * alphanumeric or underscore. (true URL-encoding leaves alone characters like '*', which
- * we cannot allow here)
- */
- // TODO: create a unit test for this method
- private static String replaceFileNameDangerousCharacters(final String name) {
- // This assumes '%' is fully available as a non-separator, normal
- // character in a file name. This is probably true for all file systems.
- final StringBuilder sb = new StringBuilder();
- final int nameLength = name.length();
- for (int i = 0; i < nameLength; i = name.offsetByCodePoints(i, 1)) {
- final int codePoint = name.codePointAt(i);
- if (isFileNameCharacter(codePoint)) {
- sb.appendCodePoint(codePoint);
- } else {
- // 6 digits - unicode is limited to 21 bits
- sb.append(String.format((Locale)null, "%%%1$06x", codePoint));
- }
- }
- return sb.toString();
- }
-
- /**
- * Reverse escaping done by replaceFileNameDangerousCharacters.
- */
- private static String getWordListIdFromFileName(final String fname) {
- final StringBuilder sb = new StringBuilder();
- final int fnameLength = fname.length();
- for (int i = 0; i < fnameLength; i = fname.offsetByCodePoints(i, 1)) {
- final int codePoint = fname.codePointAt(i);
- if ('%' != codePoint) {
- sb.appendCodePoint(codePoint);
- } else {
- final int encodedCodePoint = Integer.parseInt(fname.substring(i + 1, i + 7), 16);
- i += 6;
- sb.appendCodePoint(encodedCodePoint);
- }
- }
- return sb.toString();
- }
-
- /**
- * Helper method to get the top level cache directory.
- */
- private static String getWordListCacheDirectory(final Context context) {
- return context.getFilesDir() + File.separator + "dicts";
- }
-
- /**
- * Find out the cache directory associated with a specific locale.
- */
- private static String getCacheDirectoryForLocale(final String locale, final Context context) {
- final String relativeDirectoryName = replaceFileNameDangerousCharacters(locale);
- final String absoluteDirectoryName = getWordListCacheDirectory(context) + File.separator
- + relativeDirectoryName;
- final File directory = new File(absoluteDirectoryName);
- if (!directory.exists()) {
- if (!directory.mkdirs()) {
- Log.e(TAG, "Could not create the directory for locale" + locale);
- }
- }
- return absoluteDirectoryName;
- }
-
- /**
- * Generates a file name for the id and locale passed as an argument.
- *
- * In the current implementation the file name returned will always be unique for
- * any id/locale pair, but please do not expect that the id can be the same for
- * different dictionaries with different locales. An id should be unique for any
- * dictionary.
- * The file name is pretty much an URL-encoded version of the id inside a directory
- * named like the locale, except it will also escape characters that look dangerous
- * to some file systems.
- * @param id the id of the dictionary for which to get a file name
- * @param locale the locale for which to get the file name as a string
- * @param context the context to use for getting the directory
- * @return the name of the file to be created
- */
- public static String getCacheFileName(String id, String locale, Context context) {
- final String fileName = replaceFileNameDangerousCharacters(id);
- return getCacheDirectoryForLocale(locale, context) + File.separator + fileName;
- }
-
- /**
* Generates a unique temporary file name in the app cache directory.
*/
public static String getTempFileName(String id, Context context) throws IOException {
- return File.createTempFile(replaceFileNameDangerousCharacters(id), null).getAbsolutePath();
+ return File.createTempFile(DictionaryInfoUtils.replaceFileNameDangerousCharacters(id),
+ null).getAbsolutePath();
}
/**
@@ -222,27 +124,6 @@ final class BinaryDictionaryGetter {
}
/**
- * Helper method to the list of cache directories, one for each distinct locale.
- */
- private static File[] getCachedDirectoryList(final Context context) {
- return new File(getWordListCacheDirectory(context)).listFiles();
- }
-
- /**
- * Returns the category for a given file name.
- *
- * This parses the file name, extracts the category, and returns it. See
- * {@link #getMainDictId(Locale)} and {@link #isMainWordListId(String)}.
- * @return The category as a string or null if it can't be found in the file name.
- */
- private static String getCategoryFromFileName(final String fileName) {
- final String id = getWordListIdFromFileName(fileName);
- final String[] idArray = id.split(ID_CATEGORY_SEPARATOR);
- if (2 != idArray.length) return null;
- return idArray[0];
- }
-
- /**
* Utility class for the {@link #getCachedWordLists} method
*/
private static final class FileAndMatchLevel {
@@ -268,20 +149,21 @@ final class BinaryDictionaryGetter {
* @param context the context on which to open the files upon.
* @return an array of binary dictionary files, which may be empty but may not be null.
*/
- private static File[] getCachedWordLists(final String locale,
- final Context context) {
- final File[] directoryList = getCachedDirectoryList(context);
+ private static File[] getCachedWordLists(final String locale, final Context context) {
+ final File[] directoryList = DictionaryInfoUtils.getCachedDirectoryList(context);
if (null == directoryList) return EMPTY_FILE_ARRAY;
final HashMap<String, FileAndMatchLevel> cacheFiles = CollectionUtils.newHashMap();
for (File directory : directoryList) {
if (!directory.isDirectory()) continue;
- final String dirLocale = getWordListIdFromFileName(directory.getName());
+ final String dirLocale =
+ DictionaryInfoUtils.getWordListIdFromFileName(directory.getName());
final int matchLevel = LocaleUtils.getMatchLevel(dirLocale, locale);
if (LocaleUtils.isMatch(matchLevel)) {
final File[] wordLists = directory.listFiles();
if (null != wordLists) {
for (File wordList : wordLists) {
- final String category = getCategoryFromFileName(wordList.getName());
+ final String category =
+ DictionaryInfoUtils.getCategoryFromFileName(wordList.getName());
final FileAndMatchLevel currentBestMatch = cacheFiles.get(category);
if (null == currentBestMatch || currentBestMatch.mMatchLevel < matchLevel) {
cacheFiles.put(category, new FileAndMatchLevel(wordList, matchLevel));
@@ -310,7 +192,7 @@ final class BinaryDictionaryGetter {
final File fileToKeep) {
try {
final File canonicalFileToKeep = fileToKeep.getCanonicalFile();
- final File[] directoryList = getCachedDirectoryList(context);
+ final File[] directoryList = DictionaryInfoUtils.getCachedDirectoryList(context);
if (null == directoryList) return;
for (File directory : directoryList) {
// There is one directory per locale. See #getCachedDirectoryList
@@ -318,7 +200,8 @@ final class BinaryDictionaryGetter {
final File[] wordLists = directory.listFiles();
if (null == wordLists) continue;
for (File wordList : wordLists) {
- final String fileId = getWordListIdFromFileName(wordList.getName());
+ final String fileId =
+ DictionaryInfoUtils.getWordListIdFromFileName(wordList.getName());
if (fileId.equals(id)) {
if (!canonicalFileToKeep.equals(wordList.getCanonicalFile())) {
wordList.delete();
@@ -331,28 +214,6 @@ final class BinaryDictionaryGetter {
}
}
-
- /**
- * Returns the id associated with the main word list for a specified locale.
- *
- * Word lists stored in Android Keyboard's resources are referred to as the "main"
- * word lists. Since they can be updated like any other list, we need to assign a
- * unique ID to them. This ID is just the name of the language (locale-wise) they
- * are for, and this method returns this ID.
- */
- private static String getMainDictId(final Locale locale) {
- // This works because we don't include by default different dictionaries for
- // different countries. This actually needs to return the id that we would
- // like to use for word lists included in resources, and the following is okay.
- return MAIN_DICTIONARY_CATEGORY + ID_CATEGORY_SEPARATOR + locale.getLanguage().toString();
- }
-
- private static boolean isMainWordListId(final String id) {
- final String[] idArray = id.split(ID_CATEGORY_SEPARATOR);
- if (2 != idArray.length) return false;
- 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.
@@ -429,16 +290,16 @@ final class BinaryDictionaryGetter {
hasDefaultWordList);
}
final File[] cachedWordLists = getCachedWordLists(locale.toString(), context);
- final String mainDictId = getMainDictId(locale);
+ final String mainDictId = DictionaryInfoUtils.getMainDictId(locale);
final DictPackSettings dictPackSettings = new DictPackSettings(context);
boolean foundMainDict = false;
final ArrayList<AssetFileAddress> fileList = CollectionUtils.newArrayList();
// cachedWordLists may not be null, see doc for getCachedDictionaryList
for (final File f : cachedWordLists) {
- final String wordListId = getWordListIdFromFileName(f.getName());
+ final String wordListId = DictionaryInfoUtils.getWordListIdFromFileName(f.getName());
final boolean canUse = f.canRead() && hackCanUseDictionaryFile(locale, f);
- if (canUse && isMainWordListId(wordListId)) {
+ if (canUse && DictionaryInfoUtils.isMainWordListId(wordListId)) {
foundMainDict = true;
}
if (!dictPackSettings.isWordListActive(wordListId)) continue;
@@ -451,7 +312,7 @@ final class BinaryDictionaryGetter {
if (!foundMainDict && dictPackSettings.isWordListActive(mainDictId)) {
final int fallbackResId =
- DictionaryFactory.getMainDictionaryResourceId(context.getResources(), locale);
+ DictionaryInfoUtils.getMainDictionaryResourceId(context.getResources(), locale);
final AssetFileAddress fallbackAsset = loadFallbackResource(context, fallbackResId);
if (null != fallbackAsset) {
fileList.add(fallbackAsset);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 388ad6c59..40e51672a 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -31,9 +31,6 @@ import java.util.Locale;
*/
public final class DictionaryFactory {
private static final String TAG = DictionaryFactory.class.getSimpleName();
- // This class must be located in the same package as LatinIME.java.
- private static final String RESOURCE_PACKAGE_NAME =
- DictionaryFactory.class.getPackage().getName();
/**
* Initializes a main dictionary collection from a dictionary pack, with explicit flags.
@@ -96,8 +93,8 @@ public final class DictionaryFactory {
final Locale locale) {
AssetFileDescriptor afd = null;
try {
- final int resId =
- getMainDictionaryResourceIdIfAvailableForLocale(context.getResources(), locale);
+ final int resId = DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
+ context.getResources(), locale);
if (0 == resId) return null;
afd = context.getResources().openRawResourceFd(resId);
if (afd == null) {
@@ -154,47 +151,7 @@ public final class DictionaryFactory {
*/
public static boolean isDictionaryAvailable(Context context, Locale locale) {
final Resources res = context.getResources();
- return 0 != getMainDictionaryResourceIdIfAvailableForLocale(res, locale);
- }
-
- private static final String DEFAULT_MAIN_DICT = "main";
- private static final String MAIN_DICT_PREFIX = "main_";
-
- /**
- * Helper method to return a dictionary res id for a locale, or 0 if none.
- * @param locale dictionary locale
- * @return main dictionary resource id
- */
- private static int getMainDictionaryResourceIdIfAvailableForLocale(final Resources res,
- final Locale locale) {
- int resId;
- // Try to find main_language_country dictionary.
- if (!locale.getCountry().isEmpty()) {
- final String dictLanguageCountry = MAIN_DICT_PREFIX + locale.toString().toLowerCase();
- if ((resId = res.getIdentifier(
- dictLanguageCountry, "raw", RESOURCE_PACKAGE_NAME)) != 0) {
- return resId;
- }
- }
-
- // Try to find main_language dictionary.
- final String dictLanguage = MAIN_DICT_PREFIX + locale.getLanguage();
- if ((resId = res.getIdentifier(dictLanguage, "raw", RESOURCE_PACKAGE_NAME)) != 0) {
- return resId;
- }
-
- // Not found, return 0
- return 0;
- }
-
- /**
- * Returns a main dictionary resource id
- * @param locale dictionary locale
- * @return main dictionary resource id
- */
- public static int getMainDictionaryResourceId(final Resources res, final Locale locale) {
- int resourceId = getMainDictionaryResourceIdIfAvailableForLocale(res, locale);
- if (0 != resourceId) return resourceId;
- return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", RESOURCE_PACKAGE_NAME);
+ return 0 != DictionaryInfoUtils.getMainDictionaryResourceIdIfAvailableForLocale(
+ res, locale);
}
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
new file mode 100644
index 000000000..c676bf1b9
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2013 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.util.Log;
+
+import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
+import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+/**
+ * This class encapsulates the logic for the Latin-IME side of dictionary information management.
+ */
+public class DictionaryInfoUtils {
+ private static final String TAG = DictionaryInfoUtils.class.getSimpleName();
+ // This class must be located in the same package as LatinIME.java.
+ private static final String RESOURCE_PACKAGE_NAME =
+ DictionaryInfoUtils.class.getPackage().getName();
+ private static final String DEFAULT_MAIN_DICT = "main";
+ private static final String MAIN_DICT_PREFIX = "main_";
+ // 6 digits - unicode is limited to 21 bits
+ private static final int MAX_HEX_DIGITS_FOR_CODEPOINT = 6;
+
+ private DictionaryInfoUtils() {
+ // Private constructor to forbid instantation of this helper class.
+ }
+
+ /**
+ * Returns whether we may want to use this character as part of a file name.
+ *
+ * This basically only accepts ascii letters and numbers, and rejects everything else.
+ */
+ private static boolean isFileNameCharacter(int codePoint) {
+ if (codePoint >= 0x30 && codePoint <= 0x39) return true; // Digit
+ if (codePoint >= 0x41 && codePoint <= 0x5A) return true; // Uppercase
+ if (codePoint >= 0x61 && codePoint <= 0x7A) return true; // Lowercase
+ return codePoint == '_'; // Underscore
+ }
+
+ /**
+ * Escapes a string for any characters that may be suspicious for a file or directory name.
+ *
+ * Concretely this does a sort of URL-encoding except it will encode everything that's not
+ * alphanumeric or underscore. (true URL-encoding leaves alone characters like '*', which
+ * we cannot allow here)
+ */
+ // TODO: create a unit test for this method
+ public static String replaceFileNameDangerousCharacters(final String name) {
+ // This assumes '%' is fully available as a non-separator, normal
+ // character in a file name. This is probably true for all file systems.
+ final StringBuilder sb = new StringBuilder();
+ final int nameLength = name.length();
+ for (int i = 0; i < nameLength; i = name.offsetByCodePoints(i, 1)) {
+ final int codePoint = name.codePointAt(i);
+ if (DictionaryInfoUtils.isFileNameCharacter(codePoint)) {
+ sb.appendCodePoint(codePoint);
+ } else {
+ sb.append(String.format((Locale)null, "%%%1$0" + MAX_HEX_DIGITS_FOR_CODEPOINT + "x",
+ codePoint));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to get the top level cache directory.
+ */
+ private static String getWordListCacheDirectory(final Context context) {
+ return context.getFilesDir() + File.separator + "dicts";
+ }
+
+ /**
+ * Reverse escaping done by replaceFileNameDangerousCharacters.
+ */
+ public static String getWordListIdFromFileName(final String fname) {
+ final StringBuilder sb = new StringBuilder();
+ final int fnameLength = fname.length();
+ for (int i = 0; i < fnameLength; i = fname.offsetByCodePoints(i, 1)) {
+ final int codePoint = fname.codePointAt(i);
+ if ('%' != codePoint) {
+ sb.appendCodePoint(codePoint);
+ } else {
+ // + 1 to pass the % sign
+ final int encodedCodePoint = Integer.parseInt(
+ fname.substring(i + 1, i + 1 + MAX_HEX_DIGITS_FOR_CODEPOINT), 16);
+ i += MAX_HEX_DIGITS_FOR_CODEPOINT;
+ sb.appendCodePoint(encodedCodePoint);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Helper method to the list of cache directories, one for each distinct locale.
+ */
+ public static File[] getCachedDirectoryList(final Context context) {
+ return new File(DictionaryInfoUtils.getWordListCacheDirectory(context)).listFiles();
+ }
+
+ /**
+ * Returns the category for a given file name.
+ *
+ * This parses the file name, extracts the category, and returns it. See
+ * {@link #getMainDictId(Locale)} and {@link #isMainWordListId(String)}.
+ * @return The category as a string or null if it can't be found in the file name.
+ */
+ public static String getCategoryFromFileName(final String fileName) {
+ final String id = getWordListIdFromFileName(fileName);
+ final String[] idArray = id.split(BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR);
+ // An id is supposed to be in format category:locale, so splitting on the separator
+ // should yield a 2-elements array
+ if (2 != idArray.length) return null;
+ return idArray[0];
+ }
+
+ /**
+ * Find out the cache directory associated with a specific locale.
+ */
+ private static String getCacheDirectoryForLocale(final String locale, final Context context) {
+ final String relativeDirectoryName = replaceFileNameDangerousCharacters(locale);
+ final String absoluteDirectoryName = getWordListCacheDirectory(context) + File.separator
+ + relativeDirectoryName;
+ final File directory = new File(absoluteDirectoryName);
+ if (!directory.exists()) {
+ if (!directory.mkdirs()) {
+ Log.e(TAG, "Could not create the directory for locale" + locale);
+ }
+ }
+ return absoluteDirectoryName;
+ }
+
+ /**
+ * Generates a file name for the id and locale passed as an argument.
+ *
+ * In the current implementation the file name returned will always be unique for
+ * any id/locale pair, but please do not expect that the id can be the same for
+ * different dictionaries with different locales. An id should be unique for any
+ * dictionary.
+ * The file name is pretty much an URL-encoded version of the id inside a directory
+ * named like the locale, except it will also escape characters that look dangerous
+ * to some file systems.
+ * @param id the id of the dictionary for which to get a file name
+ * @param locale the locale for which to get the file name as a string
+ * @param context the context to use for getting the directory
+ * @return the name of the file to be created
+ */
+ public static String getCacheFileName(String id, String locale, Context context) {
+ final String fileName = replaceFileNameDangerousCharacters(id);
+ return getCacheDirectoryForLocale(locale, context) + File.separator + fileName;
+ }
+
+ public static boolean isMainWordListId(final String id) {
+ final String[] idArray = id.split(BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR);
+ // An id is supposed to be in format category:locale, so splitting on the separator
+ // should yield a 2-elements array
+ if (2 != idArray.length) return false;
+ return BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY.equals(idArray[0]);
+ }
+
+ /**
+ * Helper method to return a dictionary res id for a locale, or 0 if none.
+ * @param locale dictionary locale
+ * @return main dictionary resource id
+ */
+ public static int getMainDictionaryResourceIdIfAvailableForLocale(final Resources res,
+ final Locale locale) {
+ int resId;
+ // Try to find main_language_country dictionary.
+ if (!locale.getCountry().isEmpty()) {
+ final String dictLanguageCountry =
+ MAIN_DICT_PREFIX + locale.toString().toLowerCase(Locale.ROOT);
+ if ((resId = res.getIdentifier(
+ dictLanguageCountry, "raw", RESOURCE_PACKAGE_NAME)) != 0) {
+ return resId;
+ }
+ }
+
+ // Try to find main_language dictionary.
+ final String dictLanguage = MAIN_DICT_PREFIX + locale.getLanguage();
+ if ((resId = res.getIdentifier(dictLanguage, "raw", RESOURCE_PACKAGE_NAME)) != 0) {
+ return resId;
+ }
+
+ // Not found, return 0
+ return 0;
+ }
+
+ /**
+ * Returns a main dictionary resource id
+ * @param locale dictionary locale
+ * @return main dictionary resource id
+ */
+ public static int getMainDictionaryResourceId(final Resources res, final Locale locale) {
+ int resourceId = getMainDictionaryResourceIdIfAvailableForLocale(res, locale);
+ if (0 != resourceId) return resourceId;
+ return res.getIdentifier(DEFAULT_MAIN_DICT, "raw", RESOURCE_PACKAGE_NAME);
+ }
+
+ /**
+ * Returns the id associated with the main word list for a specified locale.
+ *
+ * Word lists stored in Android Keyboard's resources are referred to as the "main"
+ * word lists. Since they can be updated like any other list, we need to assign a
+ * unique ID to them. This ID is just the name of the language (locale-wise) they
+ * are for, and this method returns this ID.
+ */
+ public static String getMainDictId(final Locale locale) {
+ // This works because we don't include by default different dictionaries for
+ // different countries. This actually needs to return the id that we would
+ // like to use for word lists included in resources, and the following is okay.
+ return BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY +
+ BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale.getLanguage().toString();
+ }
+
+ public static FileHeader getDictionaryFileHeaderOrNull(final File file) {
+ try {
+ final FileHeader header = BinaryDictIOUtils.getDictionaryFileHeader(file);
+ return header;
+ } catch (UnsupportedFormatException e) {
+ return null;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
index 6e5a37c72..d9e4bb63d 100644
--- a/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
+++ b/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
@@ -21,11 +21,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Environment;
-import android.util.Log;
-import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
-import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -44,22 +41,11 @@ public class ExternalDictionaryGetterForDebug {
+ "/Download";
private static final String DICTIONARY_LOCALE_ATTRIBUTE = "locale";
- private static FileHeader getDictionaryFileHeaderOrNull(final File file) {
- try {
- final FileHeader header = BinaryDictIOUtils.getDictionaryFileHeader(file);
- return header;
- } catch (UnsupportedFormatException e) {
- return null;
- } catch (IOException e) {
- return null;
- }
- }
-
private static String[] findDictionariesInTheDownloadedFolder() {
final File[] files = new File(SOURCE_FOLDER).listFiles();
final ArrayList<String> eligibleList = CollectionUtils.newArrayList();
for (File f : files) {
- final FileHeader header = getDictionaryFileHeaderOrNull(f);
+ final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(f);
if (null == header) continue;
eligibleList.add(f.getName());
}
@@ -102,7 +88,7 @@ public class ExternalDictionaryGetterForDebug {
private static void askInstallFile(final Context context, final String fileName) {
final File file = new File(SOURCE_FOLDER, fileName.toString());
- final FileHeader header = getDictionaryFileHeaderOrNull(file);
+ final FileHeader header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file);
final StringBuilder message = new StringBuilder();
final String locale =
header.mDictionaryOptions.mAttributes.get(DICTIONARY_LOCALE_ATTRIBUTE);
@@ -143,7 +129,7 @@ public class ExternalDictionaryGetterForDebug {
final String id = BinaryDictionaryGetter.MAIN_DICTIONARY_CATEGORY
+ BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale;
final String finalFileName =
- BinaryDictionaryGetter.getCacheFileName(id, locale, context);
+ DictionaryInfoUtils.getCacheFileName(id, locale, context);
final String tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
tempFile = new File(tempFileName);
tempFile.delete();
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 5c8ef7e51..ca38b0de5 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -87,7 +87,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s
AKLOGE("DICT: Can't allocate memory region for dictionary. errno=%d", errno);
return 0;
}
- int ret = fseek(file, (long)dictOffset, SEEK_SET);
+ int ret = fseek(file, static_cast<long>(dictOffset), SEEK_SET);
if (ret != 0) {
AKLOGE("DICT: Failure in fseek. ret=%d errno=%d", ret, errno);
return 0;
@@ -121,7 +121,7 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s
}
PROF_END(66);
PROF_CLOSE;
- return (jlong)dictionary;
+ return reinterpret_cast<jlong>(dictionary);
}
static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, jlong dict,
@@ -216,7 +216,7 @@ static jint latinime_BinaryDictionary_getFrequency(JNIEnv *env, jclass clazz, jl
static jboolean latinime_BinaryDictionary_isValidBigram(JNIEnv *env, jclass clazz, jlong dict,
jintArray wordArray1, jintArray wordArray2) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
- if (!dictionary) return (jboolean) false;
+ if (!dictionary) return JNI_FALSE;
const jsize codePointLength1 = env->GetArrayLength(wordArray1);
const jsize codePointLength2 = env->GetArrayLength(wordArray2);
int codePoints1[codePointLength1];
diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h
index 61780dea5..f19d5e3ea 100644
--- a/native/jni/src/binary_format.h
+++ b/native/jni/src/binary_format.h
@@ -314,7 +314,7 @@ static inline int childrenAddressSize(const uint8_t flags) {
}
static AK_FORCE_INLINE int shortcutByteSize(const uint8_t *const dict, const int pos) {
- return ((int)(dict[pos] << 8)) + (dict[pos + 1]);
+ return (static_cast<int>(dict[pos] << 8)) + (dict[pos + 1]);
}
inline int BinaryFormat::skipChildrenPosition(const uint8_t flags, const int pos) {
diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp
index e892c8591..d4bd4aa00 100644
--- a/native/jni/src/correction.cpp
+++ b/native/jni/src/correction.cpp
@@ -112,7 +112,7 @@ void Correction::setCorrectionParams(const int skipPos, const int excessivePos,
mMaxErrors = maxErrors;
}
-void Correction::checkState() {
+void Correction::checkState() const {
if (DEBUG_DICT) {
int inputCount = 0;
if (mSkipPos >= 0) ++inputCount;
@@ -121,12 +121,12 @@ void Correction::checkState() {
}
}
-bool Correction::sameAsTyped() {
+bool Correction::sameAsTyped() const {
return mProximityInfoState.sameAsTyped(mWord, mOutputIndex);
}
int Correction::getFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray,
- const int wordCount, const bool isSpaceProximity, const int *word) {
+ const int wordCount, const bool isSpaceProximity, const int *word) const {
return Correction::RankingAlgorithm::calcFreqForSplitMultipleWords(freqArray, wordLengthArray,
wordCount, this, isSpaceProximity, word);
}
@@ -677,7 +677,7 @@ inline static bool isUpperCase(unsigned short c) {
const float factor =
SuggestUtils::getDistanceScalingFactor(static_cast<float>(squaredDistance));
if (factor > 0.0f) {
- multiplyRate((int)(factor * 100.0f), &finalFreq);
+ multiplyRate(static_cast<int>(factor * 100.0f), &finalFreq);
} else if (squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) {
multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq);
}
diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h
index 89e300d75..0873daef3 100644
--- a/native/jni/src/correction.h
+++ b/native/jni/src/correction.h
@@ -64,8 +64,8 @@ class Correction {
void setCorrectionParams(const int skipPos, const int excessivePos, const int transposedPos,
const int spaceProximityPos, const int missingSpacePos, const bool useFullEditDistance,
const bool doAutoCompletion, const int maxErrors);
- void checkState();
- bool sameAsTyped();
+ void checkState() const;
+ bool sameAsTyped() const;
bool initProcessState(const int index);
int getInputIndex() const;
@@ -77,7 +77,7 @@ class Correction {
}
int getFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray,
- const int wordCount, const bool isSpaceProximity, const int *word);
+ const int wordCount, const bool isSpaceProximity, const int *word) const;
int getFinalProbability(const int probability, int **word, int *wordLength);
int getFinalProbabilityForSubQueue(const int probability, int **word, int *wordLength,
const int inputSize);
diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index 387b03a24..141be2688 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -27,8 +27,6 @@
namespace latinime {
-const int ProximityInfoState::NOT_A_CODE = -1;
-
void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength,
const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize,
const int *const xCoordinates, const int *const yCoordinates, const int *const times,
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index 7422cb08f..ff1b35089 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -32,9 +32,6 @@ class ProximityInfo;
class ProximityInfoState {
public:
-
- static const int NOT_A_CODE;
-
/////////////////////////////////////////
// Defined in proximity_info_state.cpp //
/////////////////////////////////////////
@@ -196,6 +193,7 @@ class ProximityInfoState {
const int from, const int to, const int keyId, const bool extend) const;
bool isKeyInSerchKeysAfterIndex(const int index, const int keyId) const;
+
private:
DISALLOW_COPY_AND_ASSIGN(ProximityInfoState);
/////////////////////////////////////////
diff --git a/native/jni/src/proximity_info_state_utils.cpp b/native/jni/src/proximity_info_state_utils.cpp
index 9f85743e5..ac74a4e91 100644
--- a/native/jni/src/proximity_info_state_utils.cpp
+++ b/native/jni/src/proximity_info_state_utils.cpp
@@ -211,7 +211,7 @@ namespace latinime {
ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
if (squaredDistance >= 0.0f) {
normalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
- (int) (squaredDistance
+ static_cast<int>(squaredDistance
* ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
} else {
normalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
diff --git a/native/jni/src/suggest_utils.h b/native/jni/src/suggest_utils.h
index 7d49cde7e..aab9f7ba8 100644
--- a/native/jni/src/suggest_utils.h
+++ b/native/jni/src/suggest_utils.h
@@ -19,7 +19,6 @@
#include "defines.h"
#include "proximity_info_params.h"
-#include "proximity_info_state.h"
namespace latinime {
class SuggestUtils {
diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h
index 7aab1e083..8a22f051a 100644
--- a/native/jni/src/words_priority_queue.h
+++ b/native/jni/src/words_priority_queue.h
@@ -87,7 +87,7 @@ class WordsPriorityQueue {
}
}
- SuggestedWord *top() {
+ SuggestedWord *top() const {
if (mSuggestions.empty()) return 0;
SuggestedWord *sw = mSuggestions.top();
return sw;
@@ -110,7 +110,7 @@ class WordsPriorityQueue {
}
}
- AK_FORCE_INLINE void dumpTopWord() {
+ AK_FORCE_INLINE void dumpTopWord() const {
if (size() <= 0) {
return;
}
@@ -118,7 +118,7 @@ class WordsPriorityQueue {
}
AK_FORCE_INLINE float getHighestNormalizedScore(const int *before, const int beforeLength,
- int **outWord, int *outScore, int *outLength) {
+ int **outWord, int *outScore, int *outLength) const {
if (!mHighestSuggestedWord) {
return 0.0f;
}
@@ -137,7 +137,7 @@ class WordsPriorityQueue {
}
};
- SuggestedWord *getFreeSuggestedWord(int score, int *word, int wordLength, int type) {
+ SuggestedWord *getFreeSuggestedWord(int score, int *word, int wordLength, int type) const {
for (int i = 0; i < MAX_WORD_LENGTH; ++i) {
if (!mSuggestedWords[i].mUsed) {
mSuggestedWords[i].setParams(score, word, wordLength, type);
diff --git a/native/jni/src/words_priority_queue_pool.h b/native/jni/src/words_priority_queue_pool.h
index cfe7ede63..2cd210a05 100644
--- a/native/jni/src/words_priority_queue_pool.h
+++ b/native/jni/src/words_priority_queue_pool.h
@@ -44,11 +44,11 @@ class WordsPriorityQueuePool {
}
}
- WordsPriorityQueue *getMasterQueue() {
+ WordsPriorityQueue *getMasterQueue() const {
return mMasterQueue;
}
- WordsPriorityQueue *getSubQueue(const int wordIndex, const int inputWordLength) {
+ WordsPriorityQueue *getSubQueue(const int wordIndex, const int inputWordLength) const {
if (wordIndex >= MULTIPLE_WORDS_SUGGESTION_MAX_WORDS) {
return 0;
}
@@ -77,7 +77,7 @@ class WordsPriorityQueuePool {
}
}
- void dumpSubQueue1TopSuggestions() {
+ void dumpSubQueue1TopSuggestions() const {
AKLOGI("DUMP SUBQUEUE1 TOP SUGGESTIONS");
for (int i = 0; i < SUB_QUEUE_MAX_COUNT; ++i) {
getSubQueue(0, i)->dumpTopWord();