diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java | 122 |
1 files changed, 60 insertions, 62 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index 41b577cf3..3da670e2e 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -20,16 +20,18 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; +import android.database.Cursor; import android.net.Uri; import android.text.TextUtils; +import android.util.Log; -import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; @@ -38,89 +40,83 @@ import java.util.Locale; * file from the dictionary provider */ public class BinaryDictionaryFileDumper { + private static final String TAG = BinaryDictionaryFileDumper.class.getSimpleName(); + /** * The size of the temporary buffer to copy files. */ static final int FILE_READ_BUFFER_SIZE = 1024; + private static final String DICTIONARY_PROJECTION[] = { "id" }; + // Prevents this class to be accidentally instantiated. private BinaryDictionaryFileDumper() { } /** - * Generates a file name that matches the locale passed as an argument. - * The file name is basically the result of the .toString() method, except we replace - * any @File.separator with an underscore to avoid generating a file name that may not - * be created. - * @param locale the locale for which to get the file name - * @param context the context to use for getting the directory - * @return the name of the file to be created + * Return for a given locale or dictionary id the provider URI to get the dictionary. */ - private static String getCacheFileNameForLocale(Locale locale, Context context) { - // The following assumes two things : - // 1. That File.separator is not the same character as "_" - // I don't think any android system will ever use "_" as a path separator - // 2. That no two locales differ by only a File.separator versus a "_" - // Since "_" can't be part of locale components this should be safe. - // Examples: - // en -> en - // en_US_POSIX -> en_US_POSIX - // en__foo/bar -> en__foo_bar - final String[] separator = { File.separator }; - final String[] empty = { "_" }; - final CharSequence basename = TextUtils.replace(locale.toString(), separator, empty); - return context.getFilesDir() + File.separator + basename; + private static Uri getProviderUri(String path) { + return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) + .authority(BinaryDictionary.DICTIONARY_PACK_AUTHORITY).appendPath( + path).build(); } /** - * Return for a given locale the provider URI to query to get the dictionary. + * Queries a content provider for the list of dictionaries for a specific locale + * available to copy into Latin IME. */ - public static Uri getProviderUri(Locale locale) { - return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT) - .authority(BinaryDictionary.DICTIONARY_PACK_AUTHORITY).appendPath( - locale.toString()).build(); + private static List<String> getDictIdList(final Locale locale, final Context context) { + final ContentResolver resolver = context.getContentResolver(); + final Uri dictionaryPackUri = getProviderUri(locale.toString()); + + final Cursor c = resolver.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null, null); + if (null == c) return Collections.<String>emptyList(); + if (c.getCount() <= 0 || !c.moveToFirst()) { + c.close(); + return Collections.<String>emptyList(); + } + + final List<String> list = new ArrayList<String>(); + do { + final String id = c.getString(0); + if (TextUtils.isEmpty(id)) continue; + list.add(id); + } while (c.moveToNext()); + c.close(); + return list; } /** - * Queries a content provider for dictionary data for some locale and returns the file addresses + * Queries a content provider for dictionary data for some locale and cache the returned files * - * This will query a content provider for dictionary data for a given locale, and return - * the addresses of a file set the members of which are suitable to be mmap'ed. It will copy - * them to local storage if needed. - * It should also check the dictionary versions to avoid unnecessary copies but this is - * still in TODO state. - * This will make the data from the content provider the cached dictionary for this locale, - * overwriting any previous cached data. + * This will query a content provider for dictionary data for a given locale, and copy the + * files locally so that they can be mmap'ed. This may overwrite previously cached dictionaries + * with newer versions if a newer version is made available by the content provider. * @returns the addresses of the files, or null if no data could be obtained. * @throw FileNotFoundException if the provider returns non-existent data. * @throw IOException if the provider-returned data could not be read. */ - public static List<AssetFileAddress> getDictSetFromContentProvider(Locale locale, - Context context) throws FileNotFoundException, IOException { - // TODO: check whether the dictionary is the same or not and if it is, return the cached - // file. - // TODO: This should be able to read a number of files from the dictionary pack, copy - // them all and return them. + public static List<AssetFileAddress> cacheDictionariesFromContentProvider(final Locale locale, + final Context context) throws FileNotFoundException, IOException { final ContentResolver resolver = context.getContentResolver(); - final Uri dictionaryPackUri = getProviderUri(locale); - final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(dictionaryPackUri, "r"); - if (null == afd) return null; - final String fileName = - copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context)); - afd.close(); - return Arrays.asList(AssetFileAddress.makeFromFileName(fileName)); - } - - /** - * Accepts a file as dictionary data for some locale and returns the name of a file. - * - * This will make the data in the input file the cached dictionary for this locale, overwriting - * any previous cached data. - */ - public static String getDictionaryFileFromFile(String fileName, Locale locale, - Context context) throws FileNotFoundException, IOException { - return copyFileTo(new FileInputStream(fileName), getCacheFileNameForLocale(locale, - context)); + final List<String> idList = getDictIdList(locale, context); + final List<AssetFileAddress> fileAddressList = new ArrayList<AssetFileAddress>(); + for (String id : idList) { + final Uri wordListUri = getProviderUri(id); + final AssetFileDescriptor afd = + resolver.openAssetFileDescriptor(wordListUri, "r"); + if (null == afd) continue; + final String fileName = copyFileTo(afd.createInputStream(), + BinaryDictionaryGetter.getCacheFileName(id, locale, context)); + afd.close(); + if (0 >= resolver.delete(wordListUri, null, null)) { + // I'd rather not print the word list ID to the log here out of security concerns + Log.e(TAG, "Could not have the dictionary pack delete a word list"); + } + fileAddressList.add(AssetFileAddress.makeFromFileName(fileName)); + } + return fileAddressList; } /** @@ -135,7 +131,9 @@ public class BinaryDictionaryFileDumper { final Locale savedLocale = Utils.setSystemLocale(res, locale); final InputStream stream = res.openRawResource(resource); Utils.setSystemLocale(res, savedLocale); - return copyFileTo(stream, getCacheFileNameForLocale(locale, context)); + return copyFileTo(stream, + BinaryDictionaryGetter.getCacheFileName(Integer.toString(resource), + locale, context)); } /** |