Check suggested words whether they are from mainDic or not

- Added counters for suggestions by dictionarys
- Added a counter for cancelled suggestions

Change-Id: Ia7d3a73855b1e82b60a010f18dba4e1c0fe1c2bb
main
satok 2010-06-02 18:30:27 +09:00
parent 7f96616c75
commit 4ee3676cf3
10 changed files with 98 additions and 30 deletions

View File

@ -85,8 +85,8 @@ public class AutoDictionary extends ExpandableDictionary {
private static DatabaseHelper mOpenHelper = null; private static DatabaseHelper mOpenHelper = null;
public AutoDictionary(Context context, LatinIME ime, String locale) { public AutoDictionary(Context context, LatinIME ime, String locale, int dicTypeId) {
super(context); super(context, dicTypeId);
mIme = ime; mIme = ime;
mLocale = locale; mLocale = locale;
if (mOpenHelper == null) { if (mOpenHelper == null) {

View File

@ -24,7 +24,6 @@ import java.nio.channels.Channels;
import java.util.Arrays; import java.util.Arrays;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log; import android.util.Log;
/** /**
@ -40,6 +39,7 @@ public class BinaryDictionary extends Dictionary {
private static final int TYPED_LETTER_MULTIPLIER = 2; private static final int TYPED_LETTER_MULTIPLIER = 2;
private static final boolean ENABLE_MISSED_CHARACTERS = true; private static final boolean ENABLE_MISSED_CHARACTERS = true;
private int mDicTypeId;
private int mNativeDict; private int mNativeDict;
private int mDictLength; private int mDictLength;
private int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES]; 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 context application context for reading resources
* @param resId the resource containing the raw binary dictionary * @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) { if (resId != 0) {
loadDictionary(context, resId); loadDictionary(context, resId);
} }
mDicTypeId = dicTypeId;
} }
/** /**
@ -73,7 +74,7 @@ public class BinaryDictionary extends Dictionary {
* @param context application context for reading resources * @param context application context for reading resources
* @param resId the resource containing the raw binary dictionary * @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 != null) {
if (byteBuffer.isDirect()) { if (byteBuffer.isDirect()) {
mNativeDictDirectBuffer = byteBuffer; mNativeDictDirectBuffer = byteBuffer;
@ -86,6 +87,7 @@ public class BinaryDictionary extends Dictionary {
mNativeDict = openNative(mNativeDictDirectBuffer, mNativeDict = openNative(mNativeDictDirectBuffer,
TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER); TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER);
} }
mDicTypeId = dicTypeId;
} }
private native int openNative(ByteBuffer bb, int typedLetterMultiplier, int fullWordMultiplier); private native int openNative(ByteBuffer bb, int typedLetterMultiplier, int fullWordMultiplier);
@ -166,7 +168,7 @@ public class BinaryDictionary extends Dictionary {
len++; len++;
} }
if (len > 0) { if (len > 0) {
callback.addWord(mOutputChars, start, len, mFrequencies[j]); callback.addWord(mOutputChars, start, len, mFrequencies[j], mDicTypeId);
} }
} }
} }

View File

@ -20,7 +20,6 @@ import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.database.Cursor; import android.database.Cursor;
import android.os.AsyncTask;
import android.os.SystemClock; import android.os.SystemClock;
import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Contacts;
@ -37,21 +36,23 @@ public class ContactsDictionary extends ExpandableDictionary {
private long mLastLoadedContacts; private long mLastLoadedContacts;
public ContactsDictionary(Context context) { public ContactsDictionary(Context context, int dicTypeId) {
super(context); super(context, dicTypeId);
// Perform a managed query. The Activity will handle closing and requerying the cursor // Perform a managed query. The Activity will handle closing and requerying the cursor
// when needed. // when needed.
ContentResolver cres = context.getContentResolver(); ContentResolver cres = context.getContentResolver();
cres.registerContentObserver(Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) { cres.registerContentObserver(
@Override Contacts.CONTENT_URI, true,mObserver = new ContentObserver(null) {
public void onChange(boolean self) { @Override
setRequiresReload(true); public void onChange(boolean self) {
} setRequiresReload(true);
}); }
});
loadDictionary(); loadDictionary();
} }
@Override
public synchronized void close() { public synchronized void close() {
if (mObserver != null) { if (mObserver != null) {
getContext().getContentResolver().unregisterContentObserver(mObserver); getContext().getContentResolver().unregisterContentObserver(mObserver);

View File

@ -45,9 +45,10 @@ abstract public class Dictionary {
* @param wordLength length of valid characters in the character array * @param wordLength length of valid characters in the character array
* @param frequency the frequency of occurence. This is normalized between 1 and 255, but * @param frequency the frequency of occurence. This is normalized between 1 and 255, but
* can exceed those limits * 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 * @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);
} }
/** /**

View File

@ -16,11 +16,8 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import com.android.inputmethod.latin.Dictionary.WordCallback;
import android.content.Context; import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.SystemClock;
/** /**
* Base class for an in-memory dictionary that can grow dynamically and can * 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 { public class ExpandableDictionary extends Dictionary {
private Context mContext; private Context mContext;
private char[] mWordBuilder = new char[MAX_WORD_LENGTH]; private char[] mWordBuilder = new char[MAX_WORD_LENGTH];
private int mDicTypeId;
private int mMaxDepth; private int mMaxDepth;
private int mInputLength; private int mInputLength;
private int[] mNextLettersFrequencies; private int[] mNextLettersFrequencies;
@ -75,10 +73,11 @@ public class ExpandableDictionary extends Dictionary {
private int[][] mCodes; private int[][] mCodes;
ExpandableDictionary(Context context) { ExpandableDictionary(Context context, int dicTypeId) {
mContext = context; mContext = context;
clearDictionary(); clearDictionary();
mCodes = new int[MAX_WORD_LENGTH][]; mCodes = new int[MAX_WORD_LENGTH][];
mDicTypeId = dicTypeId;
} }
public void loadDictionary() { public void loadDictionary() {
@ -267,7 +266,7 @@ public class ExpandableDictionary extends Dictionary {
if (completion) { if (completion) {
word[depth] = c; word[depth] = c;
if (terminal) { if (terminal) {
if (!callback.addWord(word, 0, depth + 1, freq * snr)) { if (!callback.addWord(word, 0, depth + 1, freq * snr, mDicTypeId)) {
return; return;
} }
// Add to frequency of next letters for predictive correction // Add to frequency of next letters for predictive correction
@ -305,7 +304,7 @@ public class ExpandableDictionary extends Dictionary {
|| !same(word, depth + 1, codes.getTypedWord())) { || !same(word, depth + 1, codes.getTypedWord())) {
int finalFreq = freq * snr * addedAttenuation; int finalFreq = freq * snr * addedAttenuation;
if (skipPos < 0) finalFreq *= FULL_WORD_FREQ_MULTIPLIER; 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) { if (children != null) {

View File

@ -99,7 +99,7 @@ public class InputLanguageSelection extends PreferenceActivity {
boolean haveDictionary = false; boolean haveDictionary = false;
conf.locale = locale; conf.locale = locale;
res.updateConfiguration(conf, res.getDisplayMetrics()); 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 // Is the dictionary larger than a placeholder? Arbitrarily chose a lower limit of
// 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words. // 4000-5000 words, whereas the LARGE_DICTIONARY is about 20000+ words.
if (bd.getSize() > Suggest.LARGE_DICTIONARY_THRESHOLD / 4) { if (bd.getSize() > Suggest.LARGE_DICTIONARY_THRESHOLD / 4) {

View File

@ -331,12 +331,12 @@ public class LatinIME extends InputMethodService
if (mUserDictionary != null) mUserDictionary.close(); if (mUserDictionary != null) mUserDictionary.close();
mUserDictionary = new UserDictionary(this, mInputLocale); mUserDictionary = new UserDictionary(this, mInputLocale);
if (mContactsDictionary == null) { if (mContactsDictionary == null) {
mContactsDictionary = new ContactsDictionary(this); mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
} }
if (mAutoDictionary != null) { if (mAutoDictionary != null) {
mAutoDictionary.close(); mAutoDictionary.close();
} }
mAutoDictionary = new AutoDictionary(this, this, mInputLocale); mAutoDictionary = new AutoDictionary(this, this, mInputLocale, Suggest.DIC_AUTO);
mSuggest.setUserDictionary(mUserDictionary); mSuggest.setUserDictionary(mUserDictionary);
mSuggest.setContactsDictionary(mContactsDictionary); mSuggest.setContactsDictionary(mContactsDictionary);
mSuggest.setAutoDictionary(mAutoDictionary); mSuggest.setAutoDictionary(mAutoDictionary);

View File

@ -29,7 +29,9 @@ import android.util.Log;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener { public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "LatinIMELogs"; 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_SETTING_AUTO_COMPLETE = 8;
private static final int ID_VERSION = 9; private static final int ID_VERSION = 9;
private static final int ID_EXCEPTION = 10; 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_ENABLE_LOG = "enable_logging";
private static final String PREF_DEBUG_MODE = "debug_mode"; 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 sLastAutoSuggestBefore;
/* package */ static String sLastAutoSuggestAfter; /* package */ static String sLastAutoSuggestAfter;
/* package */ static String sLastAutoSuggestSeparator; /* package */ static String sLastAutoSuggestSeparator;
private static HashMap<String, Integer> sSuggestDicMap = new HashMap<String, Integer>();
private ArrayList<LogEntry> mLogBuffer = null; private ArrayList<LogEntry> mLogBuffer = null;
private ArrayList<LogEntry> mPrivacyLogBuffer = null; private ArrayList<LogEntry> mPrivacyLogBuffer = null;
@ -83,6 +87,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
private int mDeleteCount; private int mDeleteCount;
private int mInputCount; private int mInputCount;
private int mWordCount; private int mWordCount;
private int[] mAutoSuggestCountPerDic = new int[Suggest.DIC_TYPE_LAST_ID + 1];
private int mAutoCancelledCount;
// ActualCharCount includes all characters that were completed. // ActualCharCount includes all characters that were completed.
private int mActualCharCount; private int mActualCharCount;
@ -119,6 +125,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mInputCount = 0; mInputCount = 0;
mWordCount = 0; mWordCount = 0;
mActualCharCount = 0; mActualCharCount = 0;
Arrays.fill(mAutoSuggestCountPerDic, 0);
mAutoCancelledCount = 0;
mLogBuffer = new ArrayList<LogEntry>(); mLogBuffer = new ArrayList<LogEntry>();
mPrivacyLogBuffer = new ArrayList<LogEntry>(); mPrivacyLogBuffer = new ArrayList<LogEntry>();
mRingCharBuffer = new RingCharBuffer(context); mRingCharBuffer = new RingCharBuffer(context);
@ -138,6 +146,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mInputCount = 0; mInputCount = 0;
mWordCount = 0; mWordCount = 0;
mActualCharCount = 0; mActualCharCount = 0;
Arrays.fill(mAutoSuggestCountPerDic, 0);
mAutoCancelledCount = 0;
mLogBuffer.clear(); mLogBuffer.clear();
mPrivacyLogBuffer.clear(); mPrivacyLogBuffer.clear();
mRingCharBuffer.reset(); mRingCharBuffer.reset();
@ -177,6 +187,18 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
mLastTimeCountEntry = time; 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) { private void addThemeIdEntry(long time) {
if (sLOGPRINT) { if (sLOGPRINT) {
Log.d(TAG, "Log theme Id. (1)"); Log.d(TAG, "Log theme Id. (1)");
@ -317,6 +339,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
addThemeIdEntry(now); addThemeIdEntry(now);
addSettingsEntry(now); addSettingsEntry(now);
addVersionNameEntry(now); addVersionNameEntry(now);
addSuggestionCountEntry(now);
String s = LogSerializer.createStringFromEntries(mLogBuffer); String s = LogSerializer.createStringFromEntries(mLogBuffer);
if (!TextUtils.isEmpty(s)) { if (!TextUtils.isEmpty(s)) {
if (sLOGPRINT) { if (sLOGPRINT) {
@ -406,6 +429,21 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void logOnAutoSuggestion(String before, String after) { public static void logOnAutoSuggestion(String before, String after) {
if (sLogEnabled) { 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)) { if (before.equals(after)) {
before = ""; before = "";
after = ""; after = "";
@ -423,6 +461,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void logOnAutoSuggestionCanceled() { public static void logOnAutoSuggestionCanceled() {
if (sLogEnabled) { if (sLogEnabled) {
sLatinImeLogger.mAutoCancelledCount++;
if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) { if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) {
String[] strings = new String[] { String[] strings = new String[] {
sLastAutoSuggestBefore, sLastAutoSuggestAfter, sLastAutoSuggestSeparator}; 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 class LogSerializer {
private static void appendWithLength(StringBuffer sb, String data) { private static void appendWithLength(StringBuffer sb, String data) {
sb.append(data.length()); sb.append(data.length());

View File

@ -38,6 +38,14 @@ public class Suggest implements Dictionary.WordCallback {
public static final int CORRECTION_BASIC = 1; public static final int CORRECTION_BASIC = 1;
public static final int CORRECTION_FULL = 2; 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; static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
private BinaryDictionary mMainDict; private BinaryDictionary mMainDict;
@ -69,12 +77,12 @@ public class Suggest implements Dictionary.WordCallback {
private int mCorrectionMode = CORRECTION_BASIC; private int mCorrectionMode = CORRECTION_BASIC;
public Suggest(Context context, int dictionaryResId) { public Suggest(Context context, int dictionaryResId) {
mMainDict = new BinaryDictionary(context, dictionaryResId); mMainDict = new BinaryDictionary(context, dictionaryResId, DIC_MAIN);
initPool(); initPool();
} }
public Suggest(Context context, ByteBuffer byteBuffer) { public Suggest(Context context, ByteBuffer byteBuffer) {
mMainDict = new BinaryDictionary(context, byteBuffer); mMainDict = new BinaryDictionary(context, byteBuffer, DIC_MAIN);
initPool(); initPool();
} }
@ -177,6 +185,7 @@ public class Suggest implements Dictionary.WordCallback {
*/ */
public List<CharSequence> getSuggestions(View view, WordComposer wordComposer, public List<CharSequence> getSuggestions(View view, WordComposer wordComposer,
boolean includeTypedWordIfValid) { boolean includeTypedWordIfValid) {
LatinImeLogger.onStartSuggestion();
mHaveCorrection = false; mHaveCorrection = false;
mCapitalize = wordComposer.isCapitalized(); mCapitalize = wordComposer.isCapitalized();
collectGarbage(); collectGarbage();
@ -191,6 +200,7 @@ public class Suggest implements Dictionary.WordCallback {
} else { } else {
mLowerOriginalWord = ""; mLowerOriginalWord = "";
} }
LatinImeLogger.onAddSuggestedWord(mOriginalWord.toString(), Suggest.DIC_USER_TYPED);
// Search the dictionary only if there are at least 2 characters // Search the dictionary only if there are at least 2 characters
if (wordComposer.size() > 1) { if (wordComposer.size() > 1) {
if (mUserDictionary != null || mContactsDictionary != null) { if (mUserDictionary != null || mContactsDictionary != null) {
@ -301,7 +311,8 @@ public class Suggest implements Dictionary.WordCallback {
return false; 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; int pos = 0;
final int[] priorities = mPriorities; final int[] priorities = mPriorities;
final int prefMaxSuggestions = mPrefMaxSuggestions; final int prefMaxSuggestions = mPrefMaxSuggestions;
@ -345,6 +356,8 @@ public class Suggest implements Dictionary.WordCallback {
if (garbage instanceof StringBuilder) { if (garbage instanceof StringBuilder) {
mStringPool.add(garbage); mStringPool.add(garbage);
} }
} else {
LatinImeLogger.onAddSuggestedWord(sb.toString(), dicTypeId);
} }
return true; return true;
} }

View File

@ -38,7 +38,7 @@ public class UserDictionary extends ExpandableDictionary {
private String mLocale; private String mLocale;
public UserDictionary(Context context, String locale) { public UserDictionary(Context context, String locale) {
super(context); super(context, Suggest.DIC_USER);
mLocale = locale; mLocale = locale;
// Perform a managed query. The Activity will handle closing and requerying the cursor // Perform a managed query. The Activity will handle closing and requerying the cursor
// when needed. // when needed.
@ -54,6 +54,7 @@ public class UserDictionary extends ExpandableDictionary {
loadDictionary(); loadDictionary();
} }
@Override
public synchronized void close() { public synchronized void close() {
if (mObserver != null) { if (mObserver != null) {
getContext().getContentResolver().unregisterContentObserver(mObserver); getContext().getContentResolver().unregisterContentObserver(mObserver);