[AC4] Add native methods necessary for auto-commit

Bug: 9059617
Change-Id: I7a47b0675446fc4f39628c60d16de9aea90d1b4d
main
Jean Chalard 2013-08-20 18:00:21 +09:00
parent be470f06e4
commit 24aad5a4d5
10 changed files with 73 additions and 19 deletions

View File

@ -40,6 +40,9 @@ public final class BinaryDictionary extends Dictionary {
private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH;
// Must be equal to MAX_RESULTS in native/jni/src/defines.h // Must be equal to MAX_RESULTS in native/jni/src/defines.h
private static final int MAX_RESULTS = 18; private static final int MAX_RESULTS = 18;
// Required space count for auto commit.
// TODO: Remove this heuristic.
private static final int SPACE_COUNT_FOR_AUTO_COMMIT = 3;
private long mNativeDict; private long mNativeDict;
private final Locale mLocale; private final Locale mLocale;
@ -48,6 +51,7 @@ public final class BinaryDictionary extends Dictionary {
private final int[] mSpaceIndices = new int[MAX_RESULTS]; private final int[] mSpaceIndices = new int[MAX_RESULTS];
private final int[] mOutputScores = new int[MAX_RESULTS]; private final int[] mOutputScores = new int[MAX_RESULTS];
private final int[] mOutputTypes = new int[MAX_RESULTS]; private final int[] mOutputTypes = new int[MAX_RESULTS];
private final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; // Only one result
private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions(); private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions();
@ -102,7 +106,8 @@ public final class BinaryDictionary extends Dictionary {
long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times, long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint, int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
int[] suggestOptions, int[] prevWordCodePointArray, int[] suggestOptions, int[] prevWordCodePointArray,
int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes); int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes,
int[] outputAutoCommitFirstWordConfidence);
private static native float calcNormalizedScoreNative(int[] before, int[] after, int score); private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
private static native int editDistanceNative(int[] before, int[] after); private static native int editDistanceNative(int[] before, int[] after);
private static native void addUnigramWordNative(long dict, int[] word, int probability); private static native void addUnigramWordNative(long dict, int[] word, int probability);
@ -155,7 +160,7 @@ public final class BinaryDictionary extends Dictionary {
ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints, ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(), inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(),
prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices, prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices,
mOutputTypes); mOutputTypes, mOutputAutoCommitFirstWordConfidence);
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
for (int j = 0; j < count; ++j) { for (int j = 0; j < count; ++j) {
final int start = j * MAX_WORD_LENGTH; final int start = j * MAX_WORD_LENGTH;
@ -179,7 +184,8 @@ public final class BinaryDictionary extends Dictionary {
// flags too and pass mOutputTypes[j] instead of kind // flags too and pass mOutputTypes[j] instead of kind
suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len), suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len),
score, kind, this /* sourceDict */, score, kind, this /* sourceDict */,
mSpaceIndices[0] /* indexOfTouchPointOfSecondWord */)); mSpaceIndices[0] /* indexOfTouchPointOfSecondWord */,
mOutputAutoCommitFirstWordConfidence[0]));
} }
} }
return suggestions; return suggestions;
@ -253,6 +259,22 @@ public final class BinaryDictionary extends Dictionary {
removeBigramWordsNative(mNativeDict, codePoints0, codePoints1); removeBigramWordsNative(mNativeDict, codePoints0, codePoints1);
} }
@Override
public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
// TODO: actually use the confidence rather than use this completely broken heuristic
final String word = candidate.mWord;
final int length = word.length();
int remainingSpaces = SPACE_COUNT_FOR_AUTO_COMMIT;
for (int i = 0; i < length; ++i) {
// This is okay because no low-surrogate and no high-surrogate can ever match the
// space character, so we don't need to take care of iterating on code points.
if (Constants.CODE_SPACE == word.charAt(i)) {
if (0 >= --remainingSpaces) return true;
}
}
return false;
}
@Override @Override
public void close() { public void close() {
synchronized (mDicTraverseSessions) { synchronized (mDicTraverseSessions) {

View File

@ -137,7 +137,10 @@ public abstract class Dictionary {
} }
/** /**
* Whether we think this suggestion should trigger an auto-commit. * Whether we think this suggestion should trigger an auto-commit. prevWord is the word
* before the suggestion, so that we can use n-gram frequencies.
* @param candidate The candidate suggestion, in whole (not only the first part).
* @return whether we should auto-commit or not.
*/ */
public boolean shouldAutoCommit(final SuggestedWordInfo candidate) { public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
// If we don't have support for auto-commit, or if we don't know, we return false to // If we don't have support for auto-commit, or if we don't know, we return false to

View File

@ -344,7 +344,8 @@ public class ExpandableDictionary extends Dictionary {
// in the future. // in the future.
suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq, suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq,
SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false; if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false;
} }
if (null != node.mShortcutTargets) { if (null != node.mShortcutTargets) {
@ -353,7 +354,8 @@ public class ExpandableDictionary extends Dictionary {
final char[] shortcut = node.mShortcutTargets.get(shortcutIndex); final char[] shortcut = node.mShortcutTargets.get(shortcutIndex);
suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length), suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length),
finalFreq, SuggestedWordInfo.KIND_SHORTCUT, this /* sourceDict */, finalFreq, SuggestedWordInfo.KIND_SHORTCUT, this /* sourceDict */,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false; if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false;
} }
} }
@ -604,7 +606,8 @@ public class ExpandableDictionary extends Dictionary {
suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index, suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index,
Constants.DICTIONARY_MAX_WORD_LENGTH - index), Constants.DICTIONARY_MAX_WORD_LENGTH - index),
freq, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */, freq, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
} }
} }
} }

