Improve the architecture to support multiple dictionaries.

This change enables the interface to get multiple dictionaries from a
dictionary pack. It only implements it to the end in the case of the
proprietary method, as the open method needs still some working out,
and the "inside the package" method does not need it.

This change goes together with Iaa95bf36, and breaks the build
without it.

Bug: 1752028

Change-Id: I3ccfd696e8ef083ef9c074e1c3e4bb0bf2fcfd23
main
Jean Chalard 2011-04-27 23:13:11 +09:00
parent 3bf6fbb6b8
commit d8f52a4f18
5 changed files with 46 additions and 30 deletions

View File

@ -28,6 +28,8 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@ -79,27 +81,32 @@ public class BinaryDictionaryFileDumper {
} }
/** /**
* Queries a content provider for dictionary data for some locale and returns it as a file name. * Queries a content provider for dictionary data for some locale and returns the file addresses
* *
* This will query a content provider for dictionary data for a given locale, and return * This will query a content provider for dictionary data for a given locale, and return
* the name of a file suitable to be mmap'ed. It will copy it to local storage if needed. * the addresses of a file set the members of which are suitable to be mmap'ed. It will copy
* It should also check the dictionary version to avoid unnecessary copies but this is * them to local storage if needed.
* It should also check the dictionary versions to avoid unnecessary copies but this is
* still in TODO state. * still in TODO state.
* This will make the data from the content provider the cached dictionary for this locale, * This will make the data from the content provider the cached dictionary for this locale,
* overwriting any previous cached data. * overwriting any previous cached data.
* @returns the name of the file, or null if no data could be obtained. * @returns the addresses of the files, or null if no data could be obtained.
* @throw FileNotFoundException if the provider returns non-existent data. * @throw FileNotFoundException if the provider returns non-existent data.
* @throw IOException if the provider-returned data could not be read. * @throw IOException if the provider-returned data could not be read.
*/ */
public static String getDictionaryFileFromContentProvider(Locale locale, Context context) public static List<AssetFileAddress> getDictSetFromContentProvider(Locale locale,
throws FileNotFoundException, IOException { Context context) throws FileNotFoundException, IOException {
// TODO: check whether the dictionary is the same or not and if it is, return the cached // TODO: check whether the dictionary is the same or not and if it is, return the cached
// file. // 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 Uri dictionaryPackUri = getProviderUri(locale); final Uri dictionaryPackUri = getProviderUri(locale);
final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(dictionaryPackUri, "r"); final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(dictionaryPackUri, "r");
if (null == afd) return null; if (null == afd) return null;
return copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context)); final String fileName =
copyFileTo(afd.createInputStream(), getCacheFileNameForLocale(locale, context));
return Arrays.asList(AssetFileAddress.makeFromFileName(fileName));
} }
/** /**

View File

@ -22,6 +22,8 @@ import android.util.Log;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@ -52,13 +54,13 @@ class BinaryDictionaryGetter {
} }
/** /**
* Returns a file address for a given locale, trying relevant methods in order. * Returns a list of file addresses for a given locale, trying relevant methods in order.
* *
* Tries to get a binary dictionary from various sources, in order: * Tries to get binary dictionaries from various sources, in order:
* - Uses a private method of getting a private dictionary, as implemented by the * - Uses a private method of getting a private dictionaries, as implemented by the
* PrivateBinaryDictionaryGetter class. * PrivateBinaryDictionaryGetter class.
* If that fails: * If that fails:
* - Uses a content provider to get a public dictionary, as per the protocol described * - Uses a content provider to get a public dictionary set, as per the protocol described
* in BinaryDictionaryFileDumper. * in BinaryDictionaryFileDumper.
* If that fails: * If that fails:
* - Gets a file name from the fallback resource passed as an argument. * - Gets a file name from the fallback resource passed as an argument.
@ -66,27 +68,25 @@ class BinaryDictionaryGetter {
* - Returns null. * - Returns null.
* @return The address of a valid file, or null. * @return The address of a valid file, or null.
*/ */
public static AssetFileAddress getDictionaryFile(Locale locale, Context context, public static List<AssetFileAddress> getDictionaryFiles(Locale locale, Context context,
int fallbackResId) { int fallbackResId) {
// Try first to query a private file signed the same way. // Try first to query a private package signed the same way for private files.
final AssetFileAddress privateFile = final List<AssetFileAddress> privateFiles =
PrivateBinaryDictionaryGetter.getDictionaryFile(locale, context); PrivateBinaryDictionaryGetter.getDictionaryFiles(locale, context);
if (null != privateFile) { if (null != privateFiles) {
return privateFile; return privateFiles;
} else { } else {
try { try {
// If that was no-go, try to find a publicly exported dictionary. // If that was no-go, try to find a publicly exported dictionary.
final String fileName = BinaryDictionaryFileDumper. return BinaryDictionaryFileDumper.getDictSetFromContentProvider(locale, context);
getDictionaryFileFromContentProvider(locale, context);
return AssetFileAddress.makeFromFileName(fileName);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
Log.e(TAG, "Unable to create dictionary file from provider for locale " Log.e(TAG, "Unable to create dictionary file from provider for locale "
+ locale.toString() + ": falling back to internal dictionary"); + locale.toString() + ": falling back to internal dictionary");
return loadFallbackResource(context, fallbackResId); return Arrays.asList(loadFallbackResource(context, fallbackResId));
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Unable to read source data for locale " Log.e(TAG, "Unable to read source data for locale "
+ locale.toString() + ": falling back to internal dictionary"); + locale.toString() + ": falling back to internal dictionary");
return loadFallbackResource(context, fallbackResId); return Arrays.asList(loadFallbackResource(context, fallbackResId));
} }
} }
} }

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@ -34,6 +35,10 @@ public class DictionaryCollection extends Dictionary {
mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries); mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries);
} }
public DictionaryCollection(Collection<Dictionary> dictionaries) {
mDictionaries = new CopyOnWriteArrayList<Dictionary>(dictionaries);
}
@Override @Override
public void getWords(final WordComposer composer, final WordCallback callback) { public void getWords(final WordComposer composer, final WordCallback callback) {
for (final Dictionary dict : mDictionaries) for (final Dictionary dict : mDictionaries)

View File

@ -18,11 +18,12 @@ package com.android.inputmethod.latin;
import android.content.Context; import android.content.Context;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.util.Log; import android.util.Log;
import java.io.File; import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@ -50,11 +51,14 @@ public class DictionaryFactory {
return new DictionaryCollection(createBinaryDictionary(context, fallbackResId)); return new DictionaryCollection(createBinaryDictionary(context, fallbackResId));
} }
final AssetFileAddress dictFile = BinaryDictionaryGetter.getDictionaryFile(locale, final List<Dictionary> dictList = new LinkedList<Dictionary>();
context, fallbackResId); for (final AssetFileAddress f : BinaryDictionaryGetter.getDictionaryFiles(locale,
if (null == dictFile) return null; context, fallbackResId)) {
return new DictionaryCollection(new BinaryDictionary(context, dictList.add(new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, null));
dictFile.mFilename, dictFile.mOffset, dictFile.mLength, null)); }
if (null == dictList) return null;
return new DictionaryCollection(dictList);
} }
/** /**
@ -66,7 +70,6 @@ public class DictionaryFactory {
protected static BinaryDictionary createBinaryDictionary(Context context, int resId) { protected static BinaryDictionary createBinaryDictionary(Context context, int resId) {
AssetFileDescriptor afd = null; AssetFileDescriptor afd = null;
try { try {
// TODO: IMPORTANT: Do not create a dictionary from a placeholder.
afd = context.getResources().openRawResourceFd(resId); afd = context.getResources().openRawResourceFd(resId);
if (afd == null) { if (afd == null) {
Log.e(TAG, "Found the resource but it is compressed. resId=" + resId); Log.e(TAG, "Found the resource but it is compressed. resId=" + resId);

View File

@ -18,11 +18,12 @@ package com.android.inputmethod.latin;
import android.content.Context; import android.content.Context;
import java.util.List;
import java.util.Locale; import java.util.Locale;
class PrivateBinaryDictionaryGetter { class PrivateBinaryDictionaryGetter {
private PrivateBinaryDictionaryGetter() {} private PrivateBinaryDictionaryGetter() {}
public static AssetFileAddress getDictionaryFile(Locale locale, Context context) { public static List<AssetFileAddress> getDictionaryFiles(Locale locale, Context context) {
return null; return null;
} }
} }