[Rlog27] Refactor LogBuffer
Cleanup and prepare for replaying Change-Id: Ie09e912c6e9c0d7375168c575ccf1cfd9375dd31main
parent
13b1be988d
commit
f77dd424b0
|
@ -2094,12 +2094,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction
|
||||||
Stats.onAutoCorrection(
|
Stats.onAutoCorrection(
|
||||||
typedWord, autoCorrection.toString(), separatorString, mWordComposer);
|
typedWord, autoCorrection.toString(), separatorString, mWordComposer);
|
||||||
}
|
}
|
||||||
mExpectingUpdateSelection = true;
|
|
||||||
if (ProductionFlag.IS_EXPERIMENTAL) {
|
if (ProductionFlag.IS_EXPERIMENTAL) {
|
||||||
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord,
|
ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection,
|
||||||
autoCorrection.toString(), separatorString);
|
separatorString);
|
||||||
}
|
}
|
||||||
|
mExpectingUpdateSelection = true;
|
||||||
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
|
commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD,
|
||||||
separatorString);
|
separatorString);
|
||||||
if (!typedWord.equals(autoCorrection)) {
|
if (!typedWord.equals(autoCorrection)) {
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* 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 java.util.LinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A buffer that holds a fixed number of LogUnits.
|
||||||
|
*
|
||||||
|
* LogUnits are added in and shifted out in temporal order. Only a subset of the LogUnits are
|
||||||
|
* actual words; the other LogUnits do not count toward the word limit. Once the buffer reaches
|
||||||
|
* capacity, adding another LogUnit that is a word evicts the oldest LogUnits out one at a time to
|
||||||
|
* stay under the capacity limit.
|
||||||
|
*
|
||||||
|
* This variant of a LogBuffer has a limited memory footprint because of its limited size. This
|
||||||
|
* makes it useful, for example, for recording a window of the user's most recent actions in case
|
||||||
|
* they want to report an observed error that they do not know how to reproduce.
|
||||||
|
*/
|
||||||
|
public class FixedLogBuffer extends LogBuffer {
|
||||||
|
/* package for test */ int mWordCapacity;
|
||||||
|
// The number of members of mLogUnits that are actual words.
|
||||||
|
private int mNumActualWords;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new LogBuffer that can hold a fixed number of LogUnits that are words (and
|
||||||
|
* unlimited number of non-word LogUnits), and that outputs its result to a researchLog.
|
||||||
|
*
|
||||||
|
* @param wordCapacity maximum number of words
|
||||||
|
*/
|
||||||
|
public FixedLogBuffer(final int wordCapacity) {
|
||||||
|
super();
|
||||||
|
if (wordCapacity <= 0) {
|
||||||
|
throw new IllegalArgumentException("wordCapacity must be 1 or greater.");
|
||||||
|
}
|
||||||
|
mWordCapacity = wordCapacity;
|
||||||
|
mNumActualWords = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getNumActualWords() {
|
||||||
|
return mNumActualWords;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new LogUnit to the front of the LIFO queue, evicting existing LogUnit's
|
||||||
|
* (oldest first) if word capacity is reached.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void shiftIn(final LogUnit newLogUnit) {
|
||||||
|
if (newLogUnit.getWord() == null) {
|
||||||
|
// This LogUnit isn't a word, so it doesn't count toward the word-limit.
|
||||||
|
super.shiftIn(newLogUnit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mNumActualWords == mWordCapacity) {
|
||||||
|
shiftOutThroughFirstWord();
|
||||||
|
}
|
||||||
|
super.shiftIn(newLogUnit);
|
||||||
|
mNumActualWords++; // Must be a word, or we wouldn't be here.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shiftOutThroughFirstWord() {
|
||||||
|
final LinkedList<LogUnit> logUnits = getLogUnits();
|
||||||
|
while (!logUnits.isEmpty()) {
|
||||||
|
final LogUnit logUnit = logUnits.removeFirst();
|
||||||
|
onShiftOut(logUnit);
|
||||||
|
if (logUnit.hasWord()) {
|
||||||
|
// Successfully shifted out a word-containing LogUnit and made space for the new
|
||||||
|
// LogUnit.
|
||||||
|
mNumActualWords--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all LogUnits from the buffer without calling onShiftOut().
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
super.clear();
|
||||||
|
mNumActualWords = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a LogUnit is removed from the LogBuffer as a result of a shiftIn. LogUnits are
|
||||||
|
* removed in the order entered. This method is not called when shiftOut is called directly.
|
||||||
|
*
|
||||||
|
* Base class does nothing; subclasses may override if they want to record non-privacy sensitive
|
||||||
|
* events that fall off the end.
|
||||||
|
*/
|
||||||
|
protected void onShiftOut(final LogUnit logUnit) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to deliberately remove the oldest LogUnit. Usually called when draining the
|
||||||
|
* LogBuffer.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public LogUnit shiftOut() {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final LogUnit logUnit = super.shiftOut();
|
||||||
|
if (logUnit.hasWord()) {
|
||||||
|
mNumActualWords--;
|
||||||
|
}
|
||||||
|
return logUnit;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,102 +16,44 @@
|
||||||
|
|
||||||
package com.android.inputmethod.research;
|
package com.android.inputmethod.research;
|
||||||
|
|
||||||
import com.android.inputmethod.latin.CollectionUtils;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A buffer that holds a fixed number of LogUnits.
|
* Maintain a FIFO queue of LogUnits.
|
||||||
*
|
*
|
||||||
* LogUnits are added in and shifted out in temporal order. Only a subset of the LogUnits are
|
* This class provides an unbounded queue. This is useful when the user is aware that their actions
|
||||||
* actual words; the other LogUnits do not count toward the word limit. Once the buffer reaches
|
* are being recorded, such as when they are trying to reproduce a bug. In this case, there should
|
||||||
* capacity, adding another LogUnit that is a word evicts the oldest LogUnits out one at a time to
|
* not be artificial restrictions on how many events that can be saved.
|
||||||
* stay under the capacity limit.
|
|
||||||
*/
|
*/
|
||||||
public class LogBuffer {
|
public class LogBuffer {
|
||||||
protected final LinkedList<LogUnit> mLogUnits;
|
// TODO: Gracefully handle situations in which this LogBuffer is consuming too much memory.
|
||||||
/* package for test */ int mWordCapacity;
|
// This may happen, for example, if the user has forgotten that data is being logged.
|
||||||
// The number of members of mLogUnits that are actual words.
|
private final LinkedList<LogUnit> mLogUnits;
|
||||||
protected int mNumActualWords;
|
|
||||||
|
|
||||||
/**
|
public LogBuffer() {
|
||||||
* Create a new LogBuffer that can hold a fixed number of LogUnits that are words (and
|
mLogUnits = new LinkedList<LogUnit>();
|
||||||
* unlimited number of non-word LogUnits), and that outputs its result to a researchLog.
|
|
||||||
*
|
|
||||||
* @param wordCapacity maximum number of words
|
|
||||||
*/
|
|
||||||
LogBuffer(final int wordCapacity) {
|
|
||||||
if (wordCapacity <= 0) {
|
|
||||||
throw new IllegalArgumentException("wordCapacity must be 1 or greater.");
|
|
||||||
}
|
|
||||||
mLogUnits = CollectionUtils.newLinkedList();
|
|
||||||
mWordCapacity = wordCapacity;
|
|
||||||
mNumActualWords = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected LinkedList<LogUnit> getLogUnits() {
|
||||||
* Adds a new LogUnit to the front of the LIFO queue, evicting existing LogUnit's
|
return mLogUnits;
|
||||||
* (oldest first) if word capacity is reached.
|
|
||||||
*/
|
|
||||||
public void shiftIn(LogUnit newLogUnit) {
|
|
||||||
if (newLogUnit.getWord() == null) {
|
|
||||||
// This LogUnit isn't a word, so it doesn't count toward the word-limit.
|
|
||||||
mLogUnits.add(newLogUnit);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mNumActualWords == mWordCapacity) {
|
|
||||||
shiftOutThroughFirstWord();
|
|
||||||
}
|
|
||||||
mLogUnits.add(newLogUnit);
|
|
||||||
mNumActualWords++; // Must be a word, or we wouldn't be here.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shiftOutThroughFirstWord() {
|
|
||||||
while (!mLogUnits.isEmpty()) {
|
|
||||||
final LogUnit logUnit = mLogUnits.removeFirst();
|
|
||||||
onShiftOut(logUnit);
|
|
||||||
if (logUnit.hasWord()) {
|
|
||||||
// Successfully shifted out a word-containing LogUnit and made space for the new
|
|
||||||
// LogUnit.
|
|
||||||
mNumActualWords--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all LogUnits from the buffer without calling onShiftOut().
|
|
||||||
*/
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
mLogUnits.clear();
|
mLogUnits.clear();
|
||||||
mNumActualWords = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void shiftIn(final LogUnit logUnit) {
|
||||||
* Called when a LogUnit is removed from the LogBuffer as a result of a shiftIn. LogUnits are
|
mLogUnits.add(logUnit);
|
||||||
* removed in the order entered. This method is not called when shiftOut is called directly.
|
|
||||||
*
|
|
||||||
* Base class does nothing; subclasses may override.
|
|
||||||
*/
|
|
||||||
protected void onShiftOut(LogUnit logUnit) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called to deliberately remove the oldest LogUnit. Usually called when draining the
|
|
||||||
* LogBuffer.
|
|
||||||
*/
|
|
||||||
public LogUnit shiftOut() {
|
|
||||||
if (mLogUnits.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final LogUnit logUnit = mLogUnits.removeFirst();
|
|
||||||
if (logUnit.hasWord()) {
|
|
||||||
mNumActualWords--;
|
|
||||||
}
|
|
||||||
return logUnit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return mLogUnits.isEmpty();
|
return mLogUnits.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LogUnit shiftOut() {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return mLogUnits.removeFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,24 @@ import com.android.inputmethod.latin.Dictionary;
|
||||||
import com.android.inputmethod.latin.Suggest;
|
import com.android.inputmethod.latin.Suggest;
|
||||||
import com.android.inputmethod.latin.define.ProductionFlag;
|
import com.android.inputmethod.latin.define.ProductionFlag;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public class MainLogBuffer extends LogBuffer {
|
/**
|
||||||
|
* Provide a log buffer of fixed length that enforces privacy restrictions.
|
||||||
|
*
|
||||||
|
* The privacy restrictions include making sure that no numbers are logged, that all logged words
|
||||||
|
* are in the dictionary, and that words are recorded infrequently enough that the user's meaning
|
||||||
|
* cannot be easily determined.
|
||||||
|
*/
|
||||||
|
public class MainLogBuffer extends FixedLogBuffer {
|
||||||
private static final String TAG = MainLogBuffer.class.getSimpleName();
|
private static final String TAG = MainLogBuffer.class.getSimpleName();
|
||||||
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
|
private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG;
|
||||||
|
|
||||||
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
|
// The size of the n-grams logged. E.g. N_GRAM_SIZE = 2 means to sample bigrams.
|
||||||
private static final int N_GRAM_SIZE = 2;
|
private static final int N_GRAM_SIZE = 2;
|
||||||
// The number of words between n-grams to omit from the log.
|
// The number of words between n-grams to omit from the log. If debugging, record 50% of all
|
||||||
|
// words. Otherwise, only record 10%.
|
||||||
private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES =
|
private static final int DEFAULT_NUMBER_OF_WORDS_BETWEEN_SAMPLES =
|
||||||
ProductionFlag.IS_EXPERIMENTAL_DEBUG ? 2 : 18;
|
ProductionFlag.IS_EXPERIMENTAL_DEBUG ? 2 : 18;
|
||||||
|
|
||||||
|
@ -56,7 +65,7 @@ public class MainLogBuffer extends LogBuffer {
|
||||||
mWordsUntilSafeToSample = random.nextInt(mMinWordPeriod);
|
mWordsUntilSafeToSample = random.nextInt(mMinWordPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSuggest(Suggest suggest) {
|
public void setSuggest(final Suggest suggest) {
|
||||||
mSuggest = suggest;
|
mSuggest = suggest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,9 +117,10 @@ public class MainLogBuffer extends LogBuffer {
|
||||||
}
|
}
|
||||||
// Check each word in the buffer. If any word poses a privacy threat, we cannot upload the
|
// Check each word in the buffer. If any word poses a privacy threat, we cannot upload the
|
||||||
// complete buffer contents in detail.
|
// complete buffer contents in detail.
|
||||||
final int length = mLogUnits.size();
|
final LinkedList<LogUnit> logUnits = getLogUnits();
|
||||||
|
final int length = logUnits.size();
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
final LogUnit logUnit = mLogUnits.get(i);
|
final LogUnit logUnit = logUnits.get(i);
|
||||||
final String word = logUnit.getWord();
|
final String word = logUnit.getWord();
|
||||||
if (word == null) {
|
if (word == null) {
|
||||||
// Digits outside words are a privacy threat.
|
// Digits outside words are a privacy threat.
|
||||||
|
@ -133,7 +143,7 @@ public class MainLogBuffer extends LogBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onShiftOut(LogUnit logUnit) {
|
protected void onShiftOut(final LogUnit logUnit) {
|
||||||
if (mResearchLog != null) {
|
if (mResearchLog != null) {
|
||||||
mResearchLog.publish(logUnit, false /* isIncludingPrivateData */);
|
mResearchLog.publish(logUnit, false /* isIncludingPrivateData */);
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
|
||||||
mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
|
mFeedbackLog = new ResearchLog(createLogFile(mFilesDir));
|
||||||
// LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold
|
// LogBuffer is one more than FEEDBACK_WORD_BUFFER_SIZE, because it must also hold
|
||||||
// the feedback LogUnit itself.
|
// the feedback LogUnit itself.
|
||||||
mFeedbackLogBuffer = new LogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
|
mFeedbackLogBuffer = new FixedLogBuffer(FEEDBACK_WORD_BUFFER_SIZE + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue