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.java465
1 files changed, 165 insertions, 300 deletions
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index b5bdc1958..3cad2d099 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -67,11 +67,8 @@ import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.define.ProductionFlag;
import java.io.File;
-import java.io.IOException;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Date;
-import java.util.List;
import java.util.Locale;
import java.util.UUID;
@@ -97,24 +94,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US);
private static final boolean IS_SHOWING_INDICATOR = true;
private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false;
+ public static final int FEEDBACK_WORD_BUFFER_SIZE = 5;
// constants related to specific log points
private static final String WHITESPACE_SEPARATORS = " \t\n\r";
private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1
private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid";
- private static final int ABORT_TIMEOUT_IN_MS = 10 * 1000; // timeout to notify user
private static final ResearchLogger sInstance = new ResearchLogger();
// to write to a different filename, e.g., for testing, set mFile before calling start()
/* package */ File mFilesDir;
/* package */ String mUUIDString;
/* package */ ResearchLog mMainResearchLog;
- // The mIntentionalResearchLog 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.
- /* package */ ResearchLog mIntentionalResearchLog;
- // LogUnits are queued here and released only when the user requests the intentional log.
- private List<LogUnit> mIntentionalResearchLogQueue = new ArrayList<LogUnit>();
+ /* package */ ResearchLog mFeedbackLog;
+ /* package */ MainLogBuffer mMainLogBuffer;
+ /* package */ LogBuffer mFeedbackLogBuffer;
private boolean mIsPasswordView = false;
private boolean mIsLoggingSuspended = false;
@@ -139,9 +133,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private KeyboardSwitcher mKeyboardSwitcher;
private InputMethodService mInputMethodService;
private final Statistics mStatistics;
-
private ResearchLogUploader mResearchLogUploader;
+ private LogUnit mCurrentLogUnit = new LogUnit();
+
private ResearchLogger() {
mStatistics = Statistics.getInstance();
}
@@ -264,6 +259,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
e.apply();
}
+ private void setLoggingAllowed(boolean enableLogging) {
+ if (mPrefs == null) {
+ return;
+ }
+ Editor e = mPrefs.edit();
+ e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging);
+ e.apply();
+ sIsLogging = enableLogging;
+ }
+
private File createLogFile(File filesDir) {
final StringBuilder sb = new StringBuilder();
sb.append(FILENAME_PREFIX).append('-');
@@ -310,97 +315,58 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Log.w(TAG, "IME storage directory does not exist. Cannot start logging.");
return;
}
- try {
- if (mMainResearchLog == null || !mMainResearchLog.isAlive()) {
- mMainResearchLog = new ResearchLog(createLogFile(mFilesDir));
- }
- mMainResearchLog.start();
- if (mIntentionalResearchLog == null || !mIntentionalResearchLog.isAlive()) {
- mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir));
- }
- mIntentionalResearchLog.start();
- } catch (IOException e) {
- Log.w(TAG, "Could not start ResearchLogger.");
+ if (mMainLogBuffer == null) {
+ mMainResearchLog = new ResearchLog(createLogFile(mFilesDir));
+ mMainLogBuffer = new MainLogBuffer(mMainResearchLog);
+ mMainLogBuffer.setSuggest(mSuggest);
+ }
+ if (mFeedbackLogBuffer == null) {
+ mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
+ // LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold
+ // the feedback LogUnit itself.
+ mFeedbackLogBuffer = new LogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
}
}
/* package */ void stop() {
logStatistics();
- publishLogUnit(mCurrentLogUnit, true);
- mCurrentLogUnit = new LogUnit();
+ commitCurrentLogUnit();
- if (mMainResearchLog != null) {
- mMainResearchLog.stop();
- }
- if (mIntentionalResearchLog != null) {
- mIntentionalResearchLog.stop();
+ if (mMainLogBuffer != null) {
+ publishLogBuffer(mMainLogBuffer, mMainResearchLog, false /* isIncludingPrivateData */);
+ mMainResearchLog.close();
+ mMainLogBuffer = null;
}
- }
-
- private static final String[] EVENTKEYS_STATISTICS = {
- "Statistics", "charCount", "letterCount", "numberCount", "spaceCount", "deleteOpsCount",
- "wordCount", "isEmptyUponStarting", "isEmptinessStateKnown", "averageTimeBetweenKeys",
- "averageTimeBeforeDelete", "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete"
- };
- private static void logStatistics() {
- final ResearchLogger researchLogger = getInstance();
- final Statistics statistics = researchLogger.mStatistics;
- final Object[] values = {
- statistics.mCharCount, statistics.mLetterCount, statistics.mNumberCount,
- statistics.mSpaceCount, statistics.mDeleteKeyCount,
- statistics.mWordCount, statistics.mIsEmptyUponStarting,
- statistics.mIsEmptinessStateKnown, statistics.mKeyCounter.getAverageTime(),
- statistics.mBeforeDeleteKeyCounter.getAverageTime(),
- statistics.mDuringRepeatedDeleteKeysCounter.getAverageTime(),
- statistics.mAfterDeleteKeyCounter.getAverageTime()
- };
- researchLogger.enqueueEvent(EVENTKEYS_STATISTICS, values);
- }
-
- private void setLoggingAllowed(boolean enableLogging) {
- if (mPrefs == null) {
- return;
+ if (mFeedbackLogBuffer != null) {
+ mFeedbackLog.close();
+ mFeedbackLogBuffer = null;
}
- Editor e = mPrefs.edit();
- e.putBoolean(PREF_USABILITY_STUDY_MODE, enableLogging);
- e.apply();
- sIsLogging = enableLogging;
}
public boolean abort() {
boolean didAbortMainLog = false;
- if (mMainResearchLog != null) {
- mMainResearchLog.abort();
+ if (mMainLogBuffer != null) {
+ mMainLogBuffer.clear();
try {
- mMainResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS);
+ didAbortMainLog = mMainResearchLog.blockingAbort();
} catch (InterruptedException e) {
- // interrupted early. carry on.
- }
- if (mMainResearchLog.isAbortSuccessful()) {
- didAbortMainLog = true;
+ // Don't know whether this succeeded or not. We assume not; this is reported
+ // to the caller.
}
- mMainResearchLog = null;
+ mMainLogBuffer = null;
}
- boolean didAbortIntentionalLog = false;
- if (mIntentionalResearchLog != null) {
- mIntentionalResearchLog.abort();
+ boolean didAbortFeedbackLog = false;
+ if (mFeedbackLogBuffer != null) {
+ mFeedbackLogBuffer.clear();
try {
- mIntentionalResearchLog.waitUntilStopped(ABORT_TIMEOUT_IN_MS);
+ didAbortFeedbackLog = mFeedbackLog.blockingAbort();
} catch (InterruptedException e) {
- // interrupted early. carry on.
+ // Don't know whether this succeeded or not. We assume not; this is reported
+ // to the caller.
}
- if (mIntentionalResearchLog.isAbortSuccessful()) {
- didAbortIntentionalLog = true;
- }
- mIntentionalResearchLog = null;
- }
- return didAbortMainLog && didAbortIntentionalLog;
- }
-
- /* package */ void flush() {
- if (mMainResearchLog != null) {
- mMainResearchLog.flush();
+ mFeedbackLogBuffer = null;
}
+ return didAbortMainLog && didAbortFeedbackLog;
}
private void restart() {
@@ -504,79 +470,39 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
latinIME.launchKeyboardedDialogActivity(FeedbackActivity.class);
}
- private ResearchLog mFeedbackLog;
- private List<LogUnit> mFeedbackQueue;
- private ResearchLog mSavedMainResearchLog;
- private ResearchLog mSavedIntentionalResearchLog;
- private List<LogUnit> mSavedIntentionalResearchLogQueue;
-
- private void saveLogsForFeedback() {
- mFeedbackLog = mIntentionalResearchLog;
- if (mIntentionalResearchLogQueue != null) {
- mFeedbackQueue = new ArrayList<LogUnit>(mIntentionalResearchLogQueue);
- } else {
- mFeedbackQueue = null;
- }
- mSavedMainResearchLog = mMainResearchLog;
- mSavedIntentionalResearchLog = mIntentionalResearchLog;
- mSavedIntentionalResearchLogQueue = mIntentionalResearchLogQueue;
-
- mMainResearchLog = null;
- mIntentionalResearchLog = null;
- mIntentionalResearchLogQueue = new ArrayList<LogUnit>();
- }
-
- private static final int LOG_DRAIN_TIMEOUT_IN_MS = 1000 * 5;
+ private static final String[] EVENTKEYS_FEEDBACK = {
+ "UserTimestamp", "contents"
+ };
public void sendFeedback(final String feedbackContents, final boolean includeHistory) {
- if (includeHistory && mFeedbackLog != null) {
- try {
- LogUnit headerLogUnit = new LogUnit();
- headerLogUnit.addLogAtom(EVENTKEYS_INTENTIONAL_LOG, EVENTKEYS_NULLVALUES, false);
- mFeedbackLog.publishAllEvents(headerLogUnit);
- for (LogUnit logUnit : mFeedbackQueue) {
- mFeedbackLog.publishAllEvents(logUnit);
- }
- userFeedback(mFeedbackLog, feedbackContents);
- mFeedbackLog.stop();
- try {
- mFeedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- mIntentionalResearchLog = new ResearchLog(createLogFile(mFilesDir));
- mIntentionalResearchLog.start();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- mIntentionalResearchLogQueue.clear();
- }
- mResearchLogUploader.uploadNow(null);
- } else {
- // create a separate ResearchLog just for feedback
- final ResearchLog feedbackLog = new ResearchLog(createLogFile(mFilesDir));
- try {
- feedbackLog.start();
- userFeedback(feedbackLog, feedbackContents);
- feedbackLog.stop();
- feedbackLog.waitUntilStopped(LOG_DRAIN_TIMEOUT_IN_MS);
- mResearchLogUploader.uploadNow(null);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ if (mFeedbackLogBuffer == null) {
+ return;
+ }
+ if (!includeHistory) {
+ mFeedbackLogBuffer.clear();
}
+ commitCurrentLogUnit();
+ final LogUnit feedbackLogUnit = new LogUnit();
+ final Object[] values = {
+ feedbackContents
+ };
+ feedbackLogUnit.addLogStatement(EVENTKEYS_FEEDBACK, values,
+ false /* isPotentiallyPrivate */);
+ mFeedbackLogBuffer.shiftIn(feedbackLogUnit);
+ publishLogBuffer(mFeedbackLogBuffer, mFeedbackLog, true /* isIncludingPrivateData */);
+ mFeedbackLog.close();
+ mResearchLogUploader.uploadAfterCompletion(mFeedbackLog, null);
+ mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
}
public void onLeavingSendFeedbackDialog() {
mInFeedbackDialog = false;
- mMainResearchLog = mSavedMainResearchLog;
- mIntentionalResearchLog = mSavedIntentionalResearchLog;
- mIntentionalResearchLogQueue = mSavedIntentionalResearchLogQueue;
}
public void initSuggest(Suggest suggest) {
mSuggest = suggest;
+ if (mMainLogBuffer != null) {
+ mMainLogBuffer.setSuggest(mSuggest);
+ }
}
private void setIsPasswordView(boolean isPasswordView) {
@@ -584,7 +510,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
private boolean isAllowedToLog() {
- return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging;
+ return !mIsPasswordView && !mIsLoggingSuspended && sIsLogging && !mInFeedbackDialog;
}
public void requestIndicatorRedraw() {
@@ -631,13 +557,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
}
- private static final String CURRENT_TIME_KEY = "_ct";
- private static final String UPTIME_KEY = "_ut";
- private static final String EVENT_TYPE_KEY = "_ty";
private static final Object[] EVENTKEYS_NULLVALUES = {};
- private LogUnit mCurrentLogUnit = new LogUnit();
-
/**
* Buffer a research log event, flagging it as privacy-sensitive.
*
@@ -653,10 +574,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values) {
assert values.length + 1 == keys.length;
if (isAllowedToLog()) {
- mCurrentLogUnit.addLogAtom(keys, values, true);
+ mCurrentLogUnit.addLogStatement(keys, values, true /* isPotentiallyPrivate */);
}
}
+ private void setCurrentLogUnitContainsDigitFlag() {
+ mCurrentLogUnit.setContainsDigit();
+ }
+
/**
* Buffer a research log event, flaggint it as not privacy-sensitive.
*
@@ -672,140 +597,54 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private synchronized void enqueueEvent(final String[] keys, final Object[] values) {
assert values.length + 1 == keys.length;
if (isAllowedToLog()) {
- mCurrentLogUnit.addLogAtom(keys, values, false);
+ mCurrentLogUnit.addLogStatement(keys, values, false /* isPotentiallyPrivate */);
}
}
- // Used to track how often words are logged. Too-frequent logging can leak
- // semantics, disclosing private data.
- /* package for test */ static class LoggingFrequencyState {
- private static final int DEFAULT_WORD_LOG_FREQUENCY = 10;
- private int mWordsRemainingToSkip;
- private final int mFrequency;
-
- /**
- * Tracks how often words may be uploaded.
- *
- * @param frequency 1=Every word, 2=Every other word, etc.
- */
- public LoggingFrequencyState(int frequency) {
- mFrequency = frequency;
- mWordsRemainingToSkip = mFrequency;
- }
-
- public void onWordLogged() {
- mWordsRemainingToSkip = mFrequency;
- }
-
- public void onWordNotLogged() {
- if (mWordsRemainingToSkip > 1) {
- mWordsRemainingToSkip--;
+ /* package for test */ void commitCurrentLogUnit() {
+ if (!mCurrentLogUnit.isEmpty()) {
+ if (mMainLogBuffer != null) {
+ mMainLogBuffer.shiftIn(mCurrentLogUnit);
+ if (mMainLogBuffer.isSafeToLog() && mMainResearchLog != null) {
+ publishLogBuffer(mMainLogBuffer, mMainResearchLog,
+ true /* isIncludingPrivateData */);
+ mMainLogBuffer.resetWordCounter();
+ }
+ }
+ if (mFeedbackLogBuffer != null) {
+ mFeedbackLogBuffer.shiftIn(mCurrentLogUnit);
}
+ mCurrentLogUnit = new LogUnit();
+ Log.d(TAG, "commitCurrentLogUnit");
}
+ }
- public boolean isSafeToLog() {
- return mWordsRemainingToSkip <= 1;
+ /* package for test */ void publishLogBuffer(final LogBuffer logBuffer,
+ final ResearchLog researchLog, final boolean isIncludingPrivateData) {
+ LogUnit logUnit;
+ while ((logUnit = logBuffer.shiftOut()) != null) {
+ researchLog.publish(logUnit, isIncludingPrivateData);
}
}
- /* package for test */ LoggingFrequencyState mLoggingFrequencyState =
- new LoggingFrequencyState(LoggingFrequencyState.DEFAULT_WORD_LOG_FREQUENCY);
-
- /* package for test */ boolean isPrivacyThreat(String word) {
- // Current checks:
- // - Word not in dictionary
- // - Word contains numbers
- // - Privacy-safe word not logged recently
- if (TextUtils.isEmpty(word)) {
- return false;
- }
- if (!mLoggingFrequencyState.isSafeToLog()) {
- return true;
- }
+ private boolean hasOnlyLetters(final String word) {
final int length = word.length();
- boolean hasLetter = false;
for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
- final int codePoint = Character.codePointAt(word, i);
- if (Character.isDigit(codePoint)) {
- return true;
- }
- if (Character.isLetter(codePoint)) {
- hasLetter = true;
- break; // Word may contain digits, but will only be allowed if in the dictionary.
- }
- }
- if (hasLetter) {
- if (mDictionary == null && mSuggest != null && mSuggest.hasMainDictionary()) {
- mDictionary = mSuggest.getMainDictionary();
+ final int codePoint = word.codePointAt(i);
+ if (!Character.isLetter(codePoint)) {
+ return false;
}
- if (mDictionary == null) {
- // Can't access dictionary. Assume privacy threat.
- return true;
- }
- return !(mDictionary.isValidWord(word));
- }
- // No letters, no numbers. Punctuation, space, or something else.
- return false;
- }
-
- private void onWordComplete(String word) {
- if (isPrivacyThreat(word)) {
- publishLogUnit(mCurrentLogUnit, true);
- mLoggingFrequencyState.onWordNotLogged();
- } else {
- publishLogUnit(mCurrentLogUnit, false);
- mLoggingFrequencyState.onWordLogged();
}
- mCurrentLogUnit = new LogUnit();
- mStatistics.recordWordEntered();
+ return true;
}
- private void publishLogUnit(LogUnit logUnit, boolean isPrivacySensitive) {
- if (!isAllowedToLog()) {
- return;
- }
- if (mMainResearchLog == null) {
- return;
- }
- if (isPrivacySensitive) {
- mMainResearchLog.publishPublicEvents(logUnit);
- } else {
- mMainResearchLog.publishAllEvents(logUnit);
- }
- mIntentionalResearchLogQueue.add(logUnit);
- }
-
- /* package */ void publishCurrentLogUnit(ResearchLog researchLog, boolean isPrivacySensitive) {
- publishLogUnit(mCurrentLogUnit, isPrivacySensitive);
- }
-
- static class LogUnit {
- private final List<String[]> mKeysList = new ArrayList<String[]>();
- private final List<Object[]> mValuesList = new ArrayList<Object[]>();
- private final List<Boolean> mIsPotentiallyPrivate = new ArrayList<Boolean>();
-
- private void addLogAtom(final String[] keys, final Object[] values,
- final Boolean isPotentiallyPrivate) {
- mKeysList.add(keys);
- mValuesList.add(values);
- mIsPotentiallyPrivate.add(isPotentiallyPrivate);
- }
-
- public void publishPublicEventsTo(ResearchLog researchLog) {
- final int size = mKeysList.size();
- for (int i = 0; i < size; i++) {
- if (!mIsPotentiallyPrivate.get(i)) {
- researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i));
- }
- }
- }
-
- public void publishAllEventsTo(ResearchLog researchLog) {
- final int size = mKeysList.size();
- for (int i = 0; i < size; i++) {
- researchLog.outputEvent(mKeysList.get(i), mValuesList.get(i));
- }
+ private void onWordComplete(final String word) {
+ Log.d(TAG, "onWordComplete: " + word);
+ if (word != null && word.length() > 0 && hasOnlyLetters(word)) {
+ mCurrentLogUnit.setWord(word);
+ mStatistics.recordWordEntered();
}
+ commitCurrentLogUnit();
}
private static int scrubDigitFromCodePoint(int codePoint) {
@@ -858,12 +697,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return WORD_REPLACEMENT_STRING;
}
- // Special methods related to startup, shutdown, logging itself
-
- private static final String[] EVENTKEYS_INTENTIONAL_LOG = {
- "IntentionalLog"
- };
-
private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = {
"LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions",
"fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion"
@@ -871,9 +704,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo,
final SharedPreferences prefs) {
final ResearchLogger researchLogger = getInstance();
- if (researchLogger.mInFeedbackDialog) {
- researchLogger.saveLogsForFeedback();
- }
researchLogger.start();
if (editorInfo != null) {
final Context context = researchLogger.mInputMethodService;
@@ -905,16 +735,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
"UserFeedback", "FeedbackContents"
};
- private void userFeedback(ResearchLog researchLog, String feedbackContents) {
- // this method is special; it directs the feedbackContents to a particular researchLog
- final LogUnit logUnit = new LogUnit();
- final Object[] values = {
- feedbackContents
- };
- logUnit.addLogAtom(EVENTKEYS_USER_FEEDBACK, values, false);
- researchLog.publishAllEvents(logUnit);
- }
-
// Regular logging methods
private static final String[] EVENTKEYS_MAINKEYBOARDVIEW_PROCESSMOTIONEVENT = {
@@ -949,12 +769,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
"LatinIMEOnCodeInput", "code", "x", "y"
};
public static void latinIME_onCodeInput(final int code, final int x, final int y) {
+ final long time = SystemClock.uptimeMillis();
+ final ResearchLogger researchLogger = getInstance();
final Object[] values = {
Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y
};
- final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values);
- researchLogger.mStatistics.recordChar(code, SystemClock.uptimeMillis());
+ if (Character.isDigit(code)) {
+ researchLogger.setCurrentLogUnitContainsDigitFlag();
+ }
+ researchLogger.mStatistics.recordChar(code, time);
}
private static final String[] EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS = {
@@ -1019,9 +843,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
}
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
- // Play it safe. Remove privacy-sensitive events.
- researchLogger.publishLogUnit(researchLogger.mCurrentLogUnit, true);
- researchLogger.mCurrentLogUnit = new LogUnit();
+ researchLogger.commitCurrentLogUnit();
getInstance().stop();
}
}
@@ -1086,7 +908,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
Keyboard.printableCode(scrubDigitFromCodePoint(code))
};
- getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
+ if (Character.isDigit(code)) {
+ researchLogger.setCurrentLogUnitContainsDigitFlag();
+ }
}
private static final String[] EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACE = {
@@ -1224,10 +1050,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
EVENTKEYS_RICHINPUTCONNECTION_COMMITCOMPLETION, values);
}
+ // Disabled for privacy-protection reasons. Because this event comes after
+ // richInputConnection_commitText, which is the event used to separate LogUnits, the
+ // data in this event can be associated with the next LogUnit, revealing information
+ // about the current word even if it was supposed to be suppressed. The occurrance of
+ // autocorrection can be determined by examining the difference between the text strings in
+ // the last call to richInputConnection_setComposingText before
+ // richInputConnection_commitText, so it's not a data loss.
+ // TODO: Figure out how to log this event without loss of privacy.
+ /*
private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITCORRECTION = {
- "RichInputConnectionCommitCorrection", "CorrectionInfo"
+ "RichInputConnectionCommitCorrection", "typedWord", "autoCorrection"
};
+ */
public static void richInputConnection_commitCorrection(CorrectionInfo correctionInfo) {
+ /*
final String typedWord = correctionInfo.getOldText().toString();
final String autoCorrection = correctionInfo.getNewText().toString();
final Object[] values = {
@@ -1236,6 +1073,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final ResearchLogger researchLogger = getInstance();
researchLogger.enqueuePotentiallyPrivateEvent(
EVENTKEYS_RICHINPUTCONNECTION_COMMITCORRECTION, values);
+ */
}
private static final String[] EVENTKEYS_RICHINPUTCONNECTION_COMMITTEXT = {
@@ -1261,7 +1099,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
beforeLength, afterLength
};
- getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_RICHINPUTCONNECTION_DELETESURROUNDINGTEXT, values);
}
private static final String[] EVENTKEYS_RICHINPUTCONNECTION_FINISHCOMPOSINGTEXT = {
@@ -1291,7 +1130,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
keyEvent.getAction(),
keyEvent.getKeyCode()
};
- getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_SENDKEYEVENT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SENDKEYEVENT,
+ values);
}
private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT = {
@@ -1299,10 +1139,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
};
public static void richInputConnection_setComposingText(final CharSequence text,
final int newCursorPosition) {
+ if (text == null) {
+ throw new RuntimeException("setComposingText is null");
+ }
final Object[] values = {
text, newCursorPosition
};
- getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SETCOMPOSINGTEXT,
+ values);
}
private static final String[] EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION = {
@@ -1312,7 +1156,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
from, to
};
- getInstance().enqueueEvent(EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_RICHINPUTCONNECTION_SETSELECTION,
+ values);
}
private static final String[] EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT = {
@@ -1347,4 +1192,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public void userTimestamp() {
getInstance().enqueueEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES);
}
+
+ private static final String[] EVENTKEYS_STATISTICS = {
+ "Statistics", "charCount", "letterCount", "numberCount", "spaceCount", "deleteOpsCount",
+ "wordCount", "isEmptyUponStarting", "isEmptinessStateKnown", "averageTimeBetweenKeys",
+ "averageTimeBeforeDelete", "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete"
+ };
+ private static void logStatistics() {
+ final ResearchLogger researchLogger = getInstance();
+ final Statistics statistics = researchLogger.mStatistics;
+ final Object[] values = {
+ statistics.mCharCount, statistics.mLetterCount, statistics.mNumberCount,
+ statistics.mSpaceCount, statistics.mDeleteKeyCount,
+ statistics.mWordCount, statistics.mIsEmptyUponStarting,
+ statistics.mIsEmptinessStateKnown, statistics.mKeyCounter.getAverageTime(),
+ statistics.mBeforeDeleteKeyCounter.getAverageTime(),
+ statistics.mDuringRepeatedDeleteKeysCounter.getAverageTime(),
+ statistics.mAfterDeleteKeyCounter.getAverageTime()
+ };
+ researchLogger.enqueueEvent(EVENTKEYS_STATISTICS, values);
+ }
}