diff options
Diffstat (limited to 'java/src/com/android/inputmethod/research/ResearchLogger.java')
-rw-r--r-- | java/src/com/android/inputmethod/research/ResearchLogger.java | 156 |
1 files changed, 109 insertions, 47 deletions
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 8b8ea21e9..56ab90cb4 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -194,10 +194,17 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // gesture, and when committing the earlier word, split the LogUnit. private long mSavedDownEventTime; private Bundle mFeedbackDialogBundle = null; + // Whether the feedback dialog is visible, and the user is typing into it. Normal logging is + // not performed on text that the user types into the feedback dialog. private boolean mInFeedbackDialog = false; private Handler mUserRecordingTimeoutHandler; private static final long USER_RECORDING_TIMEOUT_MS = 30L * DateUtils.SECOND_IN_MILLIS; + // Stores a temporary LogUnit while generating a phantom space. Needed because phantom spaces + // are issued out-of-order, immediately before the characters generated by other operations that + // have already outputted LogStatements. + private LogUnit mPhantomSpaceLogUnit = null; + private ResearchLogger() { mStatistics = Statistics.getInstance(); } @@ -253,14 +260,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (DEBUG) { final String wordsString = logUnit.getWordsAsString(); Log.d(TAG, "onPublish: '" + wordsString - + "', hc: " + logUnit.containsCorrection() + + "', hc: " + logUnit.containsUserDeletions() + ", cipd: " + canIncludePrivateData); } for (final String word : logUnit.getWordsAsStringArray()) { final Dictionary dictionary = getDictionary(); mStatistics.recordWordEntered( dictionary != null && dictionary.isValidWord(word), - logUnit.containsCorrection()); + logUnit.containsUserDeletions()); } } publishLogUnits(logUnits, mMainResearchLog, canIncludePrivateData); @@ -650,7 +657,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang feedbackLogUnit.addLogStatement(LOGSTATEMENT_FEEDBACK, SystemClock.uptimeMillis(), feedbackContents, accountName, recording); - final ResearchLog feedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath( + final ResearchLog feedbackLog = new FeedbackLog(mResearchLogDirectory.getLogFilePath( System.currentTimeMillis(), System.nanoTime()), mLatinIME); final LogBuffer feedbackLogBuffer = new LogBuffer(); feedbackLogBuffer.shiftIn(feedbackLogUnit); @@ -713,8 +720,28 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mIsPasswordView = isPasswordView; } - private boolean isAllowedToLog() { - return !mIsPasswordView && sIsLogging && !mInFeedbackDialog; + /** + * Returns true if logging is permitted. + * + * This method is called when adding a LogStatement to a LogUnit, and when adding a LogUnit to a + * ResearchLog. It is checked in both places in case conditions change between these times, and + * as a defensive measure in case refactoring changes the logging pipeline. + */ + private boolean isAllowedToLogTo(final ResearchLog researchLog) { + // Logging is never allowed in these circumstances + if (mIsPasswordView) return false; + if (!sIsLogging) return false; + if (mInFeedbackDialog) { + // The FeedbackDialog is up. Normal logging should not happen (the user might be trying + // out things while the dialog is up, and their reporting of an issue may not be + // representative of what they normally type). However, after the user has finished + // entering their feedback, the logger packs their comments and an encoded version of + // any demonstration of the issue into a special "FeedbackLog". So if the FeedbackLog + // is the destination, we do want to allow logging to it. + return researchLog.isFeedbackLog(); + } + // No other exclusions. Logging is permitted. + return true; } public void requestIndicatorRedraw() { @@ -747,7 +774,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // and remove this method. // The check for MainKeyboardView ensures that the indicator only decorates the main // keyboard, not every keyboard. - if (IS_SHOWING_INDICATOR && (isAllowedToLog() || isReplaying()) + if (IS_SHOWING_INDICATOR && (isAllowedToLogTo(mMainResearchLog) || isReplaying()) && view instanceof MainKeyboardView) { final int savedColor = paint.getColor(); paint.setColor(getIndicatorColor()); @@ -782,7 +809,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private synchronized void enqueueEvent(final LogUnit logUnit, final LogStatement logStatement, final Object... values) { assert values.length == logStatement.getKeys().length; - if (isAllowedToLog() && logUnit != null) { + if (isAllowedToLogTo(mMainResearchLog) && logUnit != null) { final long time = SystemClock.uptimeMillis(); logUnit.addLogStatement(logStatement, time, values); } @@ -792,8 +819,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mCurrentLogUnit.setMayContainDigit(); } - private void setCurrentLogUnitContainsCorrection() { - mCurrentLogUnit.setContainsCorrection(); + private void setCurrentLogUnitContainsUserDeletions() { + mCurrentLogUnit.setContainsUserDeletions(); } private void setCurrentLogUnitCorrectionType(final int correctionType) { @@ -881,7 +908,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; + if (!isAllowedToLogTo(researchLog)) return; // LogUnits not containing private data, such as contextual data for the log, do not require // logSegment boundary statements. if (canIncludePrivateData) { @@ -893,7 +920,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (DEBUG) { Log.d(TAG, "publishLogBuffer: " + (logUnit.hasOneOrMoreWords() ? logUnit.getWordsAsString() : "<wordless>") - + ", correction?: " + logUnit.containsCorrection()); + + ", correction?: " + logUnit.containsUserDeletions()); } researchLog.publish(logUnit, canIncludePrivateData); } @@ -1259,7 +1286,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final ResearchLogger researchLogger = getInstance(); if (!replacedWord.equals(suggestion.toString())) { // The user chose something other than what was already there. - researchLogger.setCurrentLogUnitContainsCorrection(); + researchLogger.setCurrentLogUnitContainsUserDeletions(); researchLogger.setCurrentLogUnitCorrectionType(LogUnit.CORRECTIONTYPE_TYPO); } final String scrubbedWord = scrubDigitsFromString(suggestion); @@ -1291,17 +1318,32 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /** * Log a call to LatinIME.sendKeyCodePoint(). * - * SystemResponse: The IME is inserting text into the TextView for numbers, fixed strings, or - * some other unusual mechanism. + * SystemResponse: The IME is inserting text into the TextView for non-word-constituent, + * strings (separators, numbers, other symbols). */ private static final LogStatement LOGSTATEMENT_LATINIME_SENDKEYCODEPOINT = new LogStatement("LatinIMESendKeyCodePoint", true, false, "code"); public static void latinIME_sendKeyCodePoint(final int code) { final ResearchLogger researchLogger = getInstance(); - researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_SENDKEYCODEPOINT, - Constants.printableCode(scrubDigitFromCodePoint(code))); - if (Character.isDigit(code)) { - researchLogger.setCurrentLogUnitContainsDigitFlag(); + final LogUnit phantomSpaceLogUnit = researchLogger.mPhantomSpaceLogUnit; + if (phantomSpaceLogUnit == null) { + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_SENDKEYCODEPOINT, + Constants.printableCode(scrubDigitFromCodePoint(code))); + if (Character.isDigit(code)) { + researchLogger.setCurrentLogUnitContainsDigitFlag(); + } + researchLogger.commitCurrentLogUnit(); + } else { + researchLogger.enqueueEvent(phantomSpaceLogUnit, LOGSTATEMENT_LATINIME_SENDKEYCODEPOINT, + Constants.printableCode(scrubDigitFromCodePoint(code))); + if (Character.isDigit(code)) { + phantomSpaceLogUnit.setMayContainDigit(); + } + researchLogger.mMainLogBuffer.shiftIn(phantomSpaceLogUnit); + if (researchLogger.mUserRecordingLogBuffer != null) { + researchLogger.mUserRecordingLogBuffer.shiftIn(phantomSpaceLogUnit); + } + researchLogger.mPhantomSpaceLogUnit = null; } } @@ -1311,12 +1353,18 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang * SystemResponse: The IME is inserting a real space in place of a phantom space. */ private static final LogStatement LOGSTATEMENT_LATINIME_PROMOTEPHANTOMSPACE = - new LogStatement("LatinIMEPromotPhantomSpace", false, false); + new LogStatement("LatinIMEPromotePhantomSpace", false, false); public static void latinIME_promotePhantomSpace() { + // A phantom space is always added before the text that triggered it. The triggering text + // and the events that created it will be in mCurrentLogUnit, but the phantom space should + // be in its own LogUnit, committed before the triggering text. Although it is created + // here, it is not added to the LogBuffer until the following call to + // latinIME_sendKeyCodePoint, because SENDKEYCODEPOINT LogStatement also must go into that + // LogUnit. final ResearchLogger researchLogger = getInstance(); - final LogUnit logUnit; - logUnit = researchLogger.mMainLogBuffer.peekLastLogUnit(); - researchLogger.enqueueEvent(logUnit, LOGSTATEMENT_LATINIME_PROMOTEPHANTOMSPACE); + researchLogger.mPhantomSpaceLogUnit = new LogUnit(); + researchLogger.enqueueEvent(researchLogger.mPhantomSpaceLogUnit, + LOGSTATEMENT_LATINIME_PROMOTEPHANTOMSPACE); } /** @@ -1415,10 +1463,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord, separatorString); if (logUnit != null) { - logUnit.setContainsCorrection(); + logUnit.setContainsUserDeletions(); } researchLogger.mStatistics.recordRevertCommit(SystemClock.uptimeMillis()); - researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode); } /** @@ -1571,25 +1618,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private boolean isExpectingCommitText = false; - /** - * Log a call to (UnknownClass).commitPartialText - * - * SystemResponse: The IME is committing part of a word. This happens if a space is - * automatically inserted to split a single typed string into two or more words. - */ - // TODO: This method is currently unused. Find where it should be called from in the IME and - // add invocations. - private static final LogStatement LOGSTATEMENT_COMMIT_PARTIAL_TEXT = - new LogStatement("CommitPartialText", true, false, "newCursorPosition"); - public static void commitPartialText(final String committedWord, - final long lastTimestampOfWordData, final boolean isBatchMode) { - final ResearchLogger researchLogger = getInstance(); - final String scrubbedWord = scrubDigitsFromString(committedWord); - researchLogger.enqueueEvent(LOGSTATEMENT_COMMIT_PARTIAL_TEXT); - researchLogger.mStatistics.recordAutoCorrection(SystemClock.uptimeMillis()); - researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData, - isBatchMode); - } /** * Log a call to RichInputConnection.commitText(). @@ -1613,12 +1641,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } /** - * Shared event for logging committed text. + * Shared events for logging committed text. + * + * The "CommitTextEventHappened" LogStatement is written to the log even if privacy rules + * indicate that the word contents should not be logged. It has no contents, and only serves to + * record the event and thereby make it easier to calculate word-level statistics even when the + * word contents are unknown. */ private static final LogStatement LOGSTATEMENT_COMMITTEXT = - new LogStatement("CommitText", true, false, "committedText", "isBatchMode"); + new LogStatement("CommitText", true /* isPotentiallyPrivate */, + false /* isPotentiallyRevealing */, "committedText", "isBatchMode"); + private static final LogStatement LOGSTATEMENT_COMMITTEXT_EVENT_HAPPENED = + new LogStatement("CommitTextEventHappened", false /* isPotentiallyPrivate */, + false /* isPotentiallyRevealing */); private void enqueueCommitText(final String word, final boolean isBatchMode) { + // Event containing the word; will be published only if privacy checks pass enqueueEvent(LOGSTATEMENT_COMMITTEXT, word, isBatchMode); + // Event not containing the word; will always be published + enqueueEvent(LOGSTATEMENT_COMMITTEXT_EVENT_HAPPENED); } /** @@ -1837,6 +1877,20 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } /** + * Call this method when the logging system has attempted publication of an n-gram. + * + * Statistics are gathered about the success or failure. + * + * @param publishabilityResultCode a result code as defined by + * {@code MainLogBuffer.PUBLISHABILITY_*} + */ + static void recordPublishabilityResultCode(final int publishabilityResultCode) { + final ResearchLogger researchLogger = getInstance(); + final Statistics statistics = researchLogger.mStatistics; + statistics.recordPublishabilityResultCode(publishabilityResultCode); + } + + /** * Log statistics. * * ContextualData, recorded at the end of a session. @@ -1848,7 +1902,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete", "dictionaryWordCount", "splitWordsCount", "gestureInputCount", "gestureCharsCount", "gesturesDeletedCount", "manualSuggestionsCount", - "revertCommitsCount", "correctedWordsCount", "autoCorrectionsCount"); + "revertCommitsCount", "correctedWordsCount", "autoCorrectionsCount", + "publishableCount", "unpublishableStoppingCount", + "unpublishableIncorrectWordCount", "unpublishableSampledTooRecentlyCount", + "unpublishableDictionaryUnavailableCount", "unpublishableMayContainDigitCount", + "unpublishableNotInDictionaryCount"); private static void logStatistics() { final ResearchLogger researchLogger = getInstance(); final Statistics statistics = researchLogger.mStatistics; @@ -1863,6 +1921,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang statistics.mGesturesInputCount, statistics.mGesturesCharsCount, statistics.mGesturesDeletedCount, statistics.mManualSuggestionsCount, statistics.mRevertCommitsCount, statistics.mCorrectedWordsCount, - statistics.mAutoCorrectionsCount); + statistics.mAutoCorrectionsCount, statistics.mPublishableCount, + statistics.mUnpublishableStoppingCount, statistics.mUnpublishableIncorrectWordCount, + statistics.mUnpublishableSampledTooRecently, + statistics.mUnpublishableDictionaryUnavailable, + statistics.mUnpublishableMayContainDigit, statistics.mUnpublishableNotInDictionary); } } |