View File

@ -2697,7 +2697,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
suggestions.add(new SuggestedWordInfo(s, suggestions.add(new SuggestedWordInfo(s,
SuggestionStripView.MAX_SUGGESTIONS - i, SuggestionStripView.MAX_SUGGESTIONS - i,
SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED, SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE
/* autoCommitFirstWordConfidence */));
} }
} }
} }

View File

@ -327,7 +327,8 @@ public final class Suggest {
suggestionsContainer.add(0, new SuggestedWordInfo(typedWord, suggestionsContainer.add(0, new SuggestedWordInfo(typedWord,
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED, SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED,
Dictionary.DICTIONARY_USER_TYPED, Dictionary.DICTIONARY_USER_TYPED,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
} }
SuggestedWordInfo.removeDups(suggestionsContainer); SuggestedWordInfo.removeDups(suggestionsContainer);
@ -474,7 +475,8 @@ public final class Suggest {
sb.appendCodePoint(Constants.CODE_SINGLE_QUOTE); sb.appendCodePoint(Constants.CODE_SINGLE_QUOTE);
} }
return new SuggestedWordInfo(sb.toString(), wordInfo.mScore, wordInfo.mKind, return new SuggestedWordInfo(sb.toString(), wordInfo.mScore, wordInfo.mKind,
wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord); wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
} }
public void close() { public void close() {

View File

@ -114,7 +114,8 @@ public final class SuggestedWords {
final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(), final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED, SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED,
Dictionary.DICTIONARY_APPLICATION_DEFINED, Dictionary.DICTIONARY_APPLICATION_DEFINED,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
result.add(suggestedWordInfo); result.add(suggestedWordInfo);
} }
return result; return result;
@ -128,7 +129,8 @@ public final class SuggestedWords {
final HashSet<String> alreadySeen = CollectionUtils.newHashSet(); final HashSet<String> alreadySeen = CollectionUtils.newHashSet();
suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE, suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED, SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
alreadySeen.add(typedWord.toString()); alreadySeen.add(typedWord.toString());
final int previousSize = previousSuggestions.size(); final int previousSize = previousSuggestions.size();
for (int index = 1; index < previousSize; index++) { for (int index = 1; index < previousSize; index++) {
@ -151,6 +153,7 @@ public final class SuggestedWords {
public static final class SuggestedWordInfo { public static final class SuggestedWordInfo {
public static final int NOT_AN_INDEX = -1; public static final int NOT_AN_INDEX = -1;
public static final int NOT_A_CONFIDENCE = -1;
public static final int MAX_SCORE = Integer.MAX_VALUE; public static final int MAX_SCORE = Integer.MAX_VALUE;
public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind
public static final int KIND_TYPED = 0; // What user typed public static final int KIND_TYPED = 0; // What user typed
@ -180,16 +183,30 @@ public final class SuggestedWords {
// passed to native code to get suggestions for a gesture that corresponds to the first // passed to native code to get suggestions for a gesture that corresponds to the first
// letter of the second word. // letter of the second word.
public final int mIndexOfTouchPointOfSecondWord; public final int mIndexOfTouchPointOfSecondWord;
// For auto-commit. This is a measure of how confident we are that we can commit the
// first word of this suggestion.
public final int mAutoCommitFirstWordConfidence;
private String mDebugString = ""; private String mDebugString = "";
/**
* Create a new suggested word info.
* @param word The string to suggest.
* @param score A measure of how likely this suggestion is.
* @param kind The kind of suggestion, as one of the above KIND_* constants.
* @param sourceDict What instance of Dictionary produced this suggestion.
* @param indexOfTouchPointOfSecondWord See mIndexOfTouchPointOfSecondWord.
* @param autoCommitFirstWordConfidence See mAutoCommitFirstWordConfidence.
*/
public SuggestedWordInfo(final String word, final int score, final int kind, public SuggestedWordInfo(final String word, final int score, final int kind,
final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord) { final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord,
final int autoCommitFirstWordConfidence) {
mWord = word; mWord = word;
mScore = score; mScore = score;
mKind = kind; mKind = kind;
mSourceDict = sourceDict; mSourceDict = sourceDict;
mCodePointCount = StringUtils.codePointCount(mWord); mCodePointCount = StringUtils.codePointCount(mWord);
mIndexOfTouchPointOfSecondWord = indexOfTouchPointOfSecondWord; mIndexOfTouchPointOfSecondWord = indexOfTouchPointOfSecondWord;
mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence;
} }
public boolean isEligibleForAutoCommit() { public boolean isEligibleForAutoCommit() {

View File

@ -295,7 +295,8 @@ public final class SettingsValues {
puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec), puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED, SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
Dictionary.DICTIONARY_HARDCODED, Dictionary.DICTIONARY_HARDCODED,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
} }
} }
return new SuggestedWords(puncList, return new SuggestedWords(puncList,

View File

@ -70,7 +70,8 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j
jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray, jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions, jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions,
jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray, jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray,
jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray) { jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray,
jintArray outputAutoCommitFirstWordConfidence) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict); Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return 0; if (!dictionary) return 0;
ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo); ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo);
@ -253,7 +254,7 @@ static const JNINativeMethod sMethods[] = {
}, },
{ {
const_cast<char *>("getSuggestionsNative"), const_cast<char *>("getSuggestionsNative"),
const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I)I"), const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I)I"),
reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions) reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
}, },
{ {

View File

@ -259,7 +259,8 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
protected void pickSuggestionManually(final int index, final String suggestion) { protected void pickSuggestionManually(final int index, final String suggestion) {
mLatinIME.pickSuggestionManually(index, new SuggestedWordInfo(suggestion, 1, mLatinIME.pickSuggestionManually(index, new SuggestedWordInfo(suggestion, 1,
SuggestedWordInfo.KIND_CORRECTION, null /* sourceDict */, SuggestedWordInfo.KIND_CORRECTION, null /* sourceDict */,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
} }
// Helper to avoid writing the try{}catch block each time // Helper to avoid writing the try{}catch block each time

View File

@ -35,11 +35,13 @@ public class SuggestedWordsTests extends AndroidTestCase {
final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList(); final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList();
list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ, list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
SuggestedWordInfo.KIND_TYPED, null /* sourceDict */, SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) { for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION, list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION,
null /* sourceDict */, null /* sourceDict */,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */)); SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
} }
final SuggestedWords words = new SuggestedWords( final SuggestedWords words = new SuggestedWords(