diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java | 64 |
1 files changed, 48 insertions, 16 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java index 4a8752e43..879f1db49 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -94,33 +95,54 @@ public final class BinaryDictionaryFileDumper { } /** + * Finds out whether the dictionary pack is available on this device. + * @param context A context to get the content resolver. + * @return whether the dictionary pack is present or not. + */ + private static boolean isDictionaryPackPresent(final Context context) { + final ContentResolver cr = context.getContentResolver(); + final ContentProviderClient client = + cr.acquireContentProviderClient(getProviderUriBuilder("").build()); + if (client != null) { + client.release(); + return true; + } else { + return false; + } + } + + /** * 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 ContentResolver resolver = context.getContentResolver(); 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); + builder.appendQueryParameter(QUERY_PARAMETER_MAY_PROMPT_USER, + QUERY_PARAMETER_TRUE); } final Uri dictionaryPackUri = builder.build(); - final Cursor c = resolver.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null, null); - if (null == c) { - reinitializeClientRecordInDictionaryContentProvider(context, resolver, clientId); - return Collections.<WordListInfo>emptyList(); - } - if (c.getCount() <= 0 || !c.moveToFirst()) { - c.close(); - return Collections.<WordListInfo>emptyList(); - } - + final ContentResolver resolver = context.getContentResolver(); try { + final Cursor c = resolver.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null, + null); + if (null == c) { + if (isDictionaryPackPresent(context)) { + reinitializeClientRecordInDictionaryContentProvider(context, resolver, + clientId); + } + return Collections.<WordListInfo>emptyList(); + } + if (c.getCount() <= 0 || !c.moveToFirst()) { + c.close(); + return Collections.<WordListInfo>emptyList(); + } final List<WordListInfo> list = CollectionUtils.newArrayList(); do { final String wordListId = c.getString(0); @@ -130,10 +152,20 @@ public final class BinaryDictionaryFileDumper { } while (c.moveToNext()); c.close(); return list; + } catch (IllegalArgumentException e) { + // Any method call on the content resolver may unexpectedly crash without notice + // if the content provider is not present (for example, while crypting a device). + // Testing seems to indicate that ContentResolver#query() merely returns null + // while ContentResolver#delete throws IllegalArgumentException but this is + // undocumented, so all ContentResolver methods should be protected. A crash here is + // dangerous because crashing here would brick any encrypted device - we need the + // keyboard to be up and working to enter the password. So let's be as safe as possible. + Log.e(TAG, "IllegalArgumentException: the dictionary pack can't be contacted?", e); + return Collections.<WordListInfo>emptyList(); } catch (Exception e) { // Just in case we hit a problem in communication with the dictionary pack. // We don't want to die. - Log.e(TAG, "Exception communicating with the dictionary pack : " + e); + Log.e(TAG, "Exception communicating with the dictionary pack", e); return Collections.<WordListInfo>emptyList(); } } @@ -248,7 +280,7 @@ public final class BinaryDictionaryFileDumper { return AssetFileAddress.makeFromFileName(finalFileName); } catch (Exception e) { if (DEBUG) { - Log.i(TAG, "Can't open word list in mode " + mode + " : " + e); + Log.i(TAG, "Can't open word list in mode " + mode, e); } if (null != outputFile) { // This may or may not fail. The file may not have been created if the @@ -266,12 +298,12 @@ public final class BinaryDictionaryFileDumper { if (null != decryptedStream) decryptedStream.close(); if (null != bufferedInputStream) bufferedInputStream.close(); } catch (Exception e) { - Log.e(TAG, "Exception while closing a file descriptor : " + e); + Log.e(TAG, "Exception while closing a file descriptor", e); } try { if (null != bufferedOutputStream) bufferedOutputStream.close(); } catch (Exception e) { - Log.e(TAG, "Exception while closing a file : " + e); + Log.e(TAG, "Exception while closing a file", e); } } } |