Loading java/src/com/android/inputmethod/research/ResearchLog.java +2 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,8 @@ public class ResearchLog { } catch (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 // uploaded. if (mFile != null && mFile.exists()) { mFile.setWritable(false, false); } Loading java/src/com/android/inputmethod/research/ResearchLogDirectory.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.research; import android.content.Context; import android.util.Log; import java.io.File; import java.io.FileFilter; /** * Manages log files. * * This class handles all aspects where and how research log data is stored. This includes * generating log filenames in the correct place with the correct names, and cleaning up log files * under this directory. */ public class ResearchLogDirectory { public static final String TAG = ResearchLogDirectory.class.getSimpleName(); /* package */ static final String LOG_FILENAME_PREFIX = "researchLog"; private static final String FILENAME_SUFFIX = ".txt"; private static final String USER_RECORDING_FILENAME_PREFIX = "recording"; private static final ReadOnlyLogFileFilter sUploadableLogFileFilter = new ReadOnlyLogFileFilter(); private final File mFilesDir; static class ReadOnlyLogFileFilter implements FileFilter { @Override public boolean accept(final File pathname) { return pathname.getName().startsWith(ResearchLogDirectory.LOG_FILENAME_PREFIX) && !pathname.canWrite(); } } /** * Creates a new ResearchLogDirectory, creating the storage directory if it does not exist. */ public ResearchLogDirectory(final Context context) { mFilesDir = getLoggingDirectory(context); if (mFilesDir == null) { throw new NullPointerException("No files directory specified"); } if (!mFilesDir.exists()) { mFilesDir.mkdirs(); } } private File getLoggingDirectory(final Context context) { // TODO: Switch to using a subdirectory of getFilesDir(). return context.getFilesDir(); } /** * Get an array of log files that are ready for uploading. * * A file is ready for uploading if it is marked as read-only. * * @return the array of uploadable files */ public File[] getUploadableLogFiles() { try { return mFilesDir.listFiles(sUploadableLogFileFilter); } catch (final SecurityException e) { Log.e(TAG, "Could not cleanup log directory, permission denied", e); return new File[0]; } } public void cleanupLogFilesOlderThan(final long time) { try { for (final File file : mFilesDir.listFiles()) { final String filename = file.getName(); if ((filename.startsWith(LOG_FILENAME_PREFIX) || filename.startsWith(USER_RECORDING_FILENAME_PREFIX)) && (file.lastModified() < time)) { file.delete(); } } } catch (final SecurityException e) { Log.e(TAG, "Could not cleanup log directory, permission denied", e); } } public File getLogFilePath(final long time) { return new File(mFilesDir, getUniqueFilename(LOG_FILENAME_PREFIX, time)); } public File getUserRecordingFilePath(final long time) { return new File(mFilesDir, getUniqueFilename(USER_RECORDING_FILENAME_PREFIX, time)); } private static String getUniqueFilename(final String prefix, final long time) { return prefix + "-" + time + FILENAME_SUFFIX; } } java/src/com/android/inputmethod/research/ResearchLogger.java +25 −68 Original line number Diff line number Diff line Loading @@ -125,12 +125,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /* package */ static boolean sIsLogging = false; private static final int OUTPUT_FORMAT_VERSION = 5; private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; /* 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 Loading @@ -156,12 +150,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final long RESEARCHLOG_CLOSE_TIMEOUT_IN_MS = 5 * 1000; private static final long RESEARCHLOG_ABORT_TIMEOUT_IN_MS = 5 * 1000; private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS; private static final long MAX_LOGFILE_AGE_IN_MS = 4 * DateUtils.DAY_IN_MILLIS; private static final ResearchLogger sInstance = new ResearchLogger(); private static String sAccountType = null; private static String sAllowedAccountDomain = null; // to write to a different filename, e.g., for testing, set mFile before calling start() /* package */ File mFilesDir; /* 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 Loading @@ -187,9 +181,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Character.codePointAt("\uE000", 0); // U+E000 is in the "private-use area" // U+E001 is in the "private-use area" /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001"; private static final String PREF_LAST_CLEANUP_TIME = "pref_last_cleanup_time"; private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS; private static final long MAX_LOGFILE_AGE_IN_MS = 4 * DateUtils.DAY_IN_MILLIS; protected static final int SUSPEND_DURATION_IN_MINUTES = 1; // set when LatinIME should ignore an onUpdateSelection() callback that // arises from operations in this class Loading @@ -203,6 +194,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private final Statistics mStatistics; private final MotionEventReader mMotionEventReader = new MotionEventReader(); private final Replayer mReplayer = Replayer.getInstance(); private ResearchLogDirectory mResearchLogDirectory; private Intent mUploadIntent; private Intent mUploadNowIntent; Loading Loading @@ -240,11 +232,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final Suggest suggest) { assert latinIME != null; 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); Loading @@ -256,15 +243,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang sAccountType = res.getString(R.string.research_account_type); sAllowedAccountDomain = res.getString(R.string.research_allowed_account_domain); // 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 directory manager mResearchLogDirectory = new ResearchLogDirectory(mLatinIME); cleanLogDirectoryIfNeeded(mResearchLogDirectory, System.currentTimeMillis()); // Initialize external services mUploadIntent = new Intent(mLatinIME, UploaderService.class); Loading @@ -276,6 +257,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mReplayer.setKeyboardSwitcher(keyboardSwitcher); } private void cleanLogDirectoryIfNeeded(final ResearchLogDirectory researchLogDirectory, final long now) { final long lastCleanupTime = ResearchSettings.readResearchLastDirCleanupTime(mPrefs); if (now - lastCleanupTime < DURATION_BETWEEN_DIR_CLEANUP_IN_MS) return; final long oldestAllowedFileTime = now - MAX_LOGFILE_AGE_IN_MS; mResearchLogDirectory.cleanupLogFilesOlderThan(oldestAllowedFileTime); ResearchSettings.writeResearchLastDirCleanupTime(mPrefs, now); } /** * Arrange for the UploaderService to be run on a regular basis. * Loading @@ -295,17 +285,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang UploaderService.RUN_INTERVAL, UploaderService.RUN_INTERVAL, pendingIntent); } private void cleanupLoggingDir(final File dir, final long time) { for (File file : dir.listFiles()) { final String filename = file.getName(); if ((filename.startsWith(ResearchLogger.LOG_FILENAME_PREFIX) || filename.startsWith(ResearchLogger.USER_RECORDING_FILENAME_PREFIX)) && file.lastModified() < time) { file.delete(); } } } public void mainKeyboardView_onAttachedToWindow(final MainKeyboardView mainKeyboardView) { mMainKeyboardView = mainKeyboardView; maybeShowSplashScreen(); Loading Loading @@ -387,35 +366,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang restart(); } private static int sLogFileCounter = 0; private File createLogFile(final File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(LOG_FILENAME_PREFIX).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. if (sLogFileCounter < Integer.MAX_VALUE) { sLogFileCounter++; } else { // Wrap the counter, in the unlikely event of overflow. sLogFileCounter = 0; } sb.append(sLogFileCounter); sb.append(LOG_FILENAME_SUFFIX); return new File(filesDir, sb.toString()); } private File createUserRecordingFile(final File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(USER_RECORDING_FILENAME_PREFIX).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()); private void setLoggingAllowed(final boolean enableLogging) { if (mPrefs == null) return; sIsLogging = enableLogging; ResearchSettings.writeResearchLoggerEnabledFlag(mPrefs, enableLogging); } private void checkForEmptyEditor() { Loading Loading @@ -455,7 +409,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return; } if (mMainLogBuffer == null) { mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); 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) { Loading Loading @@ -488,7 +443,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private void resetFeedbackLogging() { mFeedbackLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); mFeedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath( System.currentTimeMillis()), mLatinIME); mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE); } Loading Loading @@ -612,7 +568,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (mUserRecordingLog != null) { mUserRecordingLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS); } mUserRecordingFile = createUserRecordingFile(mFilesDir); mUserRecordingFile = mResearchLogDirectory.getUserRecordingFilePath( System.currentTimeMillis()); mUserRecordingLog = new ResearchLog(mUserRecordingFile, mLatinIME); mUserRecordingLogBuffer = new LogBuffer(); resetRecordingTimer(); Loading java/src/com/android/inputmethod/research/ResearchSettings.java +11 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ public final class ResearchSettings { "pref_research_logger_enabled_flag"; public static final String PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH = "pref_research_logger_has_seen_splash"; public static final String PREF_RESEARCH_LAST_DIR_CLEANUP_TIME = "pref_research_last_dir_cleanup_time"; private ResearchSettings() { // Intentional empty constructor for singleton. Loading Loading @@ -58,4 +60,13 @@ public final class ResearchSettings { final boolean hasSeenSplash) { prefs.edit().putBoolean(PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH, hasSeenSplash).apply(); } public static long readResearchLastDirCleanupTime(final SharedPreferences prefs) { return prefs.getLong(PREF_RESEARCH_LAST_DIR_CLEANUP_TIME, 0L); } public static void writeResearchLastDirCleanupTime(final SharedPreferences prefs, final long lastDirCleanupTime) { prefs.edit().putLong(PREF_RESEARCH_LAST_DIR_CLEANUP_TIME, lastDirCleanupTime).apply(); } } java/src/com/android/inputmethod/research/Uploader.java +4 −14 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.inputmethod.research; import android.Manifest; import android.app.AlarmManager; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading @@ -33,7 +32,6 @@ import com.android.inputmethod.latin.define.ProductionFlag; import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; Loading @@ -55,12 +53,12 @@ public final class Uploader { private static final int BUF_SIZE = 1024 * 8; private final Context mContext; private final File mFilesDir; private final ResearchLogDirectory mResearchLogDirectory; private final URL mUrl; public Uploader(final Context context) { mContext = context; mFilesDir = context.getFilesDir(); mResearchLogDirectory = new ResearchLogDirectory(context); final String urlString = context.getString(R.string.research_logger_upload_url); if (TextUtils.isEmpty(urlString)) { Loading Loading @@ -106,16 +104,8 @@ public final class Uploader { } public void doUpload() { if (mFilesDir == null) { return; } final File[] files = mFilesDir.listFiles(new FileFilter() { @Override public boolean accept(final File pathname) { return pathname.getName().startsWith(ResearchLogger.LOG_FILENAME_PREFIX) && !pathname.canWrite(); } }); final File[] files = mResearchLogDirectory.getUploadableLogFiles(); if (files == null) return; for (final File file : files) { uploadFile(file); } Loading Loading
java/src/com/android/inputmethod/research/ResearchLog.java +2 −0 Original line number Diff line number Diff line Loading @@ -118,6 +118,8 @@ public class ResearchLog { } catch (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 // uploaded. if (mFile != null && mFile.exists()) { mFile.setWritable(false, false); } Loading
java/src/com/android/inputmethod/research/ResearchLogDirectory.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.research; import android.content.Context; import android.util.Log; import java.io.File; import java.io.FileFilter; /** * Manages log files. * * This class handles all aspects where and how research log data is stored. This includes * generating log filenames in the correct place with the correct names, and cleaning up log files * under this directory. */ public class ResearchLogDirectory { public static final String TAG = ResearchLogDirectory.class.getSimpleName(); /* package */ static final String LOG_FILENAME_PREFIX = "researchLog"; private static final String FILENAME_SUFFIX = ".txt"; private static final String USER_RECORDING_FILENAME_PREFIX = "recording"; private static final ReadOnlyLogFileFilter sUploadableLogFileFilter = new ReadOnlyLogFileFilter(); private final File mFilesDir; static class ReadOnlyLogFileFilter implements FileFilter { @Override public boolean accept(final File pathname) { return pathname.getName().startsWith(ResearchLogDirectory.LOG_FILENAME_PREFIX) && !pathname.canWrite(); } } /** * Creates a new ResearchLogDirectory, creating the storage directory if it does not exist. */ public ResearchLogDirectory(final Context context) { mFilesDir = getLoggingDirectory(context); if (mFilesDir == null) { throw new NullPointerException("No files directory specified"); } if (!mFilesDir.exists()) { mFilesDir.mkdirs(); } } private File getLoggingDirectory(final Context context) { // TODO: Switch to using a subdirectory of getFilesDir(). return context.getFilesDir(); } /** * Get an array of log files that are ready for uploading. * * A file is ready for uploading if it is marked as read-only. * * @return the array of uploadable files */ public File[] getUploadableLogFiles() { try { return mFilesDir.listFiles(sUploadableLogFileFilter); } catch (final SecurityException e) { Log.e(TAG, "Could not cleanup log directory, permission denied", e); return new File[0]; } } public void cleanupLogFilesOlderThan(final long time) { try { for (final File file : mFilesDir.listFiles()) { final String filename = file.getName(); if ((filename.startsWith(LOG_FILENAME_PREFIX) || filename.startsWith(USER_RECORDING_FILENAME_PREFIX)) && (file.lastModified() < time)) { file.delete(); } } } catch (final SecurityException e) { Log.e(TAG, "Could not cleanup log directory, permission denied", e); } } public File getLogFilePath(final long time) { return new File(mFilesDir, getUniqueFilename(LOG_FILENAME_PREFIX, time)); } public File getUserRecordingFilePath(final long time) { return new File(mFilesDir, getUniqueFilename(USER_RECORDING_FILENAME_PREFIX, time)); } private static String getUniqueFilename(final String prefix, final long time) { return prefix + "-" + time + FILENAME_SUFFIX; } }
java/src/com/android/inputmethod/research/ResearchLogger.java +25 −68 Original line number Diff line number Diff line Loading @@ -125,12 +125,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /* package */ static boolean sIsLogging = false; private static final int OUTPUT_FORMAT_VERSION = 5; private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; /* 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 Loading @@ -156,12 +150,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final long RESEARCHLOG_CLOSE_TIMEOUT_IN_MS = 5 * 1000; private static final long RESEARCHLOG_ABORT_TIMEOUT_IN_MS = 5 * 1000; private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS; private static final long MAX_LOGFILE_AGE_IN_MS = 4 * DateUtils.DAY_IN_MILLIS; private static final ResearchLogger sInstance = new ResearchLogger(); private static String sAccountType = null; private static String sAllowedAccountDomain = null; // to write to a different filename, e.g., for testing, set mFile before calling start() /* package */ File mFilesDir; /* 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 Loading @@ -187,9 +181,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Character.codePointAt("\uE000", 0); // U+E000 is in the "private-use area" // U+E001 is in the "private-use area" /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001"; private static final String PREF_LAST_CLEANUP_TIME = "pref_last_cleanup_time"; private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS; private static final long MAX_LOGFILE_AGE_IN_MS = 4 * DateUtils.DAY_IN_MILLIS; protected static final int SUSPEND_DURATION_IN_MINUTES = 1; // set when LatinIME should ignore an onUpdateSelection() callback that // arises from operations in this class Loading @@ -203,6 +194,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private final Statistics mStatistics; private final MotionEventReader mMotionEventReader = new MotionEventReader(); private final Replayer mReplayer = Replayer.getInstance(); private ResearchLogDirectory mResearchLogDirectory; private Intent mUploadIntent; private Intent mUploadNowIntent; Loading Loading @@ -240,11 +232,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final Suggest suggest) { assert latinIME != null; 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); Loading @@ -256,15 +243,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang sAccountType = res.getString(R.string.research_account_type); sAllowedAccountDomain = res.getString(R.string.research_allowed_account_domain); // 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 directory manager mResearchLogDirectory = new ResearchLogDirectory(mLatinIME); cleanLogDirectoryIfNeeded(mResearchLogDirectory, System.currentTimeMillis()); // Initialize external services mUploadIntent = new Intent(mLatinIME, UploaderService.class); Loading @@ -276,6 +257,15 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mReplayer.setKeyboardSwitcher(keyboardSwitcher); } private void cleanLogDirectoryIfNeeded(final ResearchLogDirectory researchLogDirectory, final long now) { final long lastCleanupTime = ResearchSettings.readResearchLastDirCleanupTime(mPrefs); if (now - lastCleanupTime < DURATION_BETWEEN_DIR_CLEANUP_IN_MS) return; final long oldestAllowedFileTime = now - MAX_LOGFILE_AGE_IN_MS; mResearchLogDirectory.cleanupLogFilesOlderThan(oldestAllowedFileTime); ResearchSettings.writeResearchLastDirCleanupTime(mPrefs, now); } /** * Arrange for the UploaderService to be run on a regular basis. * Loading @@ -295,17 +285,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang UploaderService.RUN_INTERVAL, UploaderService.RUN_INTERVAL, pendingIntent); } private void cleanupLoggingDir(final File dir, final long time) { for (File file : dir.listFiles()) { final String filename = file.getName(); if ((filename.startsWith(ResearchLogger.LOG_FILENAME_PREFIX) || filename.startsWith(ResearchLogger.USER_RECORDING_FILENAME_PREFIX)) && file.lastModified() < time) { file.delete(); } } } public void mainKeyboardView_onAttachedToWindow(final MainKeyboardView mainKeyboardView) { mMainKeyboardView = mainKeyboardView; maybeShowSplashScreen(); Loading Loading @@ -387,35 +366,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang restart(); } private static int sLogFileCounter = 0; private File createLogFile(final File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(LOG_FILENAME_PREFIX).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. if (sLogFileCounter < Integer.MAX_VALUE) { sLogFileCounter++; } else { // Wrap the counter, in the unlikely event of overflow. sLogFileCounter = 0; } sb.append(sLogFileCounter); sb.append(LOG_FILENAME_SUFFIX); return new File(filesDir, sb.toString()); } private File createUserRecordingFile(final File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(USER_RECORDING_FILENAME_PREFIX).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()); private void setLoggingAllowed(final boolean enableLogging) { if (mPrefs == null) return; sIsLogging = enableLogging; ResearchSettings.writeResearchLoggerEnabledFlag(mPrefs, enableLogging); } private void checkForEmptyEditor() { Loading Loading @@ -455,7 +409,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang return; } if (mMainLogBuffer == null) { mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); 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) { Loading Loading @@ -488,7 +443,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private void resetFeedbackLogging() { mFeedbackLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); mFeedbackLog = new ResearchLog(mResearchLogDirectory.getLogFilePath( System.currentTimeMillis()), mLatinIME); mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE); } Loading Loading @@ -612,7 +568,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (mUserRecordingLog != null) { mUserRecordingLog.blockingAbort(RESEARCHLOG_ABORT_TIMEOUT_IN_MS); } mUserRecordingFile = createUserRecordingFile(mFilesDir); mUserRecordingFile = mResearchLogDirectory.getUserRecordingFilePath( System.currentTimeMillis()); mUserRecordingLog = new ResearchLog(mUserRecordingFile, mLatinIME); mUserRecordingLogBuffer = new LogBuffer(); resetRecordingTimer(); Loading
java/src/com/android/inputmethod/research/ResearchSettings.java +11 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ public final class ResearchSettings { "pref_research_logger_enabled_flag"; public static final String PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH = "pref_research_logger_has_seen_splash"; public static final String PREF_RESEARCH_LAST_DIR_CLEANUP_TIME = "pref_research_last_dir_cleanup_time"; private ResearchSettings() { // Intentional empty constructor for singleton. Loading Loading @@ -58,4 +60,13 @@ public final class ResearchSettings { final boolean hasSeenSplash) { prefs.edit().putBoolean(PREF_RESEARCH_LOGGER_HAS_SEEN_SPLASH, hasSeenSplash).apply(); } public static long readResearchLastDirCleanupTime(final SharedPreferences prefs) { return prefs.getLong(PREF_RESEARCH_LAST_DIR_CLEANUP_TIME, 0L); } public static void writeResearchLastDirCleanupTime(final SharedPreferences prefs, final long lastDirCleanupTime) { prefs.edit().putLong(PREF_RESEARCH_LAST_DIR_CLEANUP_TIME, lastDirCleanupTime).apply(); } }
java/src/com/android/inputmethod/research/Uploader.java +4 −14 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.inputmethod.research; import android.Manifest; import android.app.AlarmManager; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading @@ -33,7 +32,6 @@ import com.android.inputmethod.latin.define.ProductionFlag; import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; Loading @@ -55,12 +53,12 @@ public final class Uploader { private static final int BUF_SIZE = 1024 * 8; private final Context mContext; private final File mFilesDir; private final ResearchLogDirectory mResearchLogDirectory; private final URL mUrl; public Uploader(final Context context) { mContext = context; mFilesDir = context.getFilesDir(); mResearchLogDirectory = new ResearchLogDirectory(context); final String urlString = context.getString(R.string.research_logger_upload_url); if (TextUtils.isEmpty(urlString)) { Loading Loading @@ -106,16 +104,8 @@ public final class Uploader { } public void doUpload() { if (mFilesDir == null) { return; } final File[] files = mFilesDir.listFiles(new FileFilter() { @Override public boolean accept(final File pathname) { return pathname.getName().startsWith(ResearchLogger.LOG_FILENAME_PREFIX) && !pathname.canWrite(); } }); final File[] files = mResearchLogDirectory.getUploadableLogFiles(); if (files == null) return; for (final File file : files) { uploadFile(file); } Loading