aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/research/ResearchLogger.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/research/ResearchLogger.java')
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java235
1 files changed, 84 insertions, 151 deletions
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 7a23ddb05..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
@@ -150,24 +149,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static final ResearchLogger sInstance = new ResearchLogger();
private static String sAccountType = null;
private static String sAllowedAccountDomain = null;
- /* package */ ResearchLog mMainResearchLog;
+ private ResearchLog mMainResearchLog; // always non-null after init() is called
// mFeedbackLog records all events for the session, private or not (excepting
// passwords). It is written to permanent storage only if the user explicitly commands
// the system to do so.
// LogUnits are queued in the LogBuffers and published to the ResearchLogs when words are
// complete.
- /* package */ MainLogBuffer mMainLogBuffer;
- // 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.
- /* package */ ResearchLog mFeedbackLog;
- /* package */ LogBuffer mFeedbackLogBuffer;
+ /* package for test */ MainLogBuffer mMainLogBuffer; // always non-null after init() is called
/* 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;
@@ -241,6 +225,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mResearchLogDirectory = new ResearchLogDirectory(mLatinIME);
cleanLogDirectoryIfNeeded(mResearchLogDirectory, System.currentTimeMillis());
+ // Initialize log buffers
+ resetLogBuffers();
+
// Initialize external services
mUploadIntent = new Intent(mLatinIME, UploaderService.class);
mUploadNowIntent = new Intent(mLatinIME, UploaderService.class);
@@ -252,6 +239,35 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mReplayer.setKeyboardSwitcher(keyboardSwitcher);
}
+ private void resetLogBuffers() {
+ mMainResearchLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
+ System.currentTimeMillis(), System.nanoTime()), mLatinIME);
+ final int numWordsToIgnore = new Random().nextInt(NUMBER_OF_WORDS_BETWEEN_SAMPLES + 1);
+ mMainLogBuffer = new MainLogBuffer(NUMBER_OF_WORDS_BETWEEN_SAMPLES, numWordsToIgnore,
+ mSuggest) {
+ @Override
+ protected void publish(final ArrayList<LogUnit> logUnits,
+ boolean canIncludePrivateData) {
+ canIncludePrivateData |= IS_LOGGING_EVERYTHING;
+ for (final LogUnit logUnit : logUnits) {
+ if (DEBUG) {
+ final String wordsString = logUnit.getWordsAsString();
+ Log.d(TAG, "onPublish: '" + wordsString
+ + "', hc: " + logUnit.containsCorrection()
+ + ", cipd: " + canIncludePrivateData);
+ }
+ for (final String word : logUnit.getWordsAsStringArray()) {
+ final Dictionary dictionary = getDictionary();
+ mStatistics.recordWordEntered(
+ dictionary != null && dictionary.isValidWord(word),
+ logUnit.containsCorrection());
+ }
+ }
+ publishLogUnits(logUnits, mMainResearchLog, canIncludePrivateData);
+ }
+ };
+ }
+
private void cleanLogDirectoryIfNeeded(final ResearchLogDirectory researchLogDirectory,
final long now) {
final long lastCleanupTime = ResearchSettings.readResearchLastDirCleanupTime(mPrefs);
@@ -376,52 +392,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Log.d(TAG, "start called");
}
maybeShowSplashScreen();
- updateSuspendedState();
requestIndicatorRedraw();
mStatistics.reset();
checkForEmptyEditor();
- if (mFeedbackLogBuffer == null) {
- resetFeedbackLogging();
- }
- if (!isAllowedToLog()) {
- // Log.w(TAG, "not in usability mode; not logging");
- return;
- }
- if (mMainLogBuffer == null) {
- mMainResearchLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
- System.currentTimeMillis()), mLatinIME);
- final int numWordsToIgnore = new Random().nextInt(NUMBER_OF_WORDS_BETWEEN_SAMPLES + 1);
- mMainLogBuffer = new MainLogBuffer(NUMBER_OF_WORDS_BETWEEN_SAMPLES, numWordsToIgnore,
- mSuggest) {
- @Override
- protected void publish(final ArrayList<LogUnit> logUnits,
- boolean canIncludePrivateData) {
- canIncludePrivateData |= IS_LOGGING_EVERYTHING;
- final int length = logUnits.size();
- for (int i = 0; i < length; i++) {
- final LogUnit logUnit = logUnits.get(i);
- final String word = logUnit.getWord();
- if (word != null && word.length() > 0 && hasLetters(word)) {
- Log.d(TAG, "onPublish: " + word + ", hc: "
- + logUnit.containsCorrection());
- final Dictionary dictionary = getDictionary();
- mStatistics.recordWordEntered(
- dictionary != null && dictionary.isValidWord(word),
- logUnit.containsCorrection());
- }
- }
- if (mMainResearchLog != null) {
- publishLogUnits(logUnits, mMainResearchLog, canIncludePrivateData);
- }
- }
- };
- }
- }
-
- private void resetFeedbackLogging() {
- mFeedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath(
- System.currentTimeMillis()), mLatinIME);
- mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE);
}
/* package */ void stop() {
@@ -431,35 +404,32 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// Commit mCurrentLogUnit before closing.
commitCurrentLogUnit();
- if (mMainLogBuffer != null) {
- mMainLogBuffer.shiftAndPublishAll();
- logStatistics();
- commitCurrentLogUnit();
- mMainLogBuffer.setIsStopping();
+ try {
mMainLogBuffer.shiftAndPublishAll();
- mMainResearchLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
- mMainLogBuffer = null;
+ } catch (final IOException e) {
+ Log.w(TAG, "IOException when publishing LogBuffer", e);
}
- if (mFeedbackLogBuffer != null) {
- mFeedbackLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
- mFeedbackLogBuffer = null;
+ logStatistics();
+ commitCurrentLogUnit();
+ mMainLogBuffer.setIsStopping();
+ try {
+ mMainLogBuffer.shiftAndPublishAll();
+ } catch (final IOException e) {
+ Log.w(TAG, "IOException when publishing LogBuffer", e);
}
+ mMainResearchLog.blockingClose(RESEARCHLOG_CLOSE_TIMEOUT_IN_MS);
+
+ resetLogBuffers();
}
public void abort() {
if (DEBUG) {
Log.d(TAG, "abort called");
}
- if (mMainLogBuffer != null) {
- mMainLogBuffer.clear();
- mMainResearchLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
- mMainLogBuffer = null;
- }
- if (mFeedbackLogBuffer != null) {
- mFeedbackLogBuffer.clear();
- mFeedbackLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
- mFeedbackLogBuffer = null;
- }
+ mMainLogBuffer.clear();
+ mMainResearchLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
+
+ resetLogBuffers();
}
private void restart() {
@@ -467,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);
@@ -503,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);
@@ -545,7 +497,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mUserRecordingLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS);
}
mUserRecordingFile = mResearchLogDirectory.getUserRecordingFilePath(
- System.currentTimeMillis());
+ System.currentTimeMillis(), System.nanoTime());
mUserRecordingLog = new ResearchLog(mUserRecordingFile, mLatinIME);
mUserRecordingLogBuffer = new LogBuffer();
resetRecordingTimer();
@@ -666,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
@@ -703,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) {
@@ -744,8 +694,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public void initSuggest(final Suggest suggest) {
mSuggest = suggest;
- // MainLogBuffer has out-of-date Suggest object. Need to close it down and create a new
- // one.
+ // MainLogBuffer now has an out-of-date Suggest object. Close down MainLogBuffer and create
+ // a new one.
if (mMainLogBuffer != null) {
stop();
start();
@@ -764,7 +714,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
private boolean isAllowedToLog() {
- return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog;
+ return !mIsPasswordView && sIsLogging && !mInFeedbackDialog;
}
public void requestIndicatorRedraw() {
@@ -813,7 +763,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// enabled. The dot is actually a zero-width, zero-height rectangle, placed at the
// lower-right corner of the canvas, painted with a non-zero border width.
paint.setStrokeWidth(3);
- canvas.drawRect(width, height, width, height, paint);
+ canvas.drawRect(width - 1, height - 1, width, height, paint);
}
paint.setColor(savedColor);
paint.setStyle(savedStyle);
@@ -852,16 +802,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
/* package for test */ void commitCurrentLogUnit() {
if (DEBUG) {
- Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ?
- ": " + mCurrentLogUnit.getWord() : ""));
+ Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasOneOrMoreWords() ?
+ ": " + mCurrentLogUnit.getWordsAsString() : ""));
}
if (!mCurrentLogUnit.isEmpty()) {
- if (mMainLogBuffer != null) {
- mMainLogBuffer.shiftIn(mCurrentLogUnit);
- }
- if (mFeedbackLogBuffer != null) {
- mFeedbackLogBuffer.shiftIn(mCurrentLogUnit);
- }
+ mMainLogBuffer.shiftIn(mCurrentLogUnit);
if (mUserRecordingLogBuffer != null) {
mUserRecordingLogBuffer.shiftIn(mCurrentLogUnit);
}
@@ -886,15 +831,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
//
// Note that we don't use mLastLogUnit here, because it only goes one word back and is only
// needed for reverts, which only happen one back.
- if (mMainLogBuffer == null) {
- return;
- }
final LogUnit oldLogUnit = mMainLogBuffer.peekLastLogUnit();
// Check that expected word matches.
if (oldLogUnit != null) {
- final String oldLogUnitWord = oldLogUnit.getWord();
- if (!oldLogUnitWord.equals(expectedWord)) {
+ final String oldLogUnitWords = oldLogUnit.getWordsAsString();
+ if (oldLogUnitWords != null && !oldLogUnitWords.equals(expectedWord)) {
return;
}
}
@@ -910,13 +852,11 @@ 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 "
- + (mCurrentLogUnit.hasWord() ? ": '" + mCurrentLogUnit.getWord() + "'" : ""));
+ + (mCurrentLogUnit.hasOneOrMoreWords() ? ": '"
+ + mCurrentLogUnit.getWordsAsString() + "'" : ""));
}
}
@@ -941,6 +881,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLog researchLog, final boolean canIncludePrivateData) {
final LogUnit openingLogUnit = new LogUnit();
if (logUnits.isEmpty()) return;
+ if (!isAllowedToLog()) return;
// LogUnits not containing private data, such as contextual data for the log, do not require
// logSegment boundary statements.
if (canIncludePrivateData) {
@@ -950,8 +891,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
for (LogUnit logUnit : logUnits) {
if (DEBUG) {
- Log.d(TAG, "publishLogBuffer: " + (logUnit.hasWord() ? logUnit.getWord()
- : "<wordless>") + ", correction?: " + logUnit.containsCorrection());
+ Log.d(TAG, "publishLogBuffer: " + (logUnit.hasOneOrMoreWords()
+ ? logUnit.getWordsAsString() : "<wordless>")
+ + ", correction?: " + logUnit.containsCorrection());
}
researchLog.publish(logUnit, canIncludePrivateData);
}
@@ -986,7 +928,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return;
}
if (word.length() > 0 && hasLetters(word)) {
- mCurrentLogUnit.setWord(word);
+ mCurrentLogUnit.setWords(word);
}
final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime);
enqueueCommitText(word, isBatchMode);
@@ -1107,7 +1049,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
packageInfo = mLatinIME.getPackageManager().getPackageInfo(mLatinIME.getPackageName(),
0);
final String versionName = packageInfo.versionName;
- return !(developerBuildRegex.matcher(versionName).find());
+ return developerBuildRegex.matcher(versionName).find();
} catch (final NameNotFoundException e) {
Log.e(TAG, "Could not determine package name", e);
return false;
@@ -1373,11 +1315,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_promotePhantomSpace() {
final ResearchLogger researchLogger = getInstance();
final LogUnit logUnit;
- if (researchLogger.mMainLogBuffer == null) {
- logUnit = researchLogger.mCurrentLogUnit;
- } else {
- logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
- }
+ logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_PROMOTEPHANTOMSPACE);
}
@@ -1394,11 +1332,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final String charactersAfterSwap) {
final ResearchLogger researchLogger = getInstance();
final LogUnit logUnit;
- if (researchLogger.mMainLogBuffer == null) {
- logUnit = null;
- } else {
- logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
- }
+ logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
if (logUnit != null) {
researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_SWAPSWAPPERANDSPACE,
originalCharacters, charactersAfterSwap);
@@ -1471,14 +1405,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
// TODO: Verify that mCurrentLogUnit has been restored and contains the reverted word.
final LogUnit logUnit;
- if (researchLogger.mMainLogBuffer == null) {
- logUnit = null;
- } else {
- logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
- }
+ logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit();
if (originallyTypedWord.length() > 0 && hasLetters(originallyTypedWord)) {
if (logUnit != null) {
- logUnit.setWord(originallyTypedWord);
+ logUnit.setWords(originallyTypedWord);
}
}
researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit,
@@ -1616,7 +1546,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
* Log a call to LatinIME.commitCurrentAutoCorrection().
*
* SystemResponse: The IME has committed an auto-correction. An auto-correction changes the raw
- * text input to another word that the user more likely desired to type.
+ * text input to another word (or words) that the user more likely desired to type.
*/
private static final LogStatement LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION =
new LogStatement("LatinIMECommitCurrentAutoCorrection", true, true, "typedWord",
@@ -1826,6 +1756,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_onEndBatchInput(final CharSequence enteredText,
final int enteredWordPos, final SuggestedWords suggestedWords) {
final ResearchLogger researchLogger = getInstance();
+ if (!TextUtils.isEmpty(enteredText) && hasLetters(enteredText.toString())) {
+ researchLogger.mCurrentLogUnit.setWords(enteredText.toString());
+ }
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText,
enteredWordPos);
researchLogger.mCurrentLogUnit.initializeSuggestions(suggestedWords);