Add aggressive cancellation for auto suggestion

- Add ring buffer
- Count separator for auto suggestion
- Add a test for ring buffer

Change-Id: Id4a0aa00ceb1b055b8fc96c45e100d318cceb2ab
main
satok 2010-06-01 19:58:36 +09:00
parent ac2b332e94
commit 928ebfeaf8
7 changed files with 176 additions and 38 deletions

View File

@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.inputmethod.latin"
android:versionCode="9"
android:versionName="0.12">
android:versionName="0.14">
<original-package android:name="com.android.inputmethod.latin" />

View File

@ -219,7 +219,7 @@ public class LatinIME extends InputMethodService
private final float FX_VOLUME = -1.0f;
private boolean mSilentMode;
private String mWordSeparators;
/* package */ String mWordSeparators;
private String mSentenceSeparators;
private VoiceInput mVoiceInput;
private VoiceResults mVoiceResults = new VoiceResults();
@ -955,7 +955,7 @@ public class LatinIME extends InputMethodService
case Keyboard.KEYCODE_DELETE:
handleBackspace();
mDeleteCount++;
LatinImeLogger.logOnDelete(1);
LatinImeLogger.logOnDelete();
break;
case Keyboard.KEYCODE_SHIFT:
handleShift();
@ -996,12 +996,12 @@ public class LatinIME extends InputMethodService
if (primaryCode != KEYCODE_ENTER) {
mJustAddedAutoSpace = false;
}
LatinImeLogger.logOnInputChar((char)primaryCode);
if (isWordSeparator(primaryCode)) {
handleSeparator(primaryCode);
} else {
handleCharacter(primaryCode, keyCodes);
}
LatinImeLogger.logOnInputChar(1);
// Cancel the just reverted state
mJustRevertedSeparator = null;
}

View File

