am bd99e8dc: am 41b34cf2: Merge "Allow LogUnits to hold >1 word"

* commit 'bd99e8dc246faeafa5849078dce47fb379d23eb1':
  Allow LogUnits to hold >1 word
main
Kurt Partridge 2013-05-15 10:52:51 -07:00 committed by Android Git Automerger
commit 6f3b9ddd76
4 changed files with 147 additions and 86 deletions

View File

@ -57,28 +57,29 @@ public class FixedLogBuffer extends LogBuffer {
*/ */
@Override @Override
public void shiftIn(final LogUnit newLogUnit) { public void shiftIn(final LogUnit newLogUnit) {
if (!newLogUnit.hasWord()) { if (!newLogUnit.hasOneOrMoreWords()) {
// This LogUnit isn't a word, so it doesn't count toward the word-limit. // This LogUnit doesn't contain any word, so it doesn't count toward the word-limit.
super.shiftIn(newLogUnit); super.shiftIn(newLogUnit);
return; return;
} }
final int numWordsIncoming = newLogUnit.getNumWords();
if (mNumActualWords >= mWordCapacity) { if (mNumActualWords >= mWordCapacity) {
// Give subclass a chance to handle the buffer full condition by shifting out logUnits. // Give subclass a chance to handle the buffer full condition by shifting out logUnits.
onBufferFull(); onBufferFull();
// If still full, evict. // If still full, evict.
if (mNumActualWords >= mWordCapacity) { if (mNumActualWords >= mWordCapacity) {
shiftOutWords(1); shiftOutWords(numWordsIncoming);
} }
} }
super.shiftIn(newLogUnit); super.shiftIn(newLogUnit);
mNumActualWords++; // Must be a word, or we wouldn't be here. mNumActualWords += numWordsIncoming;
} }
@Override @Override
public LogUnit unshiftIn() { public LogUnit unshiftIn() {
final LogUnit logUnit = super.unshiftIn(); final LogUnit logUnit = super.unshiftIn();
if (logUnit != null && logUnit.hasWord()) { if (logUnit != null && logUnit.hasOneOrMoreWords()) {
mNumActualWords--; mNumActualWords -= logUnit.getNumWords();
} }
return logUnit; return logUnit;
} }
@ -109,8 +110,8 @@ public class FixedLogBuffer extends LogBuffer {
@Override @Override
public LogUnit shiftOut() { public LogUnit shiftOut() {
final LogUnit logUnit = super.shiftOut(); final LogUnit logUnit = super.shiftOut();
if (logUnit != null && logUnit.hasWord()) { if (logUnit != null && logUnit.hasOneOrMoreWords()) {
mNumActualWords--; mNumActualWords -= logUnit.getNumWords();
} }
return logUnit; return logUnit;
} }
@ -121,15 +122,15 @@ public class FixedLogBuffer extends LogBuffer {
* If there are less than {@code numWords} word-containing {@link LogUnit}s, shifts out * If there are less than {@code numWords} word-containing {@link LogUnit}s, shifts out
* all {@code LogUnit}s in the buffer. * all {@code LogUnit}s in the buffer.
* *
* @param numWords the number of word-containing {@link LogUnit}s to shift out * @param numWords the minimum number of word-containing {@link LogUnit}s to shift out
* @return the number of actual {@code LogUnit}s shifted out * @return the number of actual {@code LogUnit}s shifted out
*/ */
protected int shiftOutWords(final int numWords) { protected int shiftOutWords(final int numWords) {
int numWordContainingLogUnitsShiftedOut = 0; int numWordContainingLogUnitsShiftedOut = 0;
for (LogUnit logUnit = shiftOut(); logUnit != null for (LogUnit logUnit = shiftOut(); logUnit != null
&& numWordContainingLogUnitsShiftedOut < numWords; logUnit = shiftOut()) { && numWordContainingLogUnitsShiftedOut < numWords; logUnit = shiftOut()) {
if (logUnit.hasWord()) { if (logUnit.hasOneOrMoreWords()) {
numWordContainingLogUnitsShiftedOut++; numWordContainingLogUnitsShiftedOut += logUnit.getNumWords();
} }
} }
return numWordContainingLogUnitsShiftedOut; return numWordContainingLogUnitsShiftedOut;
@ -144,27 +145,31 @@ public class FixedLogBuffer extends LogBuffer {
} }
/** /**
* Returns a list of {@link LogUnit}s at the front of the buffer that have associated words. No * Returns a list of {@link LogUnit}s at the front of the buffer that have words associated with
* more than {@code n} LogUnits will have words associated with them. If there are not enough * them.
* LogUnits in the buffer to meet the word requirement, returns the all LogUnits. *
* There will be no more than {@code n} words in the returned list. So if 2 words are
* requested, and the first LogUnit has 3 words, it is not returned. If 2 words are requested,
* and the first LogUnit has only 1 word, and the next LogUnit 2 words, only the first LogUnit
* is returned. If the first LogUnit has no words associated with it, and the second LogUnit
* has three words, then only the first LogUnit (which has no associated words) is returned. If
* there are not enough LogUnits in the buffer to meet the word requirement, then all LogUnits
* will be returned.
* *
* @param n The maximum number of {@link LogUnit}s with words to return. * @param n The maximum number of {@link LogUnit}s with words to return.
* @return The list of the {@link LogUnit}s containing the first n words * @return The list of the {@link LogUnit}s containing the first n words
*/ */
public ArrayList<LogUnit> peekAtFirstNWords(int n) { public ArrayList<LogUnit> peekAtFirstNWords(int n) {
final LinkedList<LogUnit> logUnits = getLogUnits(); final LinkedList<LogUnit> logUnits = getLogUnits();
final int length = logUnits.size();
// Allocate space for n*2 logUnits. There will be at least n, one for each word, and // Allocate space for n*2 logUnits. There will be at least n, one for each word, and
// there may be additional for punctuation, between-word commands, etc. This should be // there may be additional for punctuation, between-word commands, etc. This should be
// enough that reallocation won't be necessary. // enough that reallocation won't be necessary.
final ArrayList<LogUnit> list = new ArrayList<LogUnit>(n * 2); final ArrayList<LogUnit> resultList = new ArrayList<LogUnit>(n * 2);
for (int i = 0; i < length && n > 0; i++) { for (final LogUnit logUnit : logUnits) {
final LogUnit logUnit = logUnits.get(i); n -= logUnit.getNumWords();
list.add(logUnit); if (n < 0) break;
if (logUnit.hasWord()) { resultList.add(logUnit);
n--;
} }
} return resultList;
return list;
} }
} }

View File

@ -25,10 +25,10 @@ import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.define.ProductionFlag;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Pattern;
/** /**
* A group of log statements related to each other. * A group of log statements related to each other.
@ -49,27 +49,45 @@ public class LogUnit {
private static final boolean DEBUG = false private static final boolean DEBUG = false
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG; && ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+");
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final ArrayList<LogStatement> mLogStatementList; private final ArrayList<LogStatement> mLogStatementList;
private final ArrayList<Object[]> mValuesList; private final ArrayList<Object[]> mValuesList;
// Assume that mTimeList is sorted in increasing order. Do not insert null values into // Assume that mTimeList is sorted in increasing order. Do not insert null values into
// mTimeList. // mTimeList.
private final ArrayList<Long> mTimeList; private final ArrayList<Long> mTimeList;
// Word that this LogUnit generates. Should be null if the LogUnit does not generate a genuine // Words that this LogUnit generates. Should be null if the data in the LogUnit does not
// word (i.e. separators alone do not count as a word). Should never be empty. // generate a genuine word (i.e. separators alone do not count as a word). Should never be
private String mWord; // empty. Note that if the user types spaces explicitly, then normally mWords should contain
// only a single word; it will only contain space-separate multiple words if the user does not
// enter a space, and the system enters one automatically.
private String mWords;
private String[] mWordArray = EMPTY_STRING_ARRAY;
private boolean mMayContainDigit; private boolean mMayContainDigit;
private boolean mIsPartOfMegaword; private boolean mIsPartOfMegaword;
private boolean mContainsCorrection; private boolean mContainsCorrection;
// mCorrectionType indicates whether the word was corrected at all, and if so, whether it was // mCorrectionType indicates whether the word was corrected at all, and if so, the nature of the
// to a different word or just a "typo" correction. It is considered a "typo" if the final // correction.
// word was listed in the suggestions available the first time the word was gestured or
// tapped.
private int mCorrectionType; private int mCorrectionType;
// LogUnits start in this state. If a word is entered without being corrected, it will have
// this CorrectiontType.
public static final int CORRECTIONTYPE_NO_CORRECTION = 0; public static final int CORRECTIONTYPE_NO_CORRECTION = 0;
// The LogUnit was corrected manually by the user in an unspecified way.
public static final int CORRECTIONTYPE_CORRECTION = 1; public static final int CORRECTIONTYPE_CORRECTION = 1;
// The LogUnit was corrected manually by the user to a word not in the list of suggestions of
// the first word typed here. (Note: this is a heuristic value, it may be incorrect, for
// example, if the user repositions the cursor).
public static final int CORRECTIONTYPE_DIFFERENT_WORD = 2; public static final int CORRECTIONTYPE_DIFFERENT_WORD = 2;
// The LogUnit was corrected manually by the user to a word that was in the list of suggestions
// of the first word typed here. (Again, a heuristic). It is probably a typo correction.
public static final int CORRECTIONTYPE_TYPO = 3; public static final int CORRECTIONTYPE_TYPO = 3;
// TODO: Rather than just tracking the current state, keep a historical record of the LogUnit's
// state and statistics. This should include how many times it has been corrected, whether
// other LogUnit edits were done between edits to this LogUnit, etc. Also track when a LogUnit
// previously contained a word, but was corrected to empty (because it was deleted, and there is
// no known replacement).
private SuggestedWords mSuggestedWords; private SuggestedWords mSuggestedWords;
@ -166,7 +184,7 @@ public class LogUnit {
final LogStatement logStatement; final LogStatement logStatement;
if (canIncludePrivateData) { if (canIncludePrivateData) {
LOGSTATEMENT_LOG_UNIT_BEGIN_WITH_PRIVATE_DATA.outputToLocked(jsonWriter, LOGSTATEMENT_LOG_UNIT_BEGIN_WITH_PRIVATE_DATA.outputToLocked(jsonWriter,
SystemClock.uptimeMillis(), getWord(), getCorrectionType()); SystemClock.uptimeMillis(), getWordsAsString(), getCorrectionType());
} else { } else {
LOGSTATEMENT_LOG_UNIT_BEGIN_WITHOUT_PRIVATE_DATA.outputToLocked(jsonWriter, LOGSTATEMENT_LOG_UNIT_BEGIN_WITHOUT_PRIVATE_DATA.outputToLocked(jsonWriter,
SystemClock.uptimeMillis()); SystemClock.uptimeMillis());
@ -181,22 +199,22 @@ public class LogUnit {
} }
/** /**
* Mark the current logUnit as containing data to generate {@code word}. * Mark the current logUnit as containing data to generate {@code newWords}.
* *
* If {@code setWord()} was previously called for this LogUnit, then the method will try to * If {@code setWord()} was previously called for this LogUnit, then the method will try to
* determine what kind of correction it is, and update its internal state of the correctionType * determine what kind of correction it is, and update its internal state of the correctionType
* accordingly. * accordingly.
* *
* @param word The word this LogUnit generates. Caller should not pass null or the empty * @param newWords The words this LogUnit generates. Caller should not pass null or the empty
* string. * string.
*/ */
public void setWord(final String word) { public void setWords(final String newWords) {
if (hasWord()) { if (hasOneOrMoreWords()) {
// The word was already set once, and it is now being changed. See if the new word // The word was already set once, and it is now being changed. See if the new word
// is close to the old word. If so, then the change is probably a typo correction. // is close to the old word. If so, then the change is probably a typo correction.
// If not, the user may have decided to enter a different word, so flag it. // If not, the user may have decided to enter a different word, so flag it.
if (mSuggestedWords != null) { if (mSuggestedWords != null) {
if (isInSuggestedWords(word, mSuggestedWords)) { if (isInSuggestedWords(newWords, mSuggestedWords)) {
mCorrectionType = CORRECTIONTYPE_TYPO; mCorrectionType = CORRECTIONTYPE_TYPO;
} else { } else {
mCorrectionType = CORRECTIONTYPE_DIFFERENT_WORD; mCorrectionType = CORRECTIONTYPE_DIFFERENT_WORD;
@ -206,38 +224,71 @@ public class LogUnit {
// Mark it as a generic correction. // Mark it as a generic correction.
mCorrectionType = CORRECTIONTYPE_CORRECTION; mCorrectionType = CORRECTIONTYPE_CORRECTION;
} }
} else {
mCorrectionType = CORRECTIONTYPE_NO_CORRECTION;
}
mWords = newWords;
// Update mWordArray
mWordArray = (TextUtils.isEmpty(mWords)) ? EMPTY_STRING_ARRAY
: WHITESPACE_PATTERN.split(mWords);
if (mWordArray.length > 0 && TextUtils.isEmpty(mWordArray[0])) {
// Empty string at beginning of array. Must have been whitespace at the start of the
// word. Remove the empty string.
mWordArray = Arrays.copyOfRange(mWordArray, 1, mWordArray.length);
} }
mWord = word;
} }
public String getWord() { public String getWordsAsString() {
return mWord; return mWords;
} }
public boolean hasWord() { /**
return mWord != null && !TextUtils.isEmpty(mWord.trim()); * Retuns the words generated by the data in this LogUnit.
*
* The first word may be an empty string, if the data in the LogUnit started by generating
* whitespace.
*
* @return the array of words. an empty list of there are no words associated with this LogUnit.
*/
public String[] getWordsAsStringArray() {
return mWordArray;
} }
public boolean hasOneOrMoreWords() {
return mWordArray.length >= 1;
}
public int getNumWords() {
return mWordArray.length;
}
// TODO: Refactor to eliminate getter/setters
public void setMayContainDigit() { public void setMayContainDigit() {
mMayContainDigit = true; mMayContainDigit = true;
} }
// TODO: Refactor to eliminate getter/setters
public boolean mayContainDigit() { public boolean mayContainDigit() {
return mMayContainDigit; return mMayContainDigit;
} }
// TODO: Refactor to eliminate getter/setters
public void setContainsCorrection() { public void setContainsCorrection() {
mContainsCorrection = true; mContainsCorrection = true;
} }
// TODO: Refactor to eliminate getter/setters
public boolean containsCorrection() { public boolean containsCorrection() {
return mContainsCorrection; return mContainsCorrection;
} }
// TODO: Refactor to eliminate getter/setters
public void setCorrectionType(final int correctionType) { public void setCorrectionType(final int correctionType) {
mCorrectionType = correctionType; mCorrectionType = correctionType;
} }
// TODO: Refactor to eliminate getter/setters
public int getCorrectionType() { public int getCorrectionType() {
return mCorrectionType; return mCorrectionType;
} }
@ -267,7 +318,7 @@ public class LogUnit {
new ArrayList<Object[]>(laterValues), new ArrayList<Object[]>(laterValues),
new ArrayList<Long>(laterTimes), new ArrayList<Long>(laterTimes),
true /* isPartOfMegaword */); true /* isPartOfMegaword */);
newLogUnit.mWord = null; newLogUnit.mWords = null;
newLogUnit.mMayContainDigit = mMayContainDigit; newLogUnit.mMayContainDigit = mMayContainDigit;
newLogUnit.mContainsCorrection = mContainsCorrection; newLogUnit.mContainsCorrection = mContainsCorrection;
@ -287,9 +338,9 @@ public class LogUnit {
mLogStatementList.addAll(logUnit.mLogStatementList); mLogStatementList.addAll(logUnit.mLogStatementList);
mValuesList.addAll(logUnit.mValuesList); mValuesList.addAll(logUnit.mValuesList);
mTimeList.addAll(logUnit.mTimeList); mTimeList.addAll(logUnit.mTimeList);
mWord = null; mWords = null;
if (logUnit.mWord != null) { if (logUnit.mWords != null) {
setWord(logUnit.mWord); setWords(logUnit.mWords);
} }
mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit; mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit;
mContainsCorrection = mContainsCorrection || logUnit.mContainsCorrection; mContainsCorrection = mContainsCorrection || logUnit.mContainsCorrection;

View File

@ -126,10 +126,7 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
final int length = logUnits.size(); final int length = logUnits.size();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
final LogUnit logUnit = logUnits.get(i); final LogUnit logUnit = logUnits.get(i);
final String word = logUnit.getWord(); numWordsInLogUnitList += logUnit.getNumWords();
if (word != null) {
numWordsInLogUnitList++;
}
} }
return numWordsInLogUnitList >= minNGramSize; return numWordsInLogUnitList >= minNGramSize;
} }
@ -153,29 +150,31 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
// the complete buffer contents in detail. // the complete buffer contents in detail.
int numWordsInLogUnitList = 0; int numWordsInLogUnitList = 0;
final int length = logUnits.size(); final int length = logUnits.size();
for (int i = 0; i < length; i++) { for (final LogUnit logUnit : logUnits) {
final LogUnit logUnit = logUnits.get(i); if (!logUnit.hasOneOrMoreWords()) {
if (!logUnit.hasWord()) {
// Digits outside words are a privacy threat. // Digits outside words are a privacy threat.
if (logUnit.mayContainDigit()) { if (logUnit.mayContainDigit()) {
return false; return false;
} }
} else { } else {
numWordsInLogUnitList++; numWordsInLogUnitList += logUnit.getNumWords();
final String word = logUnit.getWord(); final String[] words = logUnit.getWordsAsStringArray();
for (final String word : words) {
// Words not in the dictionary are a privacy threat. // Words not in the dictionary are a privacy threat.
if (ResearchLogger.hasLetters(word) && !(dictionary.isValidWord(word))) { if (ResearchLogger.hasLetters(word) && !(dictionary.isValidWord(word))) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "NOT SAFE!: hasLetters: " + ResearchLogger.hasLetters(word) Log.d(TAG, "\"" + word + "\" NOT SAFE!: hasLetters: "
+ ResearchLogger.hasLetters(word)
+ ", isValid: " + (dictionary.isValidWord(word))); + ", isValid: " + (dictionary.isValidWord(word)));
} }
return false; return false;
} }
} }
} }
}
// Finally, only return true if the minNGramSize is met. // Finally, only return true if the ngram is the right size.
return numWordsInLogUnitList >= minNGramSize; return numWordsInLogUnitList == minNGramSize;
} }
public void shiftAndPublishAll() { public void shiftAndPublishAll() {
@ -198,11 +197,14 @@ public abstract class MainLogBuffer extends FixedLogBuffer {
shiftOutWords(N_GRAM_SIZE); shiftOutWords(N_GRAM_SIZE);
mNumWordsUntilSafeToSample = mNumWordsBetweenNGrams; mNumWordsUntilSafeToSample = mNumWordsBetweenNGrams;
} else { } else {
// No good n-gram at front, and buffer is full. Shift out the first word (or if there // No good n-gram at front, and buffer is full. Shift out up through the first logUnit
// is none, the existing logUnits). // with associated words (or if there is none, all the existing logUnits).
logUnits = peekAtFirstNWords(1); logUnits.clear();
for (LogUnit logUnit = shiftOut(); logUnit != null && !logUnit.hasOneOrMoreWords();
logUnit = shiftOut()) {
logUnits.add(logUnit);
}
publish(logUnits, false /* canIncludePrivateData */); publish(logUnits, false /* canIncludePrivateData */);
shiftOutWords(1);
} }
} }

