aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/research
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/research')
-rw-r--r--java/src/com/android/inputmethod/research/LogUnit.java5
-rw-r--r--java/src/com/android/inputmethod/research/MainLogBuffer.java17
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java70
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java78
-rw-r--r--java/src/com/android/inputmethod/research/Uploader.java4
5 files changed, 65 insertions, 109 deletions
diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java
index 4d60bda53..cf1388f46 100644
--- a/java/src/com/android/inputmethod/research/LogUnit.java
+++ b/java/src/com/android/inputmethod/research/LogUnit.java
@@ -25,6 +25,7 @@ import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -135,9 +136,11 @@ public class LogUnit {
* @param researchLog where to publish the contents of this {@code LogUnit}
* @param canIncludePrivateData whether the private data in this {@code LogUnit} should be
* included
+ *
+ * @throws IOException if publication to the log file is not possible
*/
public synchronized void publishTo(final ResearchLog researchLog,
- final boolean canIncludePrivateData) {
+ final boolean canIncludePrivateData) throws IOException {
// Write out any logStatement that passes the privacy filter.
final int size = mLogStatementList.size();
if (size != 0) {
diff --git a/java/src/com/android/inputmethod/research/MainLogBuffer.java b/java/src/com/android/inputmethod/research/MainLogBuffer.java
index 9bdedbf6d..9aa349906 100644
--- a/java/src/com/android/inputmethod/research/MainLogBuffer.java
+++ b/java/src/com/android/inputmethod/research/MainLogBuffer.java
@@ -23,6 +23,7 @@ import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.Suggest;
import com.android.inputmethod.latin.define.ProductionFlag;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -177,7 +178,7 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
return numWordsInLogUnitList == minNGramSize;
}
- public void shiftAndPublishAll() {
+ public void shiftAndPublishAll() throws IOException {
final LinkedList<LogUnit> logUnits = getLogUnits();
while (!logUnits.isEmpty()) {
publishLogUnitsAtFrontOfBuffer();
@@ -186,10 +187,16 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
@Override
protected final void onBufferFull() {
- publishLogUnitsAtFrontOfBuffer();
+ try {
+ publishLogUnitsAtFrontOfBuffer();
+ } catch (final IOException e) {
+ if (DEBUG) {
+ Log.w(TAG, "IOException when publishing front of LogBuffer", e);
+ }
+ }
}
- protected final void publishLogUnitsAtFrontOfBuffer() {
+ protected final void publishLogUnitsAtFrontOfBuffer() throws IOException {
// TODO: Refactor this method to require fewer passes through the LogUnits. Should really
// require only one pass.
ArrayList<LogUnit> logUnits = peekAtFirstNWords(N_GRAM_SIZE);
@@ -224,9 +231,11 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
* @param logUnits The list of logUnits to be published.
* @param canIncludePrivateData Whether the private data in the logUnits can be included in
* publication.
+ *
+ * @throws IOException if publication to the log file is not possible
*/
protected abstract void publish(final ArrayList<LogUnit> logUnits,
- final boolean canIncludePrivateData);
+ final boolean canIncludePrivateData) throws IOException;
@Override
protected int shiftOutWords(final int numWords) {
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 18bf7ba54..3e82139a6 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -25,6 +25,7 @@ import com.android.inputmethod.latin.define.ProductionFlag;
import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@@ -61,7 +62,11 @@ public class ResearchLog {
/* package */ final File mFile;
private final Context mContext;
- private JsonWriter mJsonWriter = NULL_JSON_WRITER;
+ // Earlier implementations used a dummy JsonWriter that just swallowed what it was given, but
+ // this was tricky to do well, because JsonWriter throws an exception if it is passed more than
+ // one top-level object.
+ private JsonWriter mJsonWriter = null;
+
// true if at least one byte of data has been written out to the log file. This must be
// remembered because JsonWriter requires that calls matching calls to beginObject and
// endObject, as well as beginArray and endArray, and the file is opened lazily, only when
@@ -69,26 +74,6 @@ public class ResearchLog {
// could be caught, but this might suppress other errors.
private boolean mHasWrittenData = false;
- private static final JsonWriter NULL_JSON_WRITER = new JsonWriter(
- new OutputStreamWriter(new NullOutputStream()));
- private static class NullOutputStream extends OutputStream {
- /** {@inheritDoc} */
- @Override
- public void write(byte[] buffer, int offset, int count) {
- // nop
- }
-
- /** {@inheritDoc} */
- @Override
- public void write(byte[] buffer) {
- // nop
- }
-
- @Override
- public void write(int oneByte) {
- }
- }
-
public ResearchLog(final File outputFile, final Context context) {
mExecutor = Executors.newSingleThreadScheduledExecutor();
mFile = outputFile;
@@ -108,6 +93,7 @@ public class ResearchLog {
@Override
public Object call() throws Exception {
try {
+ if (mJsonWriter == null) return null;
// TODO: This is necessary to avoid an exception. Better would be to not even
// open the JsonWriter if the file is not even opened unless there is valid data
// to write.
@@ -119,9 +105,9 @@ public class ResearchLog {
mJsonWriter.flush();
mJsonWriter.close();
if (DEBUG) {
- Log.d(TAG, "wrote log to " + mFile);
+ Log.d(TAG, "closed " + mFile);
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.d(TAG, "error when closing ResearchLog:", e);
} finally {
// Marking the file as read-only signals that this log file is ready to be
@@ -162,6 +148,7 @@ public class ResearchLog {
@Override
public Object call() throws Exception {
try {
+ if (mJsonWriter == null) return null;
if (mHasWrittenData) {
// TODO: This is necessary to avoid an exception. Better would be to not
// even open the JsonWriter if the file is not even opened unless there is
@@ -217,7 +204,7 @@ public class ResearchLog {
private final Callable<Object> mFlushCallable = new Callable<Object>() {
@Override
public Object call() throws Exception {
- mJsonWriter.flush();
+ if (mJsonWriter != null) mJsonWriter.flush();
return null;
}
};
@@ -263,30 +250,29 @@ public class ResearchLog {
/**
* Return a JsonWriter for this ResearchLog. It is initialized the first time this method is
* called. The cached value is returned in future calls.
+ *
+ * @throws IOException if opening the JsonWriter is not possible
*/
- public JsonWriter getInitializedJsonWriterLocked() {
- if (mJsonWriter != NULL_JSON_WRITER || mFile == null) return mJsonWriter;
+ public JsonWriter getInitializedJsonWriterLocked() throws IOException {
+ if (mJsonWriter != null) return mJsonWriter;
+ if (mFile == null) throw new FileNotFoundException();
try {
final JsonWriter jsonWriter = createJsonWriter(mContext, mFile);
- if (jsonWriter != null) {
- jsonWriter.beginArray();
- mJsonWriter = jsonWriter;
- mHasWrittenData = true;
- }
+ if (jsonWriter == null) throw new IOException("Could not create JsonWriter");
+
+ jsonWriter.beginArray();
+ mJsonWriter = jsonWriter;
+ mHasWrittenData = true;
+ return mJsonWriter;
} catch (final IOException e) {
- Log.w(TAG, "Error in JsonWriter; disabling logging", e);
- try {
- mJsonWriter.close();
- } catch (final IllegalStateException e1) {
- // Assume that this is just the json not being terminated properly.
- // Ignore
- } catch (final IOException e1) {
- Log.w(TAG, "Error in closing JsonWriter; disabling logging", e1);
- } finally {
- mJsonWriter = NULL_JSON_WRITER;
+ if (DEBUG) {
+ Log.w(TAG, "Exception when creating JsonWriter", e);
+ Log.w(TAG, "Closing JsonWriter");
}
+ if (mJsonWriter != null) mJsonWriter.close();
+ mJsonWriter = null;
+ throw e;
}
- return mJsonWriter;
}
/**
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index b45134edc..8b8ea21e9 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -118,7 +118,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static final boolean FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD = false;
/* package */ static boolean sIsLogging = false;
private static final int OUTPUT_FORMAT_VERSION = 5;
- private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
// Whether all words should be recorded, leaving unsampled word between bigrams. Useful for
// testing.
/* package for test */ static final boolean IS_LOGGING_EVERYTHING = false
@@ -157,17 +156,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// LogUnits are queued in the LogBuffers and published to the ResearchLogs when words are
// complete.
/* package for test */ MainLogBuffer mMainLogBuffer; // always non-null after init() is called
- // TODO: Remove the feedback log. The feedback log continuously captured user data in case the
- // user wanted to submit it. We now use the mUserRecordingLogBuffer to allow the user to
- // explicitly reproduce a problem.
- private ResearchLog mFeedbackLog;
- private LogBuffer mFeedbackLogBuffer;
/* package */ ResearchLog mUserRecordingLog;
/* package */ LogBuffer mUserRecordingLogBuffer;
private File mUserRecordingFile = null;
private boolean mIsPasswordView = false;
- private boolean mIsLoggingSuspended = false;
private SharedPreferences mPrefs;
// digits entered by the user are replaced with this codepoint.
@@ -202,15 +195,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private long mSavedDownEventTime;
private Bundle mFeedbackDialogBundle = null;
private boolean mInFeedbackDialog = false;
- // The feedback dialog causes stop() to be called for the keyboard connected to the original
- // window. This is because the feedback dialog must present its own EditText box that displays
- // a keyboard. stop() normally causes mFeedbackLogBuffer, which contains the user's data, to be
- // cleared, and causes mFeedbackLog, which is ready to collect information in case the user
- // wants to upload, to be closed. This is good because we don't need to log information about
- // what the user is typing in the feedback dialog, but bad because this data must be uploaded.
- // Here we save the LogBuffer and Log so the feedback dialog can later access their data.
- private LogBuffer mSavedFeedbackLogBuffer;
- private ResearchLog mSavedFeedbackLog;
private Handler mUserRecordingTimeoutHandler;
private static final long USER_RECORDING_TIMEOUT_MS = 30L * DateUtils.SECOND_IN_MILLIS;
@@ -282,10 +266,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
publishLogUnits(logUnits, mMainResearchLog, canIncludePrivateData);
}
};
-
- mFeedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
- System.currentTimeMillis(), System.nanoTime()), mLatinIME);
- mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE);
}
private void cleanLogDirectoryIfNeeded(final ResearchLogDirectory researchLogDirectory,
@@ -412,7 +392,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Log.d(TAG, "start called");
}
maybeShowSplashScreen();
- updateSuspendedState();
requestIndicatorRedraw();
mStatistics.reset();
checkForEmptyEditor();
@@ -425,13 +404,20 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// Commit mCurrentLogUnit before closing.
commitCurrentLogUnit();
- mMainLogBuffer.shiftAndPublishAll();
+ try {
+ mMainLogBuffer.shiftAndPublishAll();
+ } catch (final IOException e) {
+ Log.w(TAG, "IOException when publishing LogBuffer", e);
+ }
logStatistics();
commitCurrentLogUnit();
mMainLogBuffer.setIsStopping();
- mMainLogBuffer.shiftAndPublishAll();
+ try {
+ mMainLogBuffer.shiftAndPublishAll();
+ } catch (final IOException e) {
+ Log.w(TAG, "IOException when publishing LogBuffer", e);
+ }
mMainResearchLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
- mFeedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
resetLogBuffers();
}
@@ -442,8 +428,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
mMainLogBuffer.clear();
mMainResearchLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
- mFeedbackLogBuffer.clear();
- mFeedbackLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
resetLogBuffers();
}
@@ -453,23 +437,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
start();
}
- private long mResumeTime = 0L;
- private void updateSuspendedState() {
- final long time = System.currentTimeMillis();
- if (time > mResumeTime) {
- mIsLoggingSuspended = false;
- }
- }
-
@Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
if (key == null || prefs == null) {
return;
}
- sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
- if (sIsLogging == false) {
- abort();
- }
requestIndicatorRedraw();
mPrefs = prefs;
prefsChanged(prefs);
@@ -489,12 +461,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
saveRecording();
}
mInFeedbackDialog = true;
- mSavedFeedbackLogBuffer = mFeedbackLogBuffer;
- mSavedFeedbackLog = mFeedbackLog;
- // Set the non-saved versions to null so that the stop() caused by switching to the
- // Feedback dialog will not close them.
- mFeedbackLogBuffer = null;
- mFeedbackLog = null;
final Intent intent = new Intent();
intent.setClass(mLatinIME, FeedbackActivity.class);
@@ -652,12 +618,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
new LogStatement("UserFeedback", false, false, "contents", "accountName", "recording");
public void sendFeedback(final String feedbackContents, final boolean includeHistory,
final boolean isIncludingAccountName, final boolean isIncludingRecording) {
- if (mSavedFeedbackLogBuffer == null) {
- return;
- }
- if (!includeHistory) {
- mSavedFeedbackLogBuffer.clear();
- }
String recording = "";
if (isIncludingRecording) {
// Try to read recording from recently written json file
@@ -689,9 +649,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final String accountName = isIncludingAccountName ? getAccountName() : "";
feedbackLogUnit.addLogStatement(LOGSTATEMENT_FEEDBACK, SystemClock.uptimeMillis(),
feedbackContents, accountName, recording);
- mFeedbackLogBuffer.shiftIn(feedbackLogUnit);
- publishLogBuffer(mFeedbackLogBuffer, mSavedFeedbackLog, true /* isIncludingPrivateData */);
- mSavedFeedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
+
+ final ResearchLog feedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
+ System.currentTimeMillis(), System.nanoTime()), mLatinIME);
+ final LogBuffer feedbackLogBuffer = new LogBuffer();
+ feedbackLogBuffer.shiftIn(feedbackLogUnit);
+ publishLogBuffer(feedbackLogBuffer, feedbackLog, true /* isIncludingPrivateData */);
+ feedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
uploadNow();
if (isIncludingRecording && DEBUG_REPLAY_AFTER_FEEDBACK) {
@@ -750,7 +714,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
private boolean isAllowedToLog() {
- return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog;
+ return !mIsPasswordView && sIsLogging && !mInFeedbackDialog;
}
public void requestIndicatorRedraw() {
@@ -843,9 +807,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
if (!mCurrentLogUnit.isEmpty()) {
mMainLogBuffer.shiftIn(mCurrentLogUnit);
- if (mFeedbackLogBuffer != null) {
- mFeedbackLogBuffer.shiftIn(mCurrentLogUnit);
- }
if (mUserRecordingLogBuffer != null) {
mUserRecordingLogBuffer.shiftIn(mCurrentLogUnit);
}
@@ -891,9 +852,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
} else {
mCurrentLogUnit = oldLogUnit;
}
- if (mFeedbackLogBuffer != null) {
- mFeedbackLogBuffer.unshiftIn();
- }
enqueueEvent(LOGSTATEMENT_UNCOMMIT_CURRENT_LOGUNIT);
if (DEBUG) {
Log.d(TAG, "uncommitCurrentLogUnit (dump=" + dumpCurrentLogUnit + ") back to "
diff --git a/java/src/com/android/inputmethod/research/Uploader.java b/java/src/com/android/inputmethod/research/Uploader.java
index ba05ec12b..c7ea3e69d 100644
--- a/java/src/com/android/inputmethod/research/Uploader.java
+++ b/java/src/com/android/inputmethod/research/Uploader.java
@@ -49,7 +49,7 @@ public final class Uploader {
private static final boolean DEBUG = false
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
// Set IS_INHIBITING_AUTO_UPLOAD to true for local testing
- private static final boolean IS_INHIBITING_AUTO_UPLOAD = false
+ private static final boolean IS_INHIBITING_UPLOAD = false
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
private static final int BUF_SIZE = 1024 * 8;
@@ -76,7 +76,7 @@ public final class Uploader {
}
public boolean isPossibleToUpload() {
- return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_AUTO_UPLOAD;
+ return hasUploadingPermission() && mUrl != null && !IS_INHIBITING_UPLOAD;
}
private boolean hasUploadingPermission() {