@ -33,7 +33,8 @@ import java.util.Collections;
public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "LatinIMELogs";
private static boolean sDBG = false;
private static final boolean DBG = true;
private static boolean sLOGPRINT = false;
// SUPPRESS_EXCEPTION should be true when released to public.
private static final boolean SUPPRESS_EXCEPTION = false;
// DEFAULT_LOG_ENABLED should be false when released to public.
@ -43,6 +44,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private static final long MINIMUMCOUNTINTERVAL = 20 * DateUtils.SECOND_IN_MILLIS; // 20 sec
private static final long MINIMUMSENDSIZE = 40;
private static final char SEPARATER = ';';
private static final char NULL_CHAR = '\uFFFC';
private static final int ID_CLICKSUGGESTION = 0;
private static final int ID_AUTOSUGGESTIONCANCELLED = 1;
private static final int ID_AUTOSUGGESTION = 2;
@ -60,14 +62,17 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private static final String PREF_AUTO_COMPLETE = "auto_complete";
public static boolean sLogEnabled = true;
private static LatinImeLogger sLatinImeLogger = new LatinImeLogger();
/* package */ static LatinImeLogger sLatinImeLogger = new LatinImeLogger();
// Store the last auto suggested word.
// This is required for a cancellation log of auto suggestion of that word.
private static String sLastAutoSuggestBefore;
private static String sLastAutoSuggestAfter;
/* package */ static String sLastAutoSuggestBefore;
/* package */ static String sLastAutoSuggestAfter;
/* package */ static String sLastAutoSuggestSeparator;
private ArrayList<LogEntry> mLogBuffer = null;
private ArrayList<LogEntry> mPrivacyLogBuffer = null;
/* package */ RingCharBuffer mRingCharBuffer = null;
private Context mContext = null;
private DropBoxManager mDropBox = null;
private long mLastTimeActive;
@ -116,11 +121,12 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mActualCharCount = 0;
mLogBuffer = new ArrayList<LogEntry>();
mPrivacyLogBuffer = new ArrayList<LogEntry>();
mRingCharBuffer = new RingCharBuffer(context);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
sLogEnabled = prefs.getBoolean(PREF_ENABLE_LOG, DEFAULT_LOG_ENABLED);
mThemeId = prefs.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT,
KeyboardSwitcher.DEFAULT_LAYOUT_ID);
sDBG = prefs.getBoolean(PREF_DEBUG_MODE, sDBG);
sLOGPRINT = prefs.getBoolean(PREF_DEBUG_MODE, sLOGPRINT);
prefs.registerOnSharedPreferenceChangeListener(this);
}
@ -134,13 +140,14 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mActualCharCount = 0;
mLogBuffer.clear();
mPrivacyLogBuffer.clear();
mRingCharBuffer.reset();
}
/**
* Check if the input string is safe as an entry or not.
*/
private static boolean checkStringDataSafe(String s) {
if (sDBG) {
if (DBG) {
Log.d(TAG, "Check String safety: " + s);
}
for (int i = 0; i < s.length(); ++i) {
@ -152,7 +159,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
}
private void addCountEntry(long time) {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Log counts. (4)");
}
mLogBuffer.add(new LogEntry (time, ID_DELETE_COUNT,
@ -171,7 +178,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
}
private void addThemeIdEntry(long time) {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Log theme Id. (1)");
}
mLogBuffer.add(new LogEntry (time, ID_THEME_ID,
@ -179,7 +186,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
}
private void addSettingsEntry(long time) {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Log settings. (1)");
}
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
@ -189,7 +196,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
}
private void addVersionNameEntry(long time) {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Log Version. (1)");
}
try {
@ -203,15 +210,15 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
}
private void addExceptionEntry(long time, String[] data) {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Log Exception. (1)");
}
mLogBuffer.add(new LogEntry(time, ID_EXCEPTION, data));
}
private void flushPrivacyLogSafely() {
if (sDBG) {
Log.d(TAG, "Log theme Id. (" + mPrivacyLogBuffer.size() + ")");
if (sLOGPRINT) {
Log.d(TAG, "Log obfuscated data. (" + mPrivacyLogBuffer.size() + ")");
}
long now = System.currentTimeMillis();
Collections.sort(mPrivacyLogBuffer);
@ -248,7 +255,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
++mWordCount;
String[] dataStrings = (String[]) data;
if (dataStrings.length < 2) {
if (sDBG) {
if (DBG) {
Log.e(TAG, "The length of logged string array is invalid.");
}
break;
@ -258,7 +265,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mPrivacyLogBuffer.add(
new LogEntry (System.currentTimeMillis(), tag, dataStrings));
} else {
if (sDBG) {
if (DBG) {
Log.d(TAG, "Skipped to add an entry because data is unsafe.");
}
}
@ -267,7 +274,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
--mWordCount;
dataStrings = (String[]) data;
if (dataStrings.length < 2) {
if (sDBG) {
if (DBG) {
Log.e(TAG, "The length of logged string array is invalid.");
}
break;
@ -277,7 +284,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mPrivacyLogBuffer.add(
new LogEntry (System.currentTimeMillis(), tag, dataStrings));
} else {
if (sDBG) {
if (DBG) {
Log.d(TAG, "Skipped to add an entry because data is unsafe.");
}
}
@ -285,7 +292,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
case ID_EXCEPTION:
dataStrings = (String[]) data;
if (dataStrings.length < 2) {
if (sDBG) {
if (DBG) {
Log.e(TAG, "The length of logged string array is invalid.");
}
break;
@ -293,7 +300,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
addExceptionEntry(System.currentTimeMillis(), dataStrings);
break;
default:
if (sDBG) {
if (DBG) {
Log.e(TAG, "Log Tag is not entried.");
}
break;
@ -301,7 +308,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
}
private void commitInternal() {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Commit (" + mLogBuffer.size() + ")");
}
flushPrivacyLogSafely();
@ -312,7 +319,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
addVersionNameEntry(now);
String s = LogSerializer.createStringFromEntries(mLogBuffer);
if (!TextUtils.isEmpty(s)) {
if (sDBG) {
if (sLOGPRINT) {
Log.d(TAG, "Commit log: " + s);
}
mDropBox.addText(TAG, s);
@ -329,7 +336,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private synchronized void sendLogToDropBox(int tag, Object s) {
long now = System.currentTimeMillis();
if (sDBG) {
if (DBG) {
String out = "";
if (s instanceof String[]) {
for (String str: ((String[]) s)) {
@ -367,7 +374,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
KeyboardSwitcher.DEFAULT_LAYOUT_ID);
addThemeIdEntry(mLastTimeActive);
} else if (PREF_DEBUG_MODE.equals(key)) {
sDBG = sharedPreferences.getBoolean(PREF_DEBUG_MODE, sDBG);
sLOGPRINT = sharedPreferences.getBoolean(PREF_DEBUG_MODE, sLOGPRINT);
}
}
@ -403,7 +410,9 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
before = "";
after = "";
}
String[] strings = new String[] {before, after};
sLastAutoSuggestSeparator =
String.valueOf(sLatinImeLogger.mRingCharBuffer.getLastChar());
String[] strings = new String[] {before, after, sLastAutoSuggestSeparator};
synchronized (LatinImeLogger.class) {
sLastAutoSuggestBefore = before;
sLastAutoSuggestAfter = after;
@ -415,21 +424,33 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void logOnAutoSuggestionCanceled() {
if (sLogEnabled) {
if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) {
String[] strings = new String[] {sLastAutoSuggestBefore, sLastAutoSuggestAfter};
String[] strings = new String[] {
sLastAutoSuggestBefore, sLastAutoSuggestAfter, sLastAutoSuggestSeparator};
sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTIONCANCELLED, strings);
}
synchronized (LatinImeLogger.class) {
sLastAutoSuggestBefore = "";
sLastAutoSuggestAfter = "";
}
}
}
public static void logOnDelete(int length) {
public static void logOnDelete() {
if (sLogEnabled) {
sLatinImeLogger.sendLogToDropBox(ID_DELETE_COUNT, length);
String mLastWord = sLatinImeLogger.mRingCharBuffer.getLastString();
if (!TextUtils.isEmpty(mLastWord)
&& mLastWord.equalsIgnoreCase(sLastAutoSuggestBefore)) {
logOnAutoSuggestionCanceled();
}
sLatinImeLogger.mRingCharBuffer.pop();
sLatinImeLogger.sendLogToDropBox(ID_DELETE_COUNT, 1);
}
}
public static void logOnInputChar(int length) {
public static void logOnInputChar(char c) {
if (sLogEnabled) {
sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, length);
sLatinImeLogger.mRingCharBuffer.push(c);
sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, 1);
}
}
@ -478,4 +499,59 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
return sb.toString();
}
}
/* package */ static class RingCharBuffer {
final int BUFSIZE = 20;
private Context mContext;
private int mEnd = 0;
/* package */ int length = 0;
private char[] mCharBuf = new char[BUFSIZE];
public RingCharBuffer(Context context) {
mContext = context;
}
private int normalize(int in) {
int ret = in % BUFSIZE;
return ret < 0 ? ret + BUFSIZE : ret;
}
public void push(char c) {
mCharBuf[mEnd] = c;
mEnd = normalize(mEnd + 1);
if (length < BUFSIZE) {
++length;
}
}
public char pop() {
if (length < 1) {
return NULL_CHAR;
} else {
mEnd = normalize(mEnd - 1);
--length;
return mCharBuf[mEnd];
}
}
public char getLastChar() {
if (length < 1) {
return NULL_CHAR;
} else {
return mCharBuf[normalize(mEnd - 1)];
}
}
public String getLastString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; ++i) {
char c = mCharBuf[normalize(mEnd - 1 - i)];
if (!((LatinIME)mContext).isWordSeparator(c)) {
sb.append(c);
} else {
break;
}
}
return sb.reverse().toString();
}
public void reset() {
length = 0;
}
}
}

View File

@ -10,7 +10,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := LatinIMETests
LOCAL_PACKAGE_NAME := LatinIME2Tests
LOCAL_INSTRUMENTATION_FOR := LatinIme2Google

View File

@ -27,7 +27,7 @@
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.inputmethod.latin"
android:targetPackage="com.google.android.inputmethod.latin"
android:label="LatinIME tests">
</instrumentation>
</manifest>

View File

@ -0,0 +1,59 @@
package com.android.inputmethod.latin;
import android.test.ServiceTestCase;
public class ImeLoggerTests extends ServiceTestCase<LatinIME> {
private static final String WORD_SEPARATORS
= ".\u0009\u0020,;:!?\n()[]*&@{}<>;_+=|\\u0022";
public ImeLoggerTests() {
super(LatinIME.class);
}
static LatinImeLogger sLogger;
@Override
protected void setUp() {
try {
super.setUp();
} catch (Exception e) {
e.printStackTrace();
}
setupService();
// startService(null); // can't be started because VoiceInput can't be found.
final LatinIME context = getService();
context.mWordSeparators = WORD_SEPARATORS;
LatinImeLogger.init(context);
sLogger = LatinImeLogger.sLatinImeLogger;
}
/*********************** Tests *********************/
public void testRingBuffer() {
for (int i = 0; i < sLogger.mRingCharBuffer.BUFSIZE * 2; ++i) {
LatinImeLogger.logOnDelete();
}
assertEquals("", sLogger.mRingCharBuffer.getLastString());
LatinImeLogger.logOnInputChar('t');
LatinImeLogger.logOnInputChar('g');
LatinImeLogger.logOnInputChar('i');
LatinImeLogger.logOnInputChar('s');
LatinImeLogger.logOnInputChar(' ');
LatinImeLogger.logOnAutoSuggestion("tgis", "this");
LatinImeLogger.logOnInputChar(' ');
LatinImeLogger.logOnDelete();
assertEquals("", sLogger.mRingCharBuffer.getLastString());
LatinImeLogger.logOnDelete();
assertEquals("tgis", sLogger.mRingCharBuffer.getLastString());
assertEquals("tgis", LatinImeLogger.sLastAutoSuggestBefore);
LatinImeLogger.logOnAutoSuggestionCanceled();
assertEquals("", LatinImeLogger.sLastAutoSuggestBefore);
LatinImeLogger.logOnDelete();
assertEquals("tgi", sLogger.mRingCharBuffer.getLastString());
for (int i = 0; i < sLogger.mRingCharBuffer.BUFSIZE * 2; ++i) {
LatinImeLogger.logOnDelete();
}
assertEquals("", sLogger.mRingCharBuffer.getLastString());
for (int i = 0; i < sLogger.mRingCharBuffer.BUFSIZE * 2; ++i) {
LatinImeLogger.logOnInputChar('a');
}
assertEquals(sLogger.mRingCharBuffer.BUFSIZE, sLogger.mRingCharBuffer.length);
}
}

View File

@ -241,8 +241,11 @@ public class SuggestTests extends AndroidTestCase {
* Are accented forms of words suggested as corrections?
*/
public void testAccents() {
assertTrue(isDefaultCorrection("nino", "ni\u00F1o")); // nio
assertTrue(isDefaultCorrection("nimo", "ni\u00F1o")); // nio
assertTrue(isDefaultCorrection("maria", "Mar\u00EDa")); // Mara
// ni<LATIN SMALL LETTER N WITH TILDE>o
assertTrue(isDefaultCorrection("nino", "ni\u00F1o"));
// ni<LATIN SMALL LETTER N WITH TILDE>o
assertTrue(isDefaultCorrection("nimo", "ni\u00F1o"));
// Mar<LATIN SMALL LETTER I WITH ACUTE>a
assertTrue(isDefaultCorrection("maria", "Mar\u00EDa"));
}
}