View File

@ -397,13 +397,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
protected void publish(final ArrayList<LogUnit> logUnits, protected void publish(final ArrayList<LogUnit> logUnits,
boolean canIncludePrivateData) { boolean canIncludePrivateData) {
canIncludePrivateData |= IS_LOGGING_EVERYTHING; canIncludePrivateData |= IS_LOGGING_EVERYTHING;
final int length = logUnits.size(); for (final LogUnit logUnit : logUnits) {
for (int i = 0; i < length; i++) { if (DEBUG) {
final LogUnit logUnit = logUnits.get(i); final String wordsString = logUnit.getWordsAsString();
final String word = logUnit.getWord(); Log.d(TAG, "onPublish: '" + wordsString
if (word != null && word.length() > 0 && hasLetters(word)) { + "', hc: " + logUnit.containsCorrection()
Log.d(TAG, "onPublish: " + word + ", hc: " + ", cipd: " + canIncludePrivateData);
+ logUnit.containsCorrection()); }
for (final String word : logUnit.getWordsAsStringArray()) {
final Dictionary dictionary = getDictionary(); final Dictionary dictionary = getDictionary();
mStatistics.recordWordEntered( mStatistics.recordWordEntered(
dictionary != null && dictionary.isValidWord(word), dictionary != null && dictionary.isValidWord(word),
@ -852,8 +853,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
/* package for test */ void commitCurrentLogUnit() { /* package for test */ void commitCurrentLogUnit() {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ? Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasOneOrMoreWords() ?
": " + mCurrentLogUnit.getWord() : "")); ": " + mCurrentLogUnit.getWordsAsString() : ""));
} }
if (!mCurrentLogUnit.isEmpty()) { if (!mCurrentLogUnit.isEmpty()) {
if (mMainLogBuffer != null) { if (mMainLogBuffer != null) {
@ -893,8 +894,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// Check that expected word matches. // Check that expected word matches.
if (oldLogUnit != null) { if (oldLogUnit != null) {
final String oldLogUnitWord = oldLogUnit.getWord(); final String oldLogUnitWords = oldLogUnit.getWordsAsString();
if (oldLogUnitWord != null && !oldLogUnitWord.equals(expectedWord)) { if (oldLogUnitWords != null && !oldLogUnitWords.equals(expectedWord)) {
return; return;
} }
} }
@ -916,7 +917,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
enqueueEvent(LOGSTATEMENT_UNCOMMIT_CURRENT_LOGUNIT); enqueueEvent(LOGSTATEMENT_UNCOMMIT_CURRENT_LOGUNIT);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "uncommitCurrentLogUnit (dump=" + dumpCurrentLogUnit + ") back to " Log.d(TAG, "uncommitCurrentLogUnit (dump=" + dumpCurrentLogUnit + ") back to "
+ (mCurrentLogUnit.hasWord() ? ": '" + mCurrentLogUnit.getWord() + "'" : "")); + (mCurrentLogUnit.hasOneOrMoreWords() ? ": '"
+ mCurrentLogUnit.getWordsAsString() + "'" : ""));
} }
} }
@ -950,8 +952,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
} }
for (LogUnit logUnit : logUnits) { for (LogUnit logUnit : logUnits) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "publishLogBuffer: " + (logUnit.hasWord() ? logUnit.getWord() Log.d(TAG, "publishLogBuffer: " + (logUnit.hasOneOrMoreWords()
: "<wordless>") + ", correction?: " + logUnit.containsCorrection()); ? logUnit.getWordsAsString() : "<wordless>")
+ ", correction?: " + logUnit.containsCorrection());
} }
researchLog.publish(logUnit, canIncludePrivateData); researchLog.publish(logUnit, canIncludePrivateData);
} }
@ -986,7 +989,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
return; return;
} }
if (word.length() > 0 && hasLetters(word)) { if (word.length() > 0 && hasLetters(word)) {
mCurrentLogUnit.setWord(word); mCurrentLogUnit.setWords(word);
} }
final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime);
enqueueCommitText(word, isBatchMode); enqueueCommitText(word, isBatchMode);
@ -1478,7 +1481,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
} }
if (originallyTypedWord.length() > 0 && hasLetters(originallyTypedWord)) { if (originallyTypedWord.length() > 0 && hasLetters(originallyTypedWord)) {
if (logUnit != null) { if (logUnit != null) {
logUnit.setWord(originallyTypedWord); logUnit.setWords(originallyTypedWord);
} }
} }
researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit, researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit,
@ -1616,7 +1619,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
* Log a call to LatinIME.commitCurrentAutoCorrection(). * Log a call to LatinIME.commitCurrentAutoCorrection().
* *
* SystemResponse: The IME has committed an auto-correction. An auto-correction changes the raw * SystemResponse: The IME has committed an auto-correction. An auto-correction changes the raw
* text input to another word that the user more likely desired to type. * text input to another word (or words) that the user more likely desired to type.
*/ */
private static final LogStatement LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION = private static final LogStatement LOGSTATEMENT_LATINIME_COMMITCURRENTAUTOCORRECTION =
new LogStatement("LatinIMECommitCurrentAutoCorrection", true, true, "typedWord", new LogStatement("LatinIMECommitCurrentAutoCorrection", true, true, "typedWord",
@ -1827,7 +1830,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final int enteredWordPos, final SuggestedWords suggestedWords) { final int enteredWordPos, final SuggestedWords suggestedWords) {
final ResearchLogger researchLogger = getInstance(); final ResearchLogger researchLogger = getInstance();
if (!TextUtils.isEmpty(enteredText) && hasLetters(enteredText.toString())) { if (!TextUtils.isEmpty(enteredText) && hasLetters(enteredText.toString())) {
researchLogger.mCurrentLogUnit.setWord(enteredText.toString()); researchLogger.mCurrentLogUnit.setWords(enteredText.toString());
} }
researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText, researchLogger.enqueueEvent(LOGSTATEMENT_LATINIME_ONENDBATCHINPUT, enteredText,
enteredWordPos); enteredWordPos);