Have Latin IME copy files from the dictionary pack.

Also some minor cleanup: remove unused methods, minor refactoring into methods.

Bug: 5095140
Change-Id: I035537b37a31adfc8db3b933fb0cefcf703d6c7c
This commit is contained in:
Jean Chalard 2011-08-08 20:18:41 +09:00
parent 741c683d5e
commit 3a22708e65

View file

@ -23,7 +23,6 @@ import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -53,38 +52,55 @@ public class BinaryDictionaryFileDumper {
} }
/** /**
* Generates a file name that matches the locale passed as an argument. * Escapes a string for any characters that may be suspicious for a file or directory name.
* 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 * Concretely this does a sort of URL-encoding except it will encode everything that's not
* be created. * 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(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();
for (int i = 0; i < name.length(); ++i) {
final int codePoint = name.codePointAt(i);
if (Character.isLetterOrDigit(codePoint) || '_' == codePoint) {
sb.appendCodePoint(codePoint);
} else {
sb.append('%');
sb.append(Integer.toHexString(codePoint));
}
}
return sb.toString();
}
/**
* Find out the cache directory associated with a specific locale.
*/
private static String getCacheDirectoryForLocale(Locale locale, Context context) {
final String directoryName = replaceFileNameDangerousCharacters(locale.toString());
return context.getFilesDir() + File.separator + directoryName;
}
/**
* 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 * @param locale the locale for which to get the file name
* @param context the context to use for getting the directory * @param context the context to use for getting the directory
* @return the name of the file to be created * @return the name of the file to be created
*/ */
private static String getCacheFileNameForLocale(Locale locale, Context context) { private static String getCacheFileName(String id, Locale locale, Context context) {
// The following assumes two things : final String fileName = replaceFileNameDangerousCharacters(id);
// 1. That File.separator is not the same character as "_" return getCacheDirectoryForLocale(locale, context) + File.separator + fileName;
// 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;
}
/**
* Return for a given locale the provider URI to query to get the dictionary.
*/
// TODO: remove this
public static Uri getProviderUri(Locale locale) {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(BinaryDictionary.DICTIONARY_PACK_AUTHORITY).appendPath(
locale.toString()).build();
} }
/** /**
@ -102,7 +118,7 @@ public class BinaryDictionaryFileDumper {
*/ */
private static List<String> getDictIdList(final Locale locale, final Context context) { private static List<String> getDictIdList(final Locale locale, final Context context) {
final ContentResolver resolver = context.getContentResolver(); final ContentResolver resolver = context.getContentResolver();
final Uri dictionaryPackUri = getProviderUri(locale); final Uri dictionaryPackUri = getProviderUri(locale.toString());
final Cursor c = resolver.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null, null); final Cursor c = resolver.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null, null);
if (null == c) return Collections.<String>emptyList(); if (null == c) return Collections.<String>emptyList();
@ -137,10 +153,6 @@ public class BinaryDictionaryFileDumper {
*/ */
public static List<AssetFileAddress> getDictSetFromContentProvider(final Locale locale, public static List<AssetFileAddress> getDictSetFromContentProvider(final Locale locale,
final Context context) throws FileNotFoundException, IOException { final 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.
final ContentResolver resolver = context.getContentResolver(); final ContentResolver resolver = context.getContentResolver();
final List<String> idList = getDictIdList(locale, context); final List<String> idList = getDictIdList(locale, context);
final List<AssetFileAddress> fileAddressList = new ArrayList<AssetFileAddress>(); final List<AssetFileAddress> fileAddressList = new ArrayList<AssetFileAddress>();
@ -149,26 +161,14 @@ public class BinaryDictionaryFileDumper {
final AssetFileDescriptor afd = final AssetFileDescriptor afd =
resolver.openAssetFileDescriptor(dictionaryPackUri, "r"); resolver.openAssetFileDescriptor(dictionaryPackUri, "r");
if (null == afd) continue; if (null == afd) continue;
final String fileName = final String fileName = copyFileTo(afd.createInputStream(),
copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context)); getCacheFileName(id, locale, context));
afd.close(); afd.close();
fileAddressList.add(AssetFileAddress.makeFromFileName(fileName)); fileAddressList.add(AssetFileAddress.makeFromFileName(fileName));
} }
return fileAddressList; return fileAddressList;
} }
/**
* 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));
}
/** /**
* Accepts a resource number as dictionary data for some locale and returns the name of a file. * Accepts a resource number as dictionary data for some locale and returns the name of a file.
* *
@ -181,7 +181,7 @@ public class BinaryDictionaryFileDumper {
final Locale savedLocale = Utils.setSystemLocale(res, locale); final Locale savedLocale = Utils.setSystemLocale(res, locale);
final InputStream stream = res.openRawResource(resource); final InputStream stream = res.openRawResource(resource);
Utils.setSystemLocale(res, savedLocale); Utils.setSystemLocale(res, savedLocale);
return copyFileTo(stream, getCacheFileNameForLocale(locale, context)); return copyFileTo(stream, getCacheFileName(Integer.toString(resource), locale, context));
} }
/** /**