aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java139
1 files changed, 99 insertions, 40 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index 165116ae0..0d0ce5756 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -74,6 +74,8 @@ public final class BinaryDictionaryFileDumper {
// The path fragment to append after the client ID for dictionary info requests.
private static final String QUERY_PATH_DICT_INFO = "dict";
+ // The path fragment to append after the client ID for dictionary datafile requests.
+ private static final String QUERY_PATH_DATAFILE = "datafile";
// The path fragment to append after the client ID for updating the metadata URI.
private static final String QUERY_PATH_METADATA = "metadata";
private static final String INSERT_METADATA_CLIENT_ID_COLUMN = "clientid";
@@ -96,37 +98,67 @@ public final class BinaryDictionaryFileDumper {
}
/**
+ * Gets the content URI builder for a specified type.
+ *
+ * Supported types include QUERY_PATH_DICT_INFO, which takes the locale as
+ * the extraPath argument, and QUERY_PATH_DATAFILE, which needs a wordlist ID
+ * as the extraPath argument.
+ *
+ * @param clientId the clientId to use
+ * @param contentProviderClient the instance of content provider client
+ * @param queryPathType the path element encoding the type
+ * @param extraPath optional extra argument for this type (typically word list id)
+ * @return a builder that can build the URI for the best supported protocol version
+ * @throws RemoteException if the client can't be contacted
+ */
+ private static Uri.Builder getContentUriBuilderForType(final String clientId,
+ final ContentProviderClient contentProviderClient, final String queryPathType,
+ final String extraPath) throws RemoteException {
+ // Check whether protocol v2 is supported by building a v2 URI and calling getType()
+ // on it. If this returns null, v2 is not supported.
+ final Uri.Builder uriV2Builder = getProviderUriBuilder(clientId);
+ uriV2Builder.appendPath(queryPathType);
+ uriV2Builder.appendPath(extraPath);
+ uriV2Builder.appendQueryParameter(QUERY_PARAMETER_PROTOCOL,
+ QUERY_PARAMETER_PROTOCOL_VALUE);
+ if (null != contentProviderClient.getType(uriV2Builder.build())) return uriV2Builder;
+ // Protocol v2 is not supported, so create and return the protocol v1 uri.
+ return getProviderUriBuilder(extraPath);
+ }
+
+ /**
* Queries a content provider for the list of word lists for a specific locale
* available to copy into Latin IME.
*/
private static List<WordListInfo> getWordListWordListInfos(final Locale locale,
final Context context, final boolean hasDefaultWordList) {
final String clientId = context.getString(R.string.dictionary_pack_client_id);
- final Uri.Builder builder = getProviderUriBuilder(clientId);
- builder.appendPath(QUERY_PATH_DICT_INFO);
- builder.appendPath(locale.toString());
- builder.appendQueryParameter(QUERY_PARAMETER_PROTOCOL, QUERY_PARAMETER_PROTOCOL_VALUE);
- if (!hasDefaultWordList) {
- builder.appendQueryParameter(QUERY_PARAMETER_MAY_PROMPT_USER,
- QUERY_PARAMETER_TRUE);
- }
- final Uri dictionaryPackUri = builder.build();
-
final ContentProviderClient client = context.getContentResolver().
acquireContentProviderClient(getProviderUriBuilder("").build());
if (null == client) return Collections.<WordListInfo>emptyList();
+
try {
- final Cursor c = client.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null,
- null);
- if (null == c) {
+ final Uri.Builder builder = getContentUriBuilderForType(clientId, client,
+ QUERY_PATH_DICT_INFO, locale.toString());
+ if (!hasDefaultWordList) {
+ builder.appendQueryParameter(QUERY_PARAMETER_MAY_PROMPT_USER,
+ QUERY_PARAMETER_TRUE);
+ }
+ final Uri queryUri = builder.build();
+ final boolean isProtocolV2 = (QUERY_PARAMETER_PROTOCOL_VALUE.equals(
+ queryUri.getQueryParameter(QUERY_PARAMETER_PROTOCOL)));
+
+ Cursor c = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null);
+ if (isProtocolV2 && null == c) {
reinitializeClientRecordInDictionaryContentProvider(context, client, clientId);
- return Collections.<WordListInfo>emptyList();
+ c = client.query(queryUri, DICTIONARY_PROJECTION, null, null, null);
}
+ if (null == c) return Collections.<WordListInfo>emptyList();
if (c.getCount() <= 0 || !c.moveToFirst()) {
c.close();
return Collections.<WordListInfo>emptyList();
}
- final List<WordListInfo> list = CollectionUtils.newArrayList();
+ final ArrayList<WordListInfo> list = CollectionUtils.newArrayList();
do {
final String wordListId = c.getString(0);
final String wordListLocale = c.getString(1);
@@ -156,13 +188,18 @@ public final class BinaryDictionaryFileDumper {
/**
* Helper method to encapsulate exception handling.
*/
- private static AssetFileDescriptor openAssetFileDescriptor(final ContentResolver resolver,
- final Uri uri) {
+ private static AssetFileDescriptor openAssetFileDescriptor(
+ final ContentProviderClient providerClient, final Uri uri) {
try {
- return resolver.openAssetFileDescriptor(uri, "r");
+ return providerClient.openAssetFile(uri, "r");
} catch (FileNotFoundException e) {
- // I don't want to log the word list URI here for security concerns
- Log.e(TAG, "Could not find a word list from the dictionary provider.");
+ // I don't want to log the word list URI here for security concerns. The exception
+ // contains the name of the file, so let's not pass it to Log.e here.
+ Log.e(TAG, "Could not find a word list from the dictionary provider."
+ /* intentionally don't pass the exception (see comment above) */);
+ return null;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't communicate with the dictionary pack", e);
return null;
}
}
@@ -172,9 +209,8 @@ public final class BinaryDictionaryFileDumper {
* to the cache file name designated by its id and locale, overwriting it if already present
* and creating it (and its containing directory) if necessary.
*/
- private static AssetFileAddress cacheWordList(final String id, final String locale,
- final ContentResolver resolver, final Context context) {
-
+ private static AssetFileAddress cacheWordList(final String wordlistId, final String locale,
+ final ContentProviderClient providerClient, final Context context) {
final int COMPRESSED_CRYPTED_COMPRESSED = 0;
final int CRYPTED_COMPRESSED = 1;
final int COMPRESSED_CRYPTED = 2;
@@ -184,11 +220,20 @@ public final class BinaryDictionaryFileDumper {
final int MODE_MIN = COMPRESSED_CRYPTED_COMPRESSED;
final int MODE_MAX = NONE;
- final Uri.Builder wordListUriBuilder = getProviderUriBuilder(id);
- final String finalFileName = DictionaryInfoUtils.getCacheFileName(id, locale, context);
+ final String clientId = context.getString(R.string.dictionary_pack_client_id);
+ final Uri.Builder wordListUriBuilder;
+ try {
+ wordListUriBuilder = getContentUriBuilderForType(clientId,
+ providerClient, QUERY_PATH_DATAFILE, wordlistId /* extraPath */);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't communicate with the dictionary pack", e);
+ return null;
+ }
+ final String finalFileName =
+ DictionaryInfoUtils.getCacheFileName(wordlistId, locale, context);
String tempFileName;
try {
- tempFileName = BinaryDictionaryGetter.getTempFileName(id, context);
+ tempFileName = BinaryDictionaryGetter.getTempFileName(wordlistId, context);
} catch (IOException e) {
Log.e(TAG, "Can't open the temporary file", e);
return null;
@@ -206,7 +251,7 @@ public final class BinaryDictionaryFileDumper {
final Uri wordListUri = wordListUriBuilder.build();
try {
// Open input.
- afd = openAssetFileDescriptor(resolver, wordListUri);
+ afd = openAssetFileDescriptor(providerClient, wordListUri);
// If we can't open it at all, don't even try a number of times.
if (null == afd) return null;
originalSourceStream = afd.createInputStream();
@@ -254,10 +299,10 @@ public final class BinaryDictionaryFileDumper {
}
wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT,
QUERY_PARAMETER_SUCCESS);
- if (0 >= resolver.delete(wordListUriBuilder.build(), null, null)) {
+ if (0 >= providerClient.delete(wordListUriBuilder.build(), null, null)) {
Log.e(TAG, "Could not have the dictionary pack delete a word list");
}
- BinaryDictionaryGetter.removeFilesWithIdExcept(context, id, finalFile);
+ BinaryDictionaryGetter.removeFilesWithIdExcept(context, wordlistId, finalFile);
// Success! Close files (through the finally{} clause) and return.
return AssetFileAddress.makeFromFileName(finalFileName);
} catch (Exception e) {
@@ -297,8 +342,12 @@ public final class BinaryDictionaryFileDumper {
// as invalid.
wordListUriBuilder.appendQueryParameter(QUERY_PARAMETER_DELETE_RESULT,
QUERY_PARAMETER_FAILURE);
- if (0 >= resolver.delete(wordListUriBuilder.build(), null, null)) {
- Log.e(TAG, "In addition, we were unable to delete it.");
+ try {
+ if (0 >= providerClient.delete(wordListUriBuilder.build(), null, null)) {
+ Log.e(TAG, "In addition, we were unable to delete it.");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "In addition, communication with the dictionary provider was cut", e);
}
return null;
}
@@ -315,17 +364,27 @@ public final class BinaryDictionaryFileDumper {
*/
public static List<AssetFileAddress> cacheWordListsFromContentProvider(final Locale locale,
final Context context, final boolean hasDefaultWordList) {
- final ContentResolver resolver = context.getContentResolver();
- final List<WordListInfo> idList = getWordListWordListInfos(locale, context,
- hasDefaultWordList);
- final List<AssetFileAddress> fileAddressList = CollectionUtils.newArrayList();
- for (WordListInfo id : idList) {
- final AssetFileAddress afd = cacheWordList(id.mId, id.mLocale, resolver, context);
- if (null != afd) {
- fileAddressList.add(afd);
+ final ContentProviderClient providerClient = context.getContentResolver().
+ acquireContentProviderClient(getProviderUriBuilder("").build());
+ if (null == providerClient) {
+ Log.e(TAG, "Can't establish communication with the dictionary provider");
+ return CollectionUtils.newArrayList();
+ }
+ try {
+ final List<WordListInfo> idList = getWordListWordListInfos(locale, context,
+ hasDefaultWordList);
+ final ArrayList<AssetFileAddress> fileAddressList = CollectionUtils.newArrayList();
+ for (WordListInfo id : idList) {
+ final AssetFileAddress afd =
+ cacheWordList(id.mId, id.mLocale, providerClient, context);
+ if (null != afd) {
+ fileAddressList.add(afd);
+ }
}
+ return fileAddressList;
+ } finally {
+ providerClient.release();
}
- return fileAddressList;
}
/**