2012-07-31 04:55:42 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
|
|
*
|
2013-01-21 12:52:57 +00:00
|
|
|
* 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
|
2012-07-31 04:55:42 +00:00
|
|
|
*
|
2013-01-21 12:52:57 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2012-07-31 04:55:42 +00:00
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
2013-01-21 12:52:57 +00:00
|
|
|
* 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.
|
2012-07-31 04:55:42 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.inputmethod.research;
|
|
|
|
|
2012-08-09 19:20:45 +00:00
|
|
|
import android.util.Log;
|
|
|
|
|
2012-10-29 05:46:34 +00:00
|
|
|
import com.android.inputmethod.latin.Constants;
|
2012-12-18 02:19:58 +00:00
|
|
|
import com.android.inputmethod.latin.define.ProductionFlag;
|
2012-07-31 04:55:42 +00:00
|
|
|
|
2013-07-05 08:57:01 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
2012-07-31 04:55:42 +00:00
|
|
|
public class Statistics {
|
2012-08-09 19:20:45 +00:00
|
|
|
private static final String TAG = Statistics.class.getSimpleName();
|
2013-03-18 09:21:18 +00:00
|
|
|
private static final boolean DEBUG = false
|
|
|
|
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
|
2012-08-09 19:20:45 +00:00
|
|
|
|
2013-01-11 22:17:17 +00:00
|
|
|
// TODO: Cleanup comments to only including those giving meaningful information.
|
2012-07-31 04:55:42 +00:00
|
|
|
// Number of characters entered during a typing session
|
|
|
|
int mCharCount;
|
|
|
|
// Number of letter characters entered during a typing session
|
|
|
|
int mLetterCount;
|
|
|
|
// Number of number characters entered
|
|
|
|
int mNumberCount;
|
|
|
|
// Number of space characters entered
|
|
|
|
int mSpaceCount;
|
|
|
|
// Number of delete operations entered (taps on the backspace key)
|
|
|
|
int mDeleteKeyCount;
|
|
|
|
// Number of words entered during a session.
|
|
|
|
int mWordCount;
|
2012-08-10 21:21:18 +00:00
|
|
|
// Number of words found in the dictionary.
|
|
|
|
int mDictionaryWordCount;
|
|
|
|
// Number of words split and spaces automatically entered.
|
|
|
|
int mSplitWordsCount;
|
2013-01-11 22:17:17 +00:00
|
|
|
// Number of words entered during a session.
|
|
|
|
int mCorrectedWordsCount;
|
2012-08-10 21:21:18 +00:00
|
|
|
// Number of gestures that were input.
|
2012-12-21 20:22:06 +00:00
|
|
|
int mGesturesInputCount;
|
2012-08-13 17:30:12 +00:00
|
|
|
// Number of gestures that were deleted.
|
|
|
|
int mGesturesDeletedCount;
|
|
|
|
// Total number of characters in words entered by gesture.
|
2012-12-21 20:22:06 +00:00
|
|
|
int mGesturesCharsCount;
|
2012-08-28 17:26:21 +00:00
|
|
|
// Number of manual suggestions chosen.
|
|
|
|
int mManualSuggestionsCount;
|
2013-01-11 22:17:17 +00:00
|
|
|
// Number of times that autocorrection was invoked.
|
|
|
|
int mAutoCorrectionsCount;
|
2012-08-28 17:26:21 +00:00
|
|
|
// Number of times a commit was reverted in this session.
|
|
|
|
int mRevertCommitsCount;
|
2012-07-31 04:55:42 +00:00
|
|
|
// Whether the text field was empty upon editing
|
|
|
|
boolean mIsEmptyUponStarting;
|
|
|
|
boolean mIsEmptinessStateKnown;
|
|
|
|
|
2013-05-22 18:21:46 +00:00
|
|
|
// Counts of how often an n-gram is collected or not, and the reasons for the decision.
|
|
|
|
// Keep consistent with publishability result code list in MainLogBuffer
|
|
|
|
int mPublishableCount;
|
|
|
|
int mUnpublishableStoppingCount;
|
|
|
|
int mUnpublishableIncorrectWordCount;
|
|
|
|
int mUnpublishableSampledTooRecently;
|
|
|
|
int mUnpublishableDictionaryUnavailable;
|
|
|
|
int mUnpublishableMayContainDigit;
|
|
|
|
int mUnpublishableNotInDictionary;
|
|
|
|
|
2012-07-31 04:55:42 +00:00
|
|
|
// Timers to count average time to enter a key, first press a delete key,
|
|
|
|
// between delete keys, and then to return typing after a delete key.
|
|
|
|
final AverageTimeCounter mKeyCounter = new AverageTimeCounter();
|
|
|
|
final AverageTimeCounter mBeforeDeleteKeyCounter = new AverageTimeCounter();
|
|
|
|
final AverageTimeCounter mDuringRepeatedDeleteKeysCounter = new AverageTimeCounter();
|
|
|
|
final AverageTimeCounter mAfterDeleteKeyCounter = new AverageTimeCounter();
|
|
|
|
|
|
|
|
static class AverageTimeCounter {
|
|
|
|
int mCount;
|
|
|
|
int mTotalTime;
|
|
|
|
|
|
|
|
public void reset() {
|
|
|
|
mCount = 0;
|
|
|
|
mTotalTime = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void add(long deltaTime) {
|
|
|
|
mCount++;
|
|
|
|
mTotalTime += deltaTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getAverageTime() {
|
|
|
|
if (mCount == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return mTotalTime / mCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// To account for the interruptions when the user's attention is directed elsewhere, times
|
|
|
|
// longer than MIN_TYPING_INTERMISSION are not counted when estimating this statistic.
|
2013-07-05 08:57:01 +00:00
|
|
|
public static final long MIN_TYPING_INTERMISSION = TimeUnit.SECONDS.toMillis(2);
|
|
|
|
public static final long MIN_DELETION_INTERMISSION = TimeUnit.SECONDS.toMillis(10);
|
2012-07-31 04:55:42 +00:00
|
|
|
|
|
|
|
// The last time that a tap was performed
|
|
|
|
private long mLastTapTime;
|
|
|
|
// The type of the last keypress (delete key or not)
|
|
|
|
boolean mIsLastKeyDeleteKey;
|
|
|
|
|
|
|
|
private static final Statistics sInstance = new Statistics();
|
|
|
|
|
|
|
|
public static Statistics getInstance() {
|
|
|
|
return sInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Statistics() {
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void reset() {
|
|
|
|
mCharCount = 0;
|
|
|
|
mLetterCount = 0;
|
|
|
|
mNumberCount = 0;
|
|
|
|
mSpaceCount = 0;
|
|
|
|
mDeleteKeyCount = 0;
|
|
|
|
mWordCount = 0;
|
2012-12-21 20:22:06 +00:00
|
|
|
mDictionaryWordCount = 0;
|
|
|
|
mSplitWordsCount = 0;
|
2013-01-11 22:17:17 +00:00
|
|
|
mCorrectedWordsCount = 0;
|
2012-12-21 20:22:06 +00:00
|
|
|
mGesturesInputCount = 0;
|
|
|
|
mGesturesDeletedCount = 0;
|
2012-08-28 17:26:21 +00:00
|
|
|
mManualSuggestionsCount = 0;
|
|
|
|
mRevertCommitsCount = 0;
|
2013-01-11 22:17:17 +00:00
|
|
|
mAutoCorrectionsCount = 0;
|
2012-07-31 04:55:42 +00:00
|
|
|
mIsEmptyUponStarting = true;
|
|
|
|
mIsEmptinessStateKnown = false;
|
|
|
|
mKeyCounter.reset();
|
|
|
|
mBeforeDeleteKeyCounter.reset();
|
|
|
|
mDuringRepeatedDeleteKeysCounter.reset();
|
|
|
|
mAfterDeleteKeyCounter.reset();
|
2012-12-21 20:22:06 +00:00
|
|
|
mGesturesCharsCount = 0;
|
2012-08-13 17:30:12 +00:00
|
|
|
mGesturesDeletedCount = 0;
|
2013-05-22 18:21:46 +00:00
|
|
|
mPublishableCount = 0;
|
|
|
|
mUnpublishableStoppingCount = 0;
|
|
|
|
mUnpublishableIncorrectWordCount = 0;
|
|
|
|
mUnpublishableSampledTooRecently = 0;
|
|
|
|
mUnpublishableDictionaryUnavailable = 0;
|
|
|
|
mUnpublishableMayContainDigit = 0;
|
|
|
|
mUnpublishableNotInDictionary = 0;
|
2012-07-31 04:55:42 +00:00
|
|
|
|
|
|
|
mLastTapTime = 0;
|
|
|
|
mIsLastKeyDeleteKey = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void recordChar(int codePoint, long time) {
|
2012-08-09 19:20:45 +00:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "recordChar() called");
|
|
|
|
}
|
2012-10-29 05:46:34 +00:00
|
|
|
if (codePoint == Constants.CODE_DELETE) {
|
2012-07-31 04:55:42 +00:00
|
|
|
mDeleteKeyCount++;
|
2013-01-10 19:22:22 +00:00
|
|
|
recordUserAction(time, true /* isDeletion */);
|
2012-07-31 04:55:42 +00:00
|
|
|
} else {
|
|
|
|
mCharCount++;
|
|
|
|
if (Character.isDigit(codePoint)) {
|
|
|
|
mNumberCount++;
|
|
|
|
}
|
|
|
|
if (Character.isLetter(codePoint)) {
|
|
|
|
mLetterCount++;
|
|
|
|
}
|
|
|
|
if (Character.isSpaceChar(codePoint)) {
|
|
|
|
mSpaceCount++;
|
|
|
|
}
|
2013-01-10 19:22:22 +00:00
|
|
|
recordUserAction(time, false /* isDeletion */);
|
2012-07-31 04:55:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-11 22:17:17 +00:00
|
|
|
public void recordWordEntered(final boolean isDictionaryWord,
|
|
|
|
final boolean containsCorrection) {
|
2012-07-31 04:55:42 +00:00
|
|
|
mWordCount++;
|
2012-08-10 21:21:18 +00:00
|
|
|
if (isDictionaryWord) {
|
|
|
|
mDictionaryWordCount++;
|
|
|
|
}
|
2013-01-11 22:17:17 +00:00
|
|
|
if (containsCorrection) {
|
|
|
|
mCorrectedWordsCount++;
|
|
|
|
}
|
2012-08-10 21:21:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void recordSplitWords() {
|
|
|
|
mSplitWordsCount++;
|
|
|
|
}
|
|
|
|
|
2013-01-10 19:22:22 +00:00
|
|
|
public void recordGestureInput(final int numCharsEntered, final long time) {
|
2012-12-21 20:22:06 +00:00
|
|
|
mGesturesInputCount++;
|
|
|
|
mGesturesCharsCount += numCharsEntered;
|
2013-01-10 19:22:22 +00:00
|
|
|
recordUserAction(time, false /* isDeletion */);
|
2012-07-31 04:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setIsEmptyUponStarting(final boolean isEmpty) {
|
|
|
|
mIsEmptyUponStarting = isEmpty;
|
|
|
|
mIsEmptinessStateKnown = true;
|
|
|
|
}
|
2012-08-13 17:30:12 +00:00
|
|
|
|
2013-01-10 19:22:22 +00:00
|
|
|
public void recordGestureDelete(final int length, final long time) {
|
2012-08-13 17:30:12 +00:00
|
|
|
mGesturesDeletedCount++;
|
2013-01-10 19:22:22 +00:00
|
|
|
recordUserAction(time, true /* isDeletion */);
|
2012-08-13 17:30:12 +00:00
|
|
|
}
|
2013-01-10 19:22:22 +00:00
|
|
|
|
|
|
|
public void recordManualSuggestion(final long time) {
|
2012-08-28 17:26:21 +00:00
|
|
|
mManualSuggestionsCount++;
|
2013-01-10 19:22:22 +00:00
|
|
|
recordUserAction(time, false /* isDeletion */);
|
2012-08-28 17:26:21 +00:00
|
|
|
}
|
|
|
|
|
2013-01-11 22:17:17 +00:00
|
|
|
public void recordAutoCorrection(final long time) {
|
|
|
|
mAutoCorrectionsCount++;
|
|
|
|
recordUserAction(time, false /* isDeletion */);
|
|
|
|
}
|
|
|
|
|
2013-01-10 19:22:22 +00:00
|
|
|
public void recordRevertCommit(final long time) {
|
2012-08-28 17:26:21 +00:00
|
|
|
mRevertCommitsCount++;
|
2013-01-10 19:22:22 +00:00
|
|
|
recordUserAction(time, true /* isDeletion */);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void recordUserAction(final long time, final boolean isDeletion) {
|
|
|
|
final long delta = time - mLastTapTime;
|
|
|
|
if (isDeletion) {
|
|
|
|
if (delta < MIN_DELETION_INTERMISSION) {
|
|
|
|
if (mIsLastKeyDeleteKey) {
|
|
|
|
mDuringRepeatedDeleteKeysCounter.add(delta);
|
|
|
|
} else {
|
|
|
|
mBeforeDeleteKeyCounter.add(delta);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ResearchLogger.onUserPause(delta);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mIsLastKeyDeleteKey && delta < MIN_DELETION_INTERMISSION) {
|
|
|
|
mAfterDeleteKeyCounter.add(delta);
|
|
|
|
} else if (!mIsLastKeyDeleteKey && delta < MIN_TYPING_INTERMISSION) {
|
|
|
|
mKeyCounter.add(delta);
|
|
|
|
} else {
|
|
|
|
ResearchLogger.onUserPause(delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mIsLastKeyDeleteKey = isDeletion;
|
|
|
|
mLastTapTime = time;
|
2012-08-28 17:26:21 +00:00
|
|
|
}
|
2013-05-22 18:21:46 +00:00
|
|
|
|
|
|
|
public void recordPublishabilityResultCode(final int publishabilityResultCode) {
|
|
|
|
// Keep consistent with publishability result code list in MainLogBuffer
|
|
|
|
switch (publishabilityResultCode) {
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_PUBLISHABLE:
|
|
|
|
mPublishableCount++;
|
|
|
|
break;
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_STOPPING:
|
|
|
|
mUnpublishableStoppingCount++;
|
|
|
|
break;
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_INCORRECT_WORD_COUNT:
|
|
|
|
mUnpublishableIncorrectWordCount++;
|
|
|
|
break;
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_SAMPLED_TOO_RECENTLY:
|
|
|
|
mUnpublishableSampledTooRecently++;
|
|
|
|
break;
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_DICTIONARY_UNAVAILABLE:
|
|
|
|
mUnpublishableDictionaryUnavailable++;
|
|
|
|
break;
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_MAY_CONTAIN_DIGIT:
|
|
|
|
mUnpublishableMayContainDigit++;
|
|
|
|
break;
|
|
|
|
case MainLogBuffer.PUBLISHABILITY_UNPUBLISHABLE_NOT_IN_DICTIONARY:
|
|
|
|
mUnpublishableNotInDictionary++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-07-31 04:55:42 +00:00
|
|
|
}
|