diff options
Diffstat (limited to 'java/src/com/android/inputmethod/research/ResearchLogger.java')
-rw-r--r-- | java/src/com/android/inputmethod/research/ResearchLogger.java | 192 |
1 files changed, 132 insertions, 60 deletions
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index a46216c5e..2da571d5a 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -1,23 +1,25 @@ /* * Copyright (C) 2012 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 + * 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 + * 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. + * 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 static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; +import android.accounts.Account; +import android.accounts.AccountManager; import android.app.AlarmManager; import android.app.AlertDialog; import android.app.Dialog; @@ -30,6 +32,7 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -69,7 +72,9 @@ import com.android.inputmethod.latin.define.ProductionFlag; import java.io.File; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Locale; import java.util.UUID; @@ -84,9 +89,6 @@ import java.util.UUID; public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = ResearchLogger.class.getSimpleName(); private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; - // Whether all n-grams should be logged. true will disclose private info. - public static final boolean IS_LOGGING_EVERYTHING = false - && ProductionFlag.IS_EXPERIMENTAL_DEBUG; // Whether the TextView contents are logged at the end of the session. true will disclose // private info. private static final boolean LOG_FULL_TEXTVIEW_CONTENTS = false @@ -105,7 +107,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang 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 || IS_LOGGING_EVERYTHING; + private static final boolean IS_SHOWING_INDICATOR_CLEARLY = false || + (MainLogBuffer.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; @@ -115,6 +118,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String PREF_RESEARCH_LOGGER_UUID_STRING = "pref_research_logger_uuid"; 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 */ String mUUIDString; @@ -199,6 +204,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang e.apply(); } } + 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; mUploadIntent = new Intent(mLatinIME, UploaderService.class); @@ -387,15 +395,41 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } if (mMainLogBuffer == null) { mMainResearchLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); - mMainLogBuffer = new MainLogBuffer(mMainResearchLog); + mMainLogBuffer = new MainLogBuffer() { + @Override + protected void publish(final ArrayList<LogUnit> logUnits, + boolean canIncludePrivateData) { + canIncludePrivateData |= MainLogBuffer.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); + } + } + }; mMainLogBuffer.setSuggest(mSuggest); } if (mFeedbackLogBuffer == null) { - mFeedbackLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); - mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE); + resetFeedbackLogging(); } } + private void resetFeedbackLogging() { + mFeedbackLog = new ResearchLog(createLogFile(mFilesDir), mLatinIME); + mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE); + } + /* package */ void stop() { if (DEBUG) { Log.d(TAG, "stop called"); @@ -404,16 +438,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang commitCurrentLogUnit(); if (mMainLogBuffer != null) { - while (!mMainLogBuffer.isEmpty()) { - if ((mMainLogBuffer.isNGramSafe() || IS_LOGGING_EVERYTHING) && - mMainResearchLog != null) { - publishLogBuffer(mMainLogBuffer, mMainResearchLog, - true /* isIncludingPrivateData */); - mMainLogBuffer.resetWordCounter(); - } else { - mMainLogBuffer.shiftOutThroughFirstWord(); - } - } + mMainLogBuffer.shiftAndPublishAll(); + logStatistics(); + commitCurrentLogUnit(); + mMainLogBuffer.setIsStopping(); + mMainLogBuffer.shiftAndPublishAll(); mMainResearchLog.close(null /* callback */); mMainLogBuffer = null; } @@ -572,6 +601,36 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } */ + /** + * Get the name of the first allowed account on the device. + * + * Allowed accounts must be in the domain given by ALLOWED_ACCOUNT_DOMAIN. + * + * @return The user's account name. + */ + public String getAccountName() { + if (sAccountType == null || sAccountType.isEmpty()) { + return null; + } + if (sAllowedAccountDomain == null || sAllowedAccountDomain.isEmpty()) { + return null; + } + final AccountManager manager = AccountManager.get(mLatinIME); + // Filter first by account type. + final Account[] accounts = manager.getAccountsByType(sAccountType); + + for (final Account account : accounts) { + if (DEBUG) { + Log.d(TAG, account.name); + } + final String[] parts = account.name.split("@"); + if (parts.length > 1 && parts[1].equals(sAllowedAccountDomain)) { + return parts[0]; + } + } + return null; + } + static class LogStatement { final String mName; @@ -605,8 +664,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } private static final LogStatement LOGSTATEMENT_FEEDBACK = - new LogStatement("UserFeedback", false, false, "contents"); - public void sendFeedback(final String feedbackContents, final boolean includeHistory) { + new LogStatement("UserFeedback", false, false, "contents", "accountName"); + public void sendFeedback(final String feedbackContents, final boolean includeHistory, + final boolean isIncludingAccountName) { if (mSavedFeedbackLogBuffer == null) { return; } @@ -614,8 +674,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mSavedFeedbackLogBuffer.clear(); } final LogUnit feedbackLogUnit = new LogUnit(); + final String accountName = isIncludingAccountName ? getAccountName() : ""; feedbackLogUnit.addLogStatement(LOGSTATEMENT_FEEDBACK, SystemClock.uptimeMillis(), - feedbackContents); + feedbackContents, accountName); mFeedbackLogBuffer.shiftIn(feedbackLogUnit); publishLogBuffer(mFeedbackLogBuffer, mSavedFeedbackLog, true /* isIncludingPrivateData */); mSavedFeedbackLog.close(new Runnable() { @@ -731,13 +792,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } if (!mCurrentLogUnit.isEmpty()) { if (mMainLogBuffer != null) { - if ((mMainLogBuffer.isNGramSafe() || IS_LOGGING_EVERYTHING) && - mMainLogBuffer.isNGramComplete() && - mMainResearchLog != null) { - publishLogBuffer(mMainLogBuffer, mMainResearchLog, - true /* isIncludingPrivateData */); - mMainLogBuffer.resetWordCounter(); - } mMainLogBuffer.shiftIn(mCurrentLogUnit); } if (mFeedbackLogBuffer != null) { @@ -798,33 +852,39 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } } + /* package for test */ void publishLogBuffer(final LogBuffer logBuffer, + final ResearchLog researchLog, final boolean isIncludingPrivateData) { + publishLogUnits(logBuffer.getLogUnits(), researchLog, isIncludingPrivateData); + } + private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_OPENING = new LogStatement("logSegmentStart", false, false, "isIncludingPrivateData"); private static final LogStatement LOGSTATEMENT_LOG_SEGMENT_CLOSING = new LogStatement("logSegmentEnd", false, false); - /* package for test */ void publishLogBuffer(final LogBuffer logBuffer, - final ResearchLog researchLog, final boolean isIncludingPrivateData) { + /* package for test */ void publishLogUnits(final List<LogUnit> logUnits, + final ResearchLog researchLog, final boolean canIncludePrivateData) { final LogUnit openingLogUnit = new LogUnit(); - if (logBuffer.isEmpty()) return; - openingLogUnit.addLogStatement(LOGSTATEMENT_LOG_SEGMENT_OPENING, SystemClock.uptimeMillis(), - isIncludingPrivateData); - researchLog.publish(openingLogUnit, true /* isIncludingPrivateData */); - LogUnit logUnit; - int numWordsToPublish = MainLogBuffer.N_GRAM_SIZE; - while ((logUnit = logBuffer.shiftOut()) != null && numWordsToPublish > 0) { + if (logUnits.isEmpty()) return; + // LogUnits not containing private data, such as contextual data for the log, do not require + // logSegment boundary statements. + if (canIncludePrivateData) { + openingLogUnit.addLogStatement(LOGSTATEMENT_LOG_SEGMENT_OPENING, + SystemClock.uptimeMillis(), canIncludePrivateData); + researchLog.publish(openingLogUnit, true /* isIncludingPrivateData */); + } + for (LogUnit logUnit : logUnits) { if (DEBUG) { Log.d(TAG, "publishLogBuffer: " + (logUnit.hasWord() ? logUnit.getWord() - : "<wordless>")); - } - researchLog.publish(logUnit, isIncludingPrivateData); - if (logUnit.getWord() != null) { - numWordsToPublish--; + : "<wordless>") + ", correction?: " + logUnit.containsCorrection()); } + researchLog.publish(logUnit, canIncludePrivateData); + } + if (canIncludePrivateData) { + final LogUnit closingLogUnit = new LogUnit(); + closingLogUnit.addLogStatement(LOGSTATEMENT_LOG_SEGMENT_CLOSING, + SystemClock.uptimeMillis()); + researchLog.publish(closingLogUnit, true /* isIncludingPrivateData */); } - final LogUnit closingLogUnit = new LogUnit(); - closingLogUnit.addLogStatement(LOGSTATEMENT_LOG_SEGMENT_CLOSING, - SystemClock.uptimeMillis()); - researchLog.publish(closingLogUnit, true /* isIncludingPrivateData */); } public static boolean hasLetters(final String word) { @@ -849,12 +909,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (word == null) { return; } - final Dictionary dictionary = getDictionary(); if (word.length() > 0 && hasLetters(word)) { mCurrentLogUnit.setWord(word); - final boolean isDictionaryWord = dictionary != null - && dictionary.isValidWord(word); - mStatistics.recordWordEntered(isDictionaryWord, mCurrentLogUnit.containsCorrection()); } final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); enqueueCommitText(word, isBatchMode); @@ -967,7 +1023,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Integer.toHexString(editorInfo.inputType), Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, - OUTPUT_FORMAT_VERSION, IS_LOGGING_EVERYTHING, + OUTPUT_FORMAT_VERSION, MainLogBuffer.IS_LOGGING_EVERYTHING, ProductionFlag.IS_EXPERIMENTAL_DEBUG); } catch (NameNotFoundException e) { e.printStackTrace(); @@ -976,7 +1032,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } public void latinIME_onFinishInputViewInternal() { - logStatistics(); stop(); } @@ -1524,6 +1579,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang public static void richInputConnection_commitText(final String committedWord, final int newCursorPosition, final boolean isBatchMode) { final ResearchLogger researchLogger = getInstance(); + // Only include opening and closing logSegments if private data is included final String scrubbedWord = scrubDigitsFromString(committedWord); if (!researchLogger.isExpectingCommitText) { researchLogger.enqueueEvent(LOGSTATEMENT_RICHINPUTCONNECTIONCOMMITTEXT, @@ -1728,7 +1784,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang /** * Record the current time in case the LogUnit is later split. * - * If the current logUnitis split, then tapping, motion events, etc. before this time should + * If the current logUnit is split, then tapping, motion events, etc. before this time should * be assigned to one LogUnit, and events after this time should go into the following LogUnit. */ public static void recordTimeForLogUnitSplit() { @@ -1738,6 +1794,22 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang } /** + * Log a call to LatinIME.handleSeparator() + * + * SystemResponse: The system is inserting a separator character, possibly performing auto- + * correction or other actions appropriate at the end of a word. + */ + private static final LogStatement LOGSTATEMENT_LATINIME_HANDLESEPARATOR = + new LogStatement("LatinIMEHandleSeparator", false, false, "primaryCode", + "isComposingWord"); + public static void latinIME_handleSeparator(final int primaryCode, + final boolean isComposingWord) { + final ResearchLogger researchLogger = getInstance(); + researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_HANDLESEPARATOR, primaryCode, + isComposingWord); + } + + /** * Log statistics. * * ContextualData, recorded at the end of a session. |