diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java index 93f1985ca..94331d3f2 100644 --- a/java/src/com/android/inputmethod/latin/AutoDictionary.java +++ b/java/src/com/android/inputmethod/latin/AutoDictionary.java @@ -85,8 +85,8 @@ public class AutoDictionary extends ExpandableDictionary { private static DatabaseHelper mOpenHelper = null; - public AutoDictionary(Context context, LatinIME ime, String locale) { - super(context); + public AutoDictionary(Context context, LatinIME ime, String locale, int dicTypeId) { + super(context, dicTypeId); mIme = ime; mLocale = locale; if (mOpenHelper == null) { diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 5d3df4e6c..9e7dfa3a1 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -24,7 +24,6 @@ import java.nio.channels.Channels; import java.util.Arrays; import android.content.Context; -import android.content.res.AssetManager; import android.util.Log; /** @@ -40,6 +39,7 @@ public class BinaryDictionary extends Dictionary { private static final int TYPED_LETTER_MULTIPLIER = 2; private static final boolean ENABLE_MISSED_CHARACTERS = true; + private int mDicTypeId; private int mNativeDict; private int mDictLength; private int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES]; @@ -62,10 +62,11 @@ public class BinaryDictionary extends Dictionary { * @param context application context for reading resources * @param resId the resource containing the raw binary dictionary */ - public BinaryDictionary(Context context, int resId) { + public BinaryDictionary(Context context, int resId, int dicTypeId) { if (resId != 0) { loadDictionary(context, resId); } + mDicTypeId = dicTypeId; } /** @@ -73,7 +74,7 @@ public class BinaryDictionary extends Dictionary { * @param context application context for reading resources * @param resId the resource containing the raw binary dictionary */ - public BinaryDictionary(Context context, ByteBuffer byteBuffer) { + public BinaryDictionary(Context context, ByteBuffer byteBuffer, int dicTypeId) { if (byteBuffer != null) { if (byteBuffer.isDirect()) { mNativeDictDirectBuffer = byteBuffer; @@ -86,6 +87,7 @@ public class BinaryDictionary extends Dictionary { mNativeDict = openNative(mNativeDictDirectBuffer, TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER); } + mDicTypeId = dicTypeId; } private native int openNative(ByteBuffer bb, int typedLetterMultiplier, int fullWordMultiplier); @@ -166,7 +168,7 @@ public class BinaryDictionary extends Dictionary { len++; } if (len > 0) { - callback.addWord(mOutputChars, start, len, mFrequencies[j]); + callback.addWord(mOutputChars, start, len, mFrequencies[j], mDicTypeId); } } } diff --git a/java/src/com/android/inputmethod/latin/ContactsDictionary.java b/java/src/com/android/inputmethod/latin/ContactsDictionary.java index 15edb706a..f5ff865c4 100644 --- a/java/src/com/android/inputmethod/latin/ContactsDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsDictionary.java @@ -20,7 +20,6 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; -import android.os.AsyncTask; import android.os.SystemClock; import android.provider.ContactsContract.Contacts; @@ -37,21 +36,23 @@ public class ContactsDictionary extends ExpandableDictionary { private long mLastLoadedContacts; - public ContactsDictionary(Context context) { - super(context); + public ContactsDictionary(Context context, int dicTypeId) { + super(context, dicTypeId); // Perform a managed query. The Activity will handle closing and requerying the cursor // when needed. ContentResolver cres = context.getContentResolver(); - cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) { - @Override - public void onChange(boolean self) { - setRequiresReload(true); - } - }); + cres.registerContentObserver( + Contacts.CONTENT_URI, true,mObserver = new ContentObserver(null) { + @Override + public void onChange(boolean self) { + setRequiresReload(true); + } + }); loadDictionary(); } + @Override public synchronized void close() { if (mObserver != null) { getContext().getContentResolver().unregisterContentObserver(mObserver); diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index e7b526663..e38a32fa1 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -45,9 +45,10 @@ abstract public class Dictionary { * @param wordLength length of valid characters in the character array * @param frequency the frequency of occurence. This is normalized between 1 and 255, but * can exceed those limits + * @param dicTypeId of the dictionary where word was from * @return true if the word was added, false if no more words are required */ - boolean addWord(char[] word, int wordOffset, int wordLength, int frequency); + boolean addWord(char[] word, int wordOffset, int wordLength, int frequency, int dicTypeId); } /** diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 46bc41c42..e2a812796 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -16,11 +16,8 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.Dictionary.WordCallback; - import android.content.Context; import android.os.AsyncTask; -import android.os.SystemClock; /** * Base class for an in-memory dictionary that can grow dynamically and can @@ -29,6 +26,7 @@ import android.os.SystemClock; public class ExpandableDictionary extends Dictionary { private Context mContext; private char[] mWordBuilder = new char[MAX_WORD_LENGTH]; + private int mDicTypeId; private int mMaxDepth; private int mInputLength; private int[] mNextLettersFrequencies; @@ -75,10 +73,11 @@ public class ExpandableDictionary extends Dictionary { private int[][] mCodes; - ExpandableDictionary(Context context) { + ExpandableDictionary(Context context, int dicTypeId) { mContext = context; clearDictionary(); mCodes = new int[MAX_WORD_LENGTH][]; + mDicTypeId = dicTypeId; } public void loadDictionary() { @@ -267,7 +266,7 @@ public class ExpandableDictionary extends Dictionary { if (completion) { word[depth] = c; if (terminal) { - if (!callback.addWord(word, 0, depth + 1, freq * snr)) { + if (!callback.addWord(word, 0, depth + 1, freq * snr, mDicTypeId)) { return; } // Add to frequency of next letters for predictive correction @@ -305,7 +304,7 @@ public class ExpandableDictionary extends Dictionary { || !same(word, depth + 1, codes.getTypedWord())) { int finalFreq = freq * snr * addedAttenuation; if (skipPos < 0) finalFreq *= FULL_WORD_FREQ_MULTIPLIER; - callback.addWord(word, 0, depth + 1, finalFreq); + callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId); } } if (children != null) { diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java index 5e835e543..718fda18d 100644 --- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java @@ -99,7 +99,7 @@ public class InputLanguageSelection extends PreferenceActivity { boolean haveDictionary = false; conf.locale = locale; res.updateConfiguration(conf, res.getDisplayMetrics()); - BinaryDictionary bd = new BinaryDictionary(this, R.raw.main); + BinaryDictionary bd = new BinaryDictionary(this, R.raw.main, Suggest.DIC_MAIN); // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. if (bd.getSize() > Suggest.LARGE_DICTIONARY_THRESHOLD / 4) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 35edb8ae7..93c69ee71 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -331,12 +331,12 @@ public class LatinIME extends InputMethodService if (mUserDictionary != null) mUserDictionary.close(); mUserDictionary = new UserDictionary(this, mInputLocale); if (mContactsDictionary == null) { - mContactsDictionary = new ContactsDictionary(this); + mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS); } if (mAutoDictionary != null) { mAutoDictionary.close(); } - mAutoDictionary = new AutoDictionary(this, this, mInputLocale); + mAutoDictionary = new AutoDictionary(this, this, mInputLocale, Suggest.DIC_AUTO); mSuggest.setUserDictionary(mUserDictionary); mSuggest.setContactsDictionary(mContactsDictionary); mSuggest.setAutoDictionary(mAutoDictionary); diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 736b0af54..4f757d721 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -29,7 +29,9 @@ import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = "LatinIMELogs"; @@ -56,6 +58,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang private static final int ID_SETTING_AUTO_COMPLETE = 8; private static final int ID_VERSION = 9; private static final int ID_EXCEPTION = 10; + private static final int ID_SUGGESTIONCOUNT = 11; private static final String PREF_ENABLE_LOG = "enable_logging"; private static final String PREF_DEBUG_MODE = "debug_mode"; @@ -68,6 +71,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang /* package */ static String sLastAutoSuggestBefore; /* package */ static String sLastAutoSuggestAfter; /* package */ static String sLastAutoSuggestSeparator; + private static HashMap sSuggestDicMap = new HashMap(); private ArrayList mLogBuffer = null; private ArrayList mPrivacyLogBuffer = null; @@ -83,6 +87,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang private int mDeleteCount; private int mInputCount; private int mWordCount; + private int[] mAutoSuggestCountPerDic = new int[Suggest.DIC_TYPE_LAST_ID + 1]; + private int mAutoCancelledCount; // ActualCharCount includes all characters that were completed. private int mActualCharCount; @@ -119,6 +125,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang mInputCount = 0; mWordCount = 0; mActualCharCount = 0; + Arrays.fill(mAutoSuggestCountPerDic, 0); + mAutoCancelledCount = 0; mLogBuffer = new ArrayList(); mPrivacyLogBuffer = new ArrayList(); mRingCharBuffer = new RingCharBuffer(context); @@ -138,6 +146,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang mInputCount = 0; mWordCount = 0; mActualCharCount = 0; + Arrays.fill(mAutoSuggestCountPerDic, 0); + mAutoCancelledCount = 0; mLogBuffer.clear(); mPrivacyLogBuffer.clear(); mRingCharBuffer.reset(); @@ -177,6 +187,18 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang mLastTimeCountEntry = time; } + private void addSuggestionCountEntry(long time) { + if (sLOGPRINT) { + Log.d(TAG, "log suggest counts. (1)"); + } + String[] s = new String[mAutoSuggestCountPerDic.length + 1]; + s[0] = String.valueOf(mAutoCancelledCount); + for (int i = 1; i < s.length; ++i) { + s[i] = String.valueOf(mAutoSuggestCountPerDic[i - 1]); + } + mLogBuffer.add(new LogEntry(time, ID_SUGGESTIONCOUNT, s)); + } + private void addThemeIdEntry(long time) { if (sLOGPRINT) { Log.d(TAG, "Log theme Id. (1)"); @@ -317,6 +339,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang addThemeIdEntry(now); addSettingsEntry(now); addVersionNameEntry(now); + addSuggestionCountEntry(now); String s = LogSerializer.createStringFromEntries(mLogBuffer); if (!TextUtils.isEmpty(s)) { if (sLOGPRINT) { @@ -406,6 +429,21 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void logOnAutoSuggestion(String before, String after) { if (sLogEnabled) { + if (!sSuggestDicMap.containsKey(after)) { + if (DBG) { + Log.e(TAG, "logOnAutoSuggestion was cancelled: came from unknown source."); + } + return; + } + int dicId = sSuggestDicMap.get(after); + sLatinImeLogger.mAutoSuggestCountPerDic[dicId]++; + sSuggestDicMap.clear(); + if (dicId != Suggest.DIC_MAIN) { + if (DBG) { + Log.d(TAG, "logOnAutoSuggestion was cancelled: didn't come from main dic."); + } + return; + } if (before.equals(after)) { before = ""; after = ""; @@ -423,6 +461,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void logOnAutoSuggestionCanceled() { if (sLogEnabled) { + sLatinImeLogger.mAutoCancelledCount++; if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) { String[] strings = new String[] { sLastAutoSuggestBefore, sLastAutoSuggestAfter, sLastAutoSuggestSeparator}; @@ -471,6 +510,18 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang } } + public static void onStartSuggestion() { + if (sLogEnabled) { + sSuggestDicMap.clear(); + } + } + + public static void onAddSuggestedWord(String word, int typeId) { + if (sLogEnabled) { + sSuggestDicMap.put(word, typeId); + } + } + private static class LogSerializer { private static void appendWithLength(StringBuffer sb, String data) { sb.append(data.length()); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 010913d6d..8ef6c07f8 100755 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -38,6 +38,14 @@ public class Suggest implements Dictionary.WordCallback { public static final int CORRECTION_BASIC = 1; public static final int CORRECTION_FULL = 2; + public static final int DIC_USER_TYPED = 0; + public static final int DIC_MAIN = 1; + public static final int DIC_USER = 2; + public static final int DIC_AUTO = 3; + public static final int DIC_CONTACTS = 4; + // If you add a type of dictionary, increment DIC_TYPE_LAST_ID + public static final int DIC_TYPE_LAST_ID = 4; + static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000; private BinaryDictionary mMainDict; @@ -69,12 +77,12 @@ public class Suggest implements Dictionary.WordCallback { private int mCorrectionMode = CORRECTION_BASIC; public Suggest(Context context, int dictionaryResId) { - mMainDict = new BinaryDictionary(context, dictionaryResId); + mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN); initPool(); } public Suggest(Context context, ByteBuffer byteBuffer) { - mMainDict = new BinaryDictionary(context, byteBuffer); + mMainDict = new BinaryDictionary(context, byteBuffer, DIC_MAIN); initPool(); } @@ -177,6 +185,7 @@ public class Suggest implements Dictionary.WordCallback { */ public List getSuggestions(View view, WordComposer wordComposer, boolean includeTypedWordIfValid) { + LatinImeLogger.onStartSuggestion(); mHaveCorrection = false; mCapitalize = wordComposer.isCapitalized(); collectGarbage(); @@ -191,6 +200,7 @@ public class Suggest implements Dictionary.WordCallback { } else { mLowerOriginalWord = ""; } + LatinImeLogger.onAddSuggestedWord(mOriginalWord.toString(), Suggest.DIC_USER_TYPED); // Search the dictionary only if there are at least 2 characters if (wordComposer.size() > 1) { if (mUserDictionary != null || mContactsDictionary != null) { @@ -301,7 +311,8 @@ public class Suggest implements Dictionary.WordCallback { return false; } - public boolean addWord(final char[] word, final int offset, final int length, final int freq) { + public boolean addWord(final char[] word, final int offset, final int length, + final int freq, final int dicTypeId) { int pos = 0; final int[] priorities = mPriorities; final int prefMaxSuggestions = mPrefMaxSuggestions; @@ -320,7 +331,7 @@ public class Suggest implements Dictionary.WordCallback { pos++; } } - + if (pos >= prefMaxSuggestions) { return true; } @@ -345,6 +356,8 @@ public class Suggest implements Dictionary.WordCallback { if (garbage instanceof StringBuilder) { mStringPool.add(garbage); } + } else { + LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId); } return true; } diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java index e8ca33af3..3315cf6c9 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -38,7 +38,7 @@ public class UserDictionary extends ExpandableDictionary { private String mLocale; public UserDictionary(Context context, String locale) { - super(context); + super(context, Suggest.DIC_USER); mLocale = locale; // Perform a managed query. The Activity will handle closing and requerying the cursor // when needed. @@ -54,6 +54,7 @@ public class UserDictionary extends ExpandableDictionary { loadDictionary(); } + @Override public synchronized void close() { if (mObserver != null) { getContext().getContentResolver().unregisterContentObserver(mObserver);