aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java60
-rw-r--r--java/src/com/android/inputmethod/research/LogStatement.java4
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java8
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java13
4 files changed, 37 insertions, 48 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index 879f1db49..165116ae0 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
+import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
@@ -95,23 +96,6 @@ 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.
*/
@@ -128,15 +112,14 @@ public final class BinaryDictionaryFileDumper {
}
final Uri dictionaryPackUri = builder.build();
- final ContentResolver resolver = context.getContentResolver();
+ final ContentProviderClient client = context.getContentResolver().
+ acquireContentProviderClient(getProviderUriBuilder("").build());
+ if (null == client) return Collections.<WordListInfo>emptyList();
try {
- final Cursor c = resolver.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null,
+ final Cursor c = client.query(dictionaryPackUri, DICTIONARY_PROJECTION, null, null,
null);
if (null == c) {
- if (isDictionaryPackPresent(context)) {
- reinitializeClientRecordInDictionaryContentProvider(context, resolver,
- clientId);
- }
+ reinitializeClientRecordInDictionaryContentProvider(context, client, clientId);
return Collections.<WordListInfo>emptyList();
}
if (c.getCount() <= 0 || !c.moveToFirst()) {
@@ -152,21 +135,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);
+ } catch (RemoteException e) {
+ // The documentation is unclear as to in which cases this may happen, but it probably
+ // happens when the content provider got suddenly killed because it crashed or because
+ // the user disabled it through Settings.
+ Log.e(TAG, "RemoteException: communication with the dictionary pack cut", 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);
+ // 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 we don't want
+ // to die no matter what. So let's be as safe as possible.
+ Log.e(TAG, "Unexpected exception communicating with the dictionary pack", e);
return Collections.<WordListInfo>emptyList();
+ } finally {
+ client.release();
}
}
@@ -380,7 +362,7 @@ public final class BinaryDictionaryFileDumper {
}
private static void reinitializeClientRecordInDictionaryContentProvider(final Context context,
- final ContentResolver resolver, final String clientId) {
+ final ContentProviderClient client, final String clientId) throws RemoteException {
final String metadataFileUri = context.getString(R.string.dictionary_pack_metadata_uri);
if (TextUtils.isEmpty(metadataFileUri)) return;
// Tell the content provider to reset all information about this client id
@@ -388,12 +370,12 @@ public final class BinaryDictionaryFileDumper {
.appendPath(QUERY_PATH_METADATA)
.appendQueryParameter(QUERY_PARAMETER_PROTOCOL, QUERY_PARAMETER_PROTOCOL_VALUE)
.build();
- resolver.delete(metadataContentUri, null, null);
+ client.delete(metadataContentUri, null, null);
// Update the metadata URI
final ContentValues metadataValues = new ContentValues();
metadataValues.put(INSERT_METADATA_CLIENT_ID_COLUMN, clientId);
metadataValues.put(INSERT_METADATA_METADATA_URI_COLUMN, metadataFileUri);
- resolver.insert(metadataContentUri, metadataValues);
+ client.insert(metadataContentUri, metadataValues);
// Update the dictionary list.
final Uri dictionaryContentUriBase = getProviderUriBuilder(clientId)
@@ -405,7 +387,7 @@ public final class BinaryDictionaryFileDumper {
final int length = dictionaryList.size();
for (int i = 0; i < length; ++i) {
final DictionaryInfo info = dictionaryList.get(i);
- resolver.insert(Uri.withAppendedPath(dictionaryContentUriBase, info.mId),
+ client.insert(Uri.withAppendedPath(dictionaryContentUriBase, info.mId),
info.toContentValues());
}
}
diff --git a/java/src/com/android/inputmethod/research/LogStatement.java b/java/src/com/android/inputmethod/research/LogStatement.java
index 059146ae6..09b12fcfa 100644
--- a/java/src/com/android/inputmethod/research/LogStatement.java
+++ b/java/src/com/android/inputmethod/research/LogStatement.java
@@ -35,7 +35,7 @@ import java.io.IOException;
* associated with the {@code String[] keys} are likely to reveal information about the user. The
* actual values are stored separately.
*/
-class LogStatement {
+public class LogStatement {
private static final String TAG = LogStatement.class.getSimpleName();
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
@@ -166,6 +166,8 @@ class LogStatement {
/**
* Write the contents out through jsonWriter.
*
+ * The JsonWriter class must have already had {@code JsonWriter.beginArray} called on it.
+ *
* Note that this method is not thread safe for the same jsonWriter. Callers must ensure
* thread safety.
*/
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index a584a3af6..1a9a720f3 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -110,7 +110,13 @@ import java.util.List;
}
/**
- * Publish the contents of this LogUnit to researchLog.
+ * Publish the contents of this LogUnit to {@code researchLog}.
+ *
+ * For each publishable {@code LogStatement}, invoke {@link LogStatement#outputToLocked}.
+ *
+ * @param researchLog where to publish the contents of this {@code LogUnit}
+ * @param canIncludePrivateData whether the private data in this {@code LogUnit} should be
+ * included
*/
public synchronized void publishTo(final ResearchLog researchLog,
final boolean canIncludePrivateData) {
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 24bf7d15f..5114977d8 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -81,10 +81,7 @@ public class ResearchLog {
}
}
- public ResearchLog(final File outputFile, Context context) {
- if (outputFile == null) {
- throw new IllegalArgumentException();
- }
+ public ResearchLog(final File outputFile, final Context context) {
mExecutor = Executors.newSingleThreadScheduledExecutor();
mFile = outputFile;
mContext = context;
@@ -112,7 +109,7 @@ public class ResearchLog {
Log.d(TAG, "error when closing ResearchLog:");
e.printStackTrace();
} finally {
- if (mFile.exists()) {
+ if (mFile != null && mFile.exists()) {
mFile.setWritable(false, false);
}
if (onClosed != null) {
@@ -139,7 +136,9 @@ public class ResearchLog {
mHasWrittenData = false;
}
} finally {
- mIsAbortSuccessful = mFile.delete();
+ if (mFile != null) {
+ mIsAbortSuccessful = mFile.delete();
+ }
}
return null;
}
@@ -209,7 +208,7 @@ public class ResearchLog {
*/
public JsonWriter getValidJsonWriterLocked() {
try {
- if (mJsonWriter == NULL_JSON_WRITER) {
+ if (mJsonWriter == NULL_JSON_WRITER && mFile != null) {
final FileOutputStream fos =
mContext.openFileOutput(mFile.getName(), Context.MODE_PRIVATE);
mJsonWriter = new JsonWriter(new BufferedWriter(new OutputStreamWriter(fos)));