Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5676a80 authored by Janet Sun's avatar Janet Sun Committed by Michael Bestas
Browse files

LatinIME: Add shortcuts support

Making sure to include unit test changes this time.
Adjust for deleted files and delete references to them.

This reverts commit fe674a44,
"am 12d80ebe: Remove shortcut support from LatinIME."

Ticket-Id: CYNGNOS-3129, CYNGNOS-3267
Change-Id: I136e307f93445b353e0d798284fd0fbaee61c0d9
parent f3d16dbc
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ public final class BinaryDictionary extends Dictionary {
    private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0;
    private static final int FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX = 1;
    private static final int FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX = 2;
    private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; // DEPRECATED
    private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3;
    private static final int FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX = 4;

    // Format to get probability and historical info from native side via getWordPropertyNative().
@@ -412,9 +412,11 @@ public final class BinaryDictionary extends Dictionary {
                outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
                outFlags[FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX],
                outFlags[FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX],
                outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX],
                outFlags[FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX], outProbabilityInfo,
                outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
                outNgramTargets, outNgramProbabilityInfo);
                outNgramTargets, outNgramProbabilityInfo, outShortcutTargets,
                outShortcutProbabilities);
    }

    public static class GetNextWordPropertyResult {
@@ -442,16 +444,19 @@ public final class BinaryDictionary extends Dictionary {
    }

    // Add a unigram entry to binary dictionary with unigram attributes in native code.
    public boolean addUnigramEntry(
            final String word, final int probability, final boolean isBeginningOfSentence,
            final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
    public boolean addUnigramEntry(final String word, final int probability,
            final String shortcutTarget, final int shortcutProbability,
            final boolean isBeginningOfSentence, final boolean isNotAWord,
            final boolean isPossiblyOffensive, final int timestamp) {
        if (word == null || (word.isEmpty() && !isBeginningOfSentence)) {
            return false;
        }
        final int[] codePoints = StringUtils.toCodePointArray(word);
        if (!addUnigramEntryNative(mNativeDict, codePoints, probability,
                null /* shortcutTargetCodePoints */, 0 /* shortcutProbability */,
                isBeginningOfSentence, isNotAWord, isPossiblyOffensive, timestamp)) {
        final int[] shortcutTargetCodePoints = (shortcutTarget != null) ?
                StringUtils.toCodePointArray(shortcutTarget) : null;
        if (!addUnigramEntryNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints,
                shortcutProbability, isBeginningOfSentence, isNotAWord, isPossiblyOffensive,
                timestamp)) {
            return false;
        }
        mHasUpdated = true;
+4 −2
Original line number Diff line number Diff line
@@ -101,6 +101,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
            }
            runGCIfRequiredLocked(true /* mindsBlockByGC */);
            addUnigramLocked(word, ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS,
                    null /* shortcut */,
                    0 /* shortcutFreq */,
                    false /* isNotAWord */, false /* isPossiblyOffensive */,
                    BinaryDictionary.NOT_A_VALID_TIMESTAMP);
        }
@@ -151,8 +153,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
                        Log.d(TAG, "addName " + name + ", " + word + ", "  + ngramContext);
                    }
                    runGCIfRequiredLocked(true /* mindsBlockByGC */);
                    addUnigramLocked(word,
                            ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS, false /* isNotAWord */,
                    addUnigramLocked(word, ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS,
                            null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */,
                            false /* isPossiblyOffensive */,
                            BinaryDictionary.NOT_A_VALID_TIMESTAMP);
                    if (ngramContext.isValid() && mUseFirstLastBigrams) {
+7 −4
Original line number Diff line number Diff line
@@ -295,18 +295,21 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
     * Adds unigram information of a word to the dictionary. May overwrite an existing entry.
     */
    public void addUnigramEntry(final String word, final int frequency,
            final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
            final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
            final boolean isPossiblyOffensive, final int timestamp) {
        updateDictionaryWithWriteLock(new Runnable() {
            @Override
            public void run() {
                addUnigramLocked(word, frequency, isNotAWord, isPossiblyOffensive, timestamp);
                addUnigramLocked(word, frequency, shortcutTarget, shortcutFreq,
                        isNotAWord, isPossiblyOffensive, timestamp);
            }
        });
    }

    protected void addUnigramLocked(final String word, final int frequency,
            final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
        if (!mBinaryDictionary.addUnigramEntry(word, frequency,
            final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
            final boolean isPossiblyOffensive, final int timestamp) {
        if (!mBinaryDictionary.addUnigramEntry(word, frequency, shortcutTarget, shortcutFreq,
                false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive, timestamp)) {
            Log.e(TAG, "Cannot add unigram entry. word: " + word);
        }
+40 −4
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Build;
import android.provider.UserDictionary.Words;
import android.text.TextUtils;
import android.util.Log;
@@ -46,8 +47,19 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
    private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
    private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
    private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;

    private static final String[] PROJECTION_QUERY = new String[] {Words.WORD, Words.FREQUENCY};
    // Shortcut frequency is 0~15, with 15 = whitelist. We don't want user dictionary entries
    // to auto-correct, so we set this to the highest frequency that won't, i.e. 14.
    private static final int USER_DICT_SHORTCUT_FREQUENCY = 14;

    private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] {
            Words.WORD,
            Words.SHORTCUT,
            Words.FREQUENCY,
    };
    private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] {
            Words.WORD,
            Words.FREQUENCY,
    };

    private static final String NAME = "userunigram";

@@ -159,7 +171,20 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
            requestArguments = localeElements;
        }
        final String requestString = request.toString();
        addWordsFromProjectionLocked(PROJECTION_QUERY, requestString, requestArguments);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            try {
                addWordsFromProjectionLocked(PROJECTION_QUERY_WITH_SHORTCUT, requestString,
                        requestArguments);
            } catch (IllegalArgumentException e) {
                // This may happen on some non-compliant devices where the declared API is JB+ but
                // the SHORTCUT column is not present for some reason.
                addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
                        requestArguments);
            }
        } else {
            addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
                    requestArguments);
        }
    }

    private void addWordsFromProjectionLocked(final String[] query, String request,
@@ -194,20 +219,31 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
    }

    private void addWordsLocked(final Cursor cursor) {
        final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
        if (cursor == null) return;
        if (cursor.moveToFirst()) {
            final int indexWord = cursor.getColumnIndex(Words.WORD);
            final int indexShortcut = hasShortcutColumn ? cursor.getColumnIndex(Words.SHORTCUT) : 0;
            final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
            while (!cursor.isAfterLast()) {
                final String word = cursor.getString(indexWord);
                final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null;
                final int frequency = cursor.getInt(indexFrequency);
                final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
                // Safeguard against adding really long words.
                if (word.length() <= MAX_WORD_LENGTH) {
                    runGCIfRequiredLocked(true /* mindsBlockByGC */);
                    addUnigramLocked(word, adjustedFrequency, false /* isNotAWord */,
                    addUnigramLocked(word, adjustedFrequency, null /* shortcutTarget */,
                            0 /* shortcutFreq */, false /* isNotAWord */,
                            false /* isPossiblyOffensive */,
                            BinaryDictionary.NOT_A_VALID_TIMESTAMP);
                    if (null != shortcut && shortcut.length() <= MAX_WORD_LENGTH) {
                        runGCIfRequiredLocked(true /* mindsBlockByGC */);
                        addUnigramLocked(shortcut, adjustedFrequency, word,
                                USER_DICT_SHORTCUT_FREQUENCY, true /* isNotAWord */,
                                false /* isPossiblyOffensive */,
                                BinaryDictionary.NOT_A_VALID_TIMESTAMP);
                    }
                }
                cursor.moveToNext();
            }
+23 −5
Original line number Diff line number Diff line
@@ -37,11 +37,13 @@ import javax.annotation.Nullable;
public final class WordProperty implements Comparable<WordProperty> {
    public final String mWord;
    public final ProbabilityInfo mProbabilityInfo;
    public final ArrayList<WeightedString> mShortcutTargets;
    public final ArrayList<NgramProperty> mNgrams;
    // TODO: Support mIsBeginningOfSentence.
    public final boolean mIsBeginningOfSentence;
    public final boolean mIsNotAWord;
    public final boolean mIsPossiblyOffensive;
    public final boolean mHasShortcuts;
    public final boolean mHasNgrams;

    private int mHashCode = 0;
@@ -49,10 +51,12 @@ public final class WordProperty implements Comparable<WordProperty> {
    // TODO: Support n-gram.
    @UsedForTesting
    public WordProperty(final String word, final ProbabilityInfo probabilityInfo,
            final ArrayList<WeightedString> shortcutTargets,
            @Nullable final ArrayList<WeightedString> bigrams,
            final boolean isNotAWord, final boolean isPossiblyOffensive) {
        mWord = word;
        mProbabilityInfo = probabilityInfo;
        mShortcutTargets = shortcutTargets;
        if (null == bigrams) {
            mNgrams = null;
        } else {
@@ -66,6 +70,7 @@ public final class WordProperty implements Comparable<WordProperty> {
        mIsNotAWord = isNotAWord;
        mIsPossiblyOffensive = isPossiblyOffensive;
        mHasNgrams = bigrams != null && !bigrams.isEmpty();
        mHasShortcuts = shortcutTargets != null && !shortcutTargets.isEmpty();
    }

    private static ProbabilityInfo createProbabilityInfoFromArray(final int[] probabilityInfo) {
@@ -79,17 +84,21 @@ public final class WordProperty implements Comparable<WordProperty> {
    // Construct word property using information from native code.
    // This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY.
    public WordProperty(final int[] codePoints, final boolean isNotAWord,
            final boolean isPossiblyOffensive, final boolean hasBigram,
            final boolean isPossiblyOffensive, final boolean hasBigram, final boolean hasShortcuts,
            final boolean isBeginningOfSentence, final int[] probabilityInfo,
            final ArrayList<int[][]> ngramPrevWordsArray,
            final ArrayList<boolean[]> ngramPrevWordIsBeginningOfSentenceArray,
            final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo) {
            final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo,
            final ArrayList<int[]> shortcutTargets,
            final ArrayList<Integer> shortcutProbabilities) {
        mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
        mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo);
        mShortcutTargets = new ArrayList<>();
        final ArrayList<NgramProperty> ngrams = new ArrayList<>();
        mIsBeginningOfSentence = isBeginningOfSentence;
        mIsNotAWord = isNotAWord;
        mIsPossiblyOffensive = isPossiblyOffensive;
        mHasShortcuts = hasShortcuts;
        mHasNgrams = hasBigram;

        final int relatedNgramCount = ngramTargets.size();
@@ -112,6 +121,14 @@ public final class WordProperty implements Comparable<WordProperty> {
            ngrams.add(new NgramProperty(ngramTarget, ngramContext));
        }
        mNgrams = ngrams.isEmpty() ? null : ngrams;

        final int shortcutTargetCount = shortcutTargets.size();
        for (int i = 0; i < shortcutTargetCount; i++) {
            final String shortcutTargetString =
                    StringUtils.getStringFromNullTerminatedCodePointArray(shortcutTargets.get(i));
            mShortcutTargets.add(
                    new WeightedString(shortcutTargetString, shortcutProbabilities.get(i)));
        }
    }

    // TODO: Remove
@@ -137,6 +154,7 @@ public final class WordProperty implements Comparable<WordProperty> {
        return Arrays.hashCode(new Object[] {
                word.mWord,
                word.mProbabilityInfo,
                word.mShortcutTargets,
                word.mNgrams,
                word.mIsNotAWord,
                word.mIsPossiblyOffensive
@@ -167,10 +185,10 @@ public final class WordProperty implements Comparable<WordProperty> {
        if (o == this) return true;
        if (!(o instanceof WordProperty)) return false;
        WordProperty w = (WordProperty)o;
        return mProbabilityInfo.equals(w.mProbabilityInfo)
                && mWord.equals(w.mWord) && equals(mNgrams, w.mNgrams)
        return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord)
                && mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams)
                && mIsNotAWord == w.mIsNotAWord && mIsPossiblyOffensive == w.mIsPossiblyOffensive
                && mHasNgrams == w.mHasNgrams;
                && mHasNgrams == w.mHasNgrams && mHasShortcuts && w.mHasNgrams;
    }

    // TDOO: Have a utility method like java.util.Objects.equals.
Loading