diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java index 93f1985ca4bd0cc23e7c27e0ba039a7e4dc3bf30..94331d3f2df2a5fc4a9355cf44d84d99c38b8c6e 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 5d3df4e6c91061ce6b5435a206c97b264d6a2cbe..9e7dfa3a1908df96812557f95ed4a3aa773705ca 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 15edb706a3bc44cf9050e0a61af4757eb866b39f..f5ff865c4d8493e8a3869a898ec7e14b48040abd 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 e7b52666338b8d934d11c22ee04ccf04b72075c4..e38a32fa1bd49e316548f27af9ce24cbcd46652c 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 46bc41c4236543abc5377f9a264c65dc4e89ddd6..e2a812796d82d64acc4e1603d8f46e4eecac68a0 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 5e835e543a7042b1a26ee52a37d17ed33f6a761f..718fda18de210a9c4238258b21f5d1e9d11a808e 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 35edb8ae713b232952097e6d0eac04ae0c1b70c2..93c69ee7186f1e9353c9ad7ebfce41b2c7dfd60b 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 736b0af5436da6fa7a3b91810e1f5c59ff4ccf8f..4f757d721ef78d37cdeb32ed4a63c919e364da93 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<String, Integer> sSuggestDicMap = new HashMap<String, Integer>(); private ArrayList<LogEntry> mLogBuffer = null; private ArrayList<LogEntry> 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<LogEntry>(); mPrivacyLogBuffer = new ArrayList<LogEntry>(); 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 010913d6d6276f7235b6a36e55843aac99954a8b..8ef6c07f86da650c4b127645b3382f5c0e2dd50d 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<CharSequence> 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 e8ca33af38fe894dc6bd3d0f89f6cf91353bef44..3315cf6c9d4d5ed7c2258d79157fe559296804f9 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);