diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index 10be866af..b4a5ab60c 100755
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -1,7 +1,7 @@
+ android:versionName="0.14">
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index b15de6bd5..35edb8ae7 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -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;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index b497c0c66..736b0af54 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -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 mLogBuffer = null;
private ArrayList 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();
mPrivacyLogBuffer = new ArrayList();
+ 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;
+ }
+ }
}
diff --git a/tests/Android.mk b/tests/Android.mk
index e72587ddd..60e82d5c2 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -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
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 210e81489..66cecee8b 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -27,7 +27,7 @@
diff --git a/tests/src/com/android/inputmethod/latin/ImeLoggerTests.java b/tests/src/com/android/inputmethod/latin/ImeLoggerTests.java
new file mode 100644
index 000000000..234559bb7
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/ImeLoggerTests.java
@@ -0,0 +1,59 @@
+package com.android.inputmethod.latin;
+
+import android.test.ServiceTestCase;
+
+public class ImeLoggerTests extends ServiceTestCase {
+
+ 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);
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/tests/SuggestTests.java b/tests/src/com/android/inputmethod/latin/tests/SuggestTests.java
index 9401d926a..0d3babfbc 100644
--- a/tests/src/com/android/inputmethod/latin/tests/SuggestTests.java
+++ b/tests/src/com/android/inputmethod/latin/tests/SuggestTests.java
@@ -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")); // ni–o
- assertTrue(isDefaultCorrection("nimo", "ni\u00F1o")); // ni–o
- assertTrue(isDefaultCorrection("maria", "Mar\u00EDa")); // Mar’a
+ // nio
+ assertTrue(isDefaultCorrection("nino", "ni\u00F1o"));
+ // nio
+ assertTrue(isDefaultCorrection("nimo", "ni\u00F1o"));
+ // Mara
+ assertTrue(isDefaultCorrection("maria", "Mar\u00EDa"));
}
}