diff options
Diffstat (limited to 'java/src/com/android/inputmethod/research/ResearchLogger.java')
-rw-r--r-- | java/src/com/android/inputmethod/research/ResearchLogger.java | 167 |
1 files changed, 68 insertions, 99 deletions
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index 45212913e..e705ddda1 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -88,6 +88,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Random; import java.util.UUID; /** @@ -121,31 +122,36 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // field holds a channel name, the developer does not have to re-enter it when using the // feedback mechanism to generate multiple tests. private static final boolean FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD = false; - public static final boolean DEFAULT_USABILITY_STUDY_MODE = 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"; - private static final String PREF_RESEARCH_HAS_SEEN_SPLASH = "pref_research_has_seen_splash"; /* package */ static final String LOG_FILENAME_PREFIX = "researchLog"; private static final String LOG_FILENAME_SUFFIX = ".txt"; /* package */ static final String USER_RECORDING_FILENAME_PREFIX = "recording"; private static final String USER_RECORDING_FILENAME_SUFFIX = ".txt"; private static final SimpleDateFormat TIMESTAMP_DATEFORMAT = new SimpleDateFormat("yyyyMMddHHmmssS", Locale.US); + // Whether all words should be recorded, leaving unsampled word between bigrams. Useful for + // testing. + /* package for test */ static final boolean IS_LOGGING_EVERYTHING = false + && ProductionFlag.IS_EXPERIMENTAL_DEBUG; + // The number of words between n-grams to omit from the log. + private static final int NUMBER_OF_WORDS_BETWEEN_SAMPLES = + IS_LOGGING_EVERYTHING ? 0 : (DEBUG ? 2 : 18); + // Whether to show an indicator on the screen that logging is on. Currently a very small red // dot in the lower right hand corner. Most users should not notice it. private static final boolean IS_SHOWING_INDICATOR = true; // Change the default indicator to something very visible. Currently two red vertical bars on // either side of they keyboard. private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || - (MainLogBuffer.IS_LOGGING_EVERYTHING && ProductionFlag.IS_EXPERIMENTAL_DEBUG); + (IS_LOGGING_EVERYTHING && ProductionFlag.IS_EXPERIMENTAL_DEBUG); // FEEDBACK_WORD_BUFFER_SIZE should add 1 because it must also hold the feedback LogUnit itself. public static final int FEEDBACK_WORD_BUFFER_SIZE = (Integer.MAX_VALUE - 1) + 1; // 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 String PREF_RESEARCH_SAVED_CHANNEL = "pref_research_saved_channel"; private static final ResearchLogger sInstance = new ResearchLogger(); @@ -153,7 +159,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static String sAllowedAccountDomain = null; // to write to a different filename, e.g., for testing, set mFile before calling start() /* package */ File mFilesDir; - /* package */ String mUUIDString; /* package */ ResearchLog mMainResearchLog; // mFeedbackLog records all events for the session, private or not (excepting // passwords). It is written to permanent storage only if the user explicitly commands @@ -199,7 +204,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private Intent mUploadIntent; private Intent mUploadNowIntent; - private LogUnit mCurrentLogUnit = new LogUnit(); + /* package for test */ LogUnit mCurrentLogUnit = new LogUnit(); // Gestured or tapped words may be committed after the gesture of the next word has started. // To ensure that the gesture data of the next word is not associated with the previous word, @@ -228,50 +233,44 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return sInstance; } - public void init(final LatinIME latinIME, final KeyboardSwitcher keyboardSwitcher) { + public void init(final LatinIME latinIME, final KeyboardSwitcher keyboardSwitcher, + final Suggest suggest) { assert latinIME != null; - if (latinIME == null) { - Log.w(TAG, "IMS is null; logging is off"); - } else { - mFilesDir = latinIME.getFilesDir(); - if (mFilesDir == null || !mFilesDir.exists()) { - Log.w(TAG, "IME storage directory does not exist."); - } - } - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIME); - if (prefs != null) { - mUUIDString = getUUID(prefs); - if (!prefs.contains(PREF_USABILITY_STUDY_MODE)) { - Editor e = prefs.edit(); - e.putBoolean(PREF_USABILITY_STUDY_MODE, DEFAULT_USABILITY_STUDY_MODE); - e.apply(); - } - sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); - prefs.registerOnSharedPreferenceChangeListener(this); - - final long lastCleanupTime = prefs.getLong(PREF_LAST_CLEANUP_TIME, 0L); - final long now = System.currentTimeMillis(); - if (lastCleanupTime + DURATION_BETWEEN_DIR_CLEANUP_IN_MS < now) { - final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS; - cleanupLoggingDir(mFilesDir, timeHorizon); - Editor e = prefs.edit(); - e.putLong(PREF_LAST_CLEANUP_TIME, now); - e.apply(); - } + mLatinIME = latinIME; + mFilesDir = latinIME.getFilesDir(); + if (mFilesDir == null || !mFilesDir.exists()) { + Log.w(TAG, "IME storage directory does not exist. Cannot start logging."); + return; } + mPrefs = PreferenceManager.getDefaultSharedPreferences(latinIME); + mPrefs.registerOnSharedPreferenceChangeListener(this); + + // Initialize fields from preferences + sIsLogging = ResearchSettings.readResearchLoggerEnabledFlag(mPrefs); + + // Initialize fields from resources final Resources res = latinIME.getResources(); sAccountType = res.getString(R.string.research_account_type); sAllowedAccountDomain = res.getString(R.string.research_allowed_account_domain); - mLatinIME = latinIME; - mPrefs = prefs; + + // Cleanup logging directory + // TODO: Move this and other file-related components to separate file. + final long lastCleanupTime = mPrefs.getLong(PREF_LAST_CLEANUP_TIME, 0L); + final long now = System.currentTimeMillis(); + if (now - lastCleanupTime > DURATION_BETWEEN_DIR_CLEANUP_IN_MS) { + final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS; + cleanupLoggingDir(mFilesDir, timeHorizon); + mPrefs.edit().putLong(PREF_LAST_CLEANUP_TIME, now).apply(); + } + + // Initialize external services mUploadIntent = new Intent(mLatinIME, UploaderService.class); mUploadNowIntent = new Intent(mLatinIME, UploaderService.class); mUploadNowIntent.putExtra(UploaderService.EXTRA_UPLOAD_UNCONDITIONALLY, true); - mReplayer.setKeyboardSwitcher(keyboardSwitcher); - if (ProductionFlag.IS_EXPERIMENTAL) { scheduleUploadingService(mLatinIME); } + mReplayer.setKeyboardSwitcher(keyboardSwitcher); } /** @@ -313,14 +312,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mMainKeyboardView = null; } - private boolean hasSeenSplash() { - return mPrefs.getBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, false); + public void onDestroy() { + if (mPrefs != null) { + mPrefs.unregisterOnSharedPreferenceChangeListener(this); + } } private Dialog mSplashDialog = null; private void maybeShowSplashScreen() { - if (hasSeenSplash()) { + if (ResearchSettings.readHasSeenSplash(mPrefs)) { return; } if (mSplashDialog != null && mSplashDialog.isShowing()) { @@ -373,32 +374,23 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } public void onUserLoggingConsent() { - setLoggingAllowed(true); if (mPrefs == null) { - return; + mPrefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); + if (mPrefs == null) return; } - final Editor e = mPrefs.edit(); - e.putBoolean(PREF_RESEARCH_HAS_SEEN_SPLASH, true); - e.apply(); + sIsLogging = true; + ResearchSettings.writeResearchLoggerEnabledFlag(mPrefs, true); + ResearchSettings.writeHasSeenSplash(mPrefs, true); restart(); } - 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 static int sLogFileCounter = 0; private File createLogFile(final File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(LOG_FILENAME_PREFIX).append('-'); - sb.append(mUUIDString).append('-'); + final String uuid = ResearchSettings.readResearchLoggerUuid(mPrefs); + sb.append(uuid).append('-'); sb.append(TIMESTAMP_DATEFORMAT.format(new Date())).append('-'); // Sometimes logFiles are created within milliseconds of each other. Append a counter to // separate these. @@ -416,7 +408,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private File createUserRecordingFile(final File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(USER_RECORDING_FILENAME_PREFIX).append('-'); - sb.append(mUUIDString).append('-'); + final String uuid = ResearchSettings.readResearchLoggerUuid(mPrefs); + sb.append(uuid).append('-'); sb.append(TIMESTAMP_DATEFORMAT.format(new Date())); sb.append(USER_RECORDING_FILENAME_SUFFIX); return new File(filesDir, sb.toString()); @@ -458,17 +451,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang // Log.w(TAG, "not in usability mode; not logging"); return; } - if (mFilesDir == null || !mFilesDir.exists()) { - Log.w(TAG, "IME storage directory does not exist. Cannot start logging."); - return; - } if (mMainLogBuffer == null) { mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); - mMainLogBuffer = new MainLogBuffer() { + 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 |= MainLogBuffer.IS_LOGGING_EVERYTHING; + canIncludePrivateData |= IS_LOGGING_EVERYTHING; final int length = logUnits.size(); for (int i = 0; i < length; i++) { final LogUnit logUnit = logUnits.get(i); @@ -487,7 +478,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } }; - mMainLogBuffer.setSuggest(mSuggest); } if (mFeedbackLogBuffer == null) { resetFeedbackLogging(); @@ -564,7 +554,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } @Override - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { if (key == null || prefs == null) { return; } @@ -586,7 +576,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang presentFeedbackDialog(latinIME); } - public void presentFeedbackDialog(LatinIME latinIME) { + public void presentFeedbackDialog(final LatinIME latinIME) { if (isMakingUserRecording()) { saveRecording(); } @@ -818,9 +808,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (mPrefs == null) { return; } - final Editor e = mPrefs.edit(); - e.putString(PREF_RESEARCH_SAVED_CHANNEL, channelName); - e.apply(); + mPrefs.edit().putString(PREF_RESEARCH_SAVED_CHANNEL, channelName).apply(); } } @@ -835,10 +823,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mInFeedbackDialog = false; } - public void initSuggest(Suggest suggest) { + 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. if (mMainLogBuffer != null) { - mMainLogBuffer.setSuggest(mSuggest); + stop(); + start(); } } @@ -1127,18 +1118,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } - private static String getUUID(final SharedPreferences prefs) { - String uuidString = prefs.getString(PREF_RESEARCH_LOGGER_UUID_STRING, null); - if (null == uuidString) { - UUID uuid = UUID.randomUUID(); - uuidString = uuid.toString(); - Editor editor = prefs.edit(); - editor.putString(PREF_RESEARCH_LOGGER_UUID_STRING, uuidString); - editor.apply(); - } - return uuidString; - } - private String scrubWord(String word) { final Dictionary dictionary = getDictionary(); if (dictionary == null) { @@ -1185,12 +1164,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang 0); final Integer versionCode = packageInfo.versionCode; final String versionName = packageInfo.versionName; + final String uuid = ResearchSettings.readResearchLoggerUuid(researchLogger.mPrefs); researchLogger.enqueueEvent(LOGSTATEMENT_LATIN_IME_ON_START_INPUT_VIEW_INTERNAL, - researchLogger.mUUIDString, editorInfo.packageName, - Integer.toHexString(editorInfo.inputType), + uuid, editorInfo.packageName, Integer.toHexString(editorInfo.inputType), Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, - OUTPUT_FORMAT_VERSION, MainLogBuffer.IS_LOGGING_EVERYTHING, + OUTPUT_FORMAT_VERSION, IS_LOGGING_EVERYTHING, ProductionFlag.IS_EXPERIMENTAL_DEBUG); } catch (NameNotFoundException e) { e.printStackTrace(); @@ -1226,17 +1205,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action, final long eventTime, final int index, final int id, final int x, final int y) { if (me != null) { - final String actionString; - switch (action) { - case MotionEvent.ACTION_CANCEL: actionString = "CANCEL"; break; - case MotionEvent.ACTION_UP: actionString = "UP"; break; - case MotionEvent.ACTION_DOWN: actionString = "DOWN"; break; - case MotionEvent.ACTION_POINTER_UP: actionString = "POINTER_UP"; break; - case MotionEvent.ACTION_POINTER_DOWN: actionString = "POINTER_DOWN"; break; - case MotionEvent.ACTION_MOVE: actionString = "MOVE"; break; - case MotionEvent.ACTION_OUTSIDE: actionString = "OUTSIDE"; break; - default: actionString = "ACTION_" + action; break; - } + final String actionString = LoggingUtils.getMotionEventActionTypeString(action); final ResearchLogger researchLogger = getInstance(); researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT, actionString, false /* IS_LOGGING_RELATED */, MotionEvent.obtain(me)); |