Remove shortcut support from LatinIME.
Note this change does not affect the native decoder interface. Change-Id: I73b7dc008a5acaf75a31a36a2d332b5afabd82d0main
parent
2979fad213
commit
12d80ebead
|
@ -16,11 +16,20 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin.common;
|
package com.android.inputmethod.latin.common;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
public final class Constants {
|
public final class Constants {
|
||||||
|
|
||||||
|
public static final boolean JELLY_BEAN_OR_HIGHER =
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
|
||||||
|
|
||||||
|
public static final boolean JELLY_BEAN_MR1_OR_HIGHER =
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
|
||||||
|
|
||||||
public static final class Color {
|
public static final class Color {
|
||||||
/**
|
/**
|
||||||
* The alpha value for fully opaque.
|
* The alpha value for fully opaque.
|
||||||
|
|
|
@ -43,26 +43,6 @@
|
||||||
android:layout_marginStart="8dip"
|
android:layout_marginStart="8dip"
|
||||||
android:columnCount="2" >
|
android:columnCount="2" >
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/user_dictionary_add_shortcut_label"
|
|
||||||
style="?android:attr/textAppearanceSmall"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start|center_vertical"
|
|
||||||
android:text="@string/user_dict_settings_add_shortcut_option_name" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/user_dictionary_add_shortcut"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_gravity="fill_horizontal|center_vertical"
|
|
||||||
android:layout_marginBottom="8dip"
|
|
||||||
android:layout_marginStart="8dip"
|
|
||||||
android:layout_marginTop="8dip"
|
|
||||||
android:hint="@string/user_dict_settings_add_shortcut_hint"
|
|
||||||
android:imeOptions="flagNoFullscreen"
|
|
||||||
android:inputType="textNoSuggestions"
|
|
||||||
android:maxLength="@integer/config_user_dictionary_max_word_length" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/user_dictionary_add_locale_label"
|
android:id="@+id/user_dictionary_add_locale_label"
|
||||||
style="?android:attr/textAppearanceSmall"
|
style="?android:attr/textAppearanceSmall"
|
||||||
|
|
|
@ -35,6 +35,7 @@ import android.view.inputmethod.EditorInfo;
|
||||||
import com.android.inputmethod.compat.SettingsSecureCompatUtils;
|
import com.android.inputmethod.compat.SettingsSecureCompatUtils;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.SuggestedWords;
|
import com.android.inputmethod.latin.SuggestedWords;
|
||||||
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
import com.android.inputmethod.latin.utils.InputTypeUtils;
|
import com.android.inputmethod.latin.utils.InputTypeUtils;
|
||||||
|
|
||||||
public final class AccessibilityUtils {
|
public final class AccessibilityUtils {
|
||||||
|
@ -221,7 +222,7 @@ public final class AccessibilityUtils {
|
||||||
|
|
||||||
// Platforms starting at SDK version 16 (Build.VERSION_CODES.JELLY_BEAN) should use
|
// Platforms starting at SDK version 16 (Build.VERSION_CODES.JELLY_BEAN) should use
|
||||||
// announce events.
|
// announce events.
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Constants.JELLY_BEAN_OR_HIGHER) {
|
||||||
event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
|
event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
|
||||||
} else {
|
} else {
|
||||||
event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
||||||
|
|
|
@ -38,7 +38,7 @@ public final class InputMethodSubtypeCompatUtils {
|
||||||
int.class, int.class, String.class, String.class, String.class, boolean.class,
|
int.class, int.class, String.class, String.class, String.class, boolean.class,
|
||||||
boolean.class, int.class);
|
boolean.class, int.class);
|
||||||
static {
|
static {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
if (Constants.JELLY_BEAN_MR1_OR_HIGHER) {
|
||||||
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
|
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null) {
|
||||||
android.util.Log.w(TAG, "Warning!!! Constructor is not defined.");
|
android.util.Log.w(TAG, "Warning!!! Constructor is not defined.");
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,7 @@ public final class InputMethodSubtypeCompatUtils {
|
||||||
public static InputMethodSubtype newInputMethodSubtype(int nameId, int iconId, String locale,
|
public static InputMethodSubtype newInputMethodSubtype(int nameId, int iconId, String locale,
|
||||||
String mode, String extraValue, boolean isAuxiliary,
|
String mode, String extraValue, boolean isAuxiliary,
|
||||||
boolean overridesImplicitlyEnabledSubtype, int id) {
|
boolean overridesImplicitlyEnabledSubtype, int id) {
|
||||||
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null
|
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null || !Constants.JELLY_BEAN_MR1_OR_HIGHER) {
|
||||||
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
|
||||||
return new InputMethodSubtype(nameId, iconId, locale, mode, extraValue, isAuxiliary,
|
return new InputMethodSubtype(nameId, iconId, locale, mode, extraValue, isAuxiliary,
|
||||||
overridesImplicitlyEnabledSubtype);
|
overridesImplicitlyEnabledSubtype);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,8 @@
|
||||||
package com.android.inputmethod.compat;
|
package com.android.inputmethod.compat;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.os.Build;
|
|
||||||
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
@ -73,7 +74,7 @@ public class NotificationCompatUtils {
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static Notification build(final Notification.Builder builder) {
|
public static Notification build(final Notification.Builder builder) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
if (Constants.JELLY_BEAN_OR_HIGHER) {
|
||||||
// #build was added in API level 16, JELLY_BEAN
|
// #build was added in API level 16, JELLY_BEAN
|
||||||
return (Notification) CompatUtils.invoke(builder, null, METHOD_build);
|
return (Notification) CompatUtils.invoke(builder, null, METHOD_build);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.compat;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.provider.UserDictionary;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public final class UserDictionaryCompatUtils {
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static void addWord(final Context context, final String word,
|
|
||||||
final int freq, final String shortcut, final Locale locale) {
|
|
||||||
if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
|
||||||
addWordWithShortcut(context, word, freq, shortcut, locale);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Fall back to the pre-JellyBean method.
|
|
||||||
final Locale currentLocale = context.getResources().getConfiguration().locale;
|
|
||||||
final int localeType = currentLocale.equals(locale)
|
|
||||||
? UserDictionary.Words.LOCALE_TYPE_CURRENT : UserDictionary.Words.LOCALE_TYPE_ALL;
|
|
||||||
UserDictionary.Words.addWord(context, word, freq, localeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// {@link UserDictionary.Words#addWord(Context,String,int,String,Locale)} was introduced
|
|
||||||
// in API level 16 (Build.VERSION_CODES.JELLY_BEAN).
|
|
||||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
|
||||||
private static void addWordWithShortcut(final Context context, final String word,
|
|
||||||
final int freq, final String shortcut, final Locale locale) {
|
|
||||||
UserDictionary.Words.addWord(context, word, freq, shortcut, locale);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -40,13 +40,11 @@ import com.android.inputmethod.latin.settings.Settings;
|
||||||
import com.android.inputmethod.latin.settings.SettingsValues;
|
import com.android.inputmethod.latin.settings.SettingsValues;
|
||||||
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
import com.android.inputmethod.latin.utils.CapsModeUtils;
|
||||||
import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
|
import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
|
||||||
import com.android.inputmethod.latin.utils.NetworkConnectivityUtils;
|
|
||||||
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
|
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
|
||||||
import com.android.inputmethod.latin.utils.ResourceUtils;
|
import com.android.inputmethod.latin.utils.ResourceUtils;
|
||||||
import com.android.inputmethod.latin.utils.ScriptUtils;
|
import com.android.inputmethod.latin.utils.ScriptUtils;
|
||||||
|
|
||||||
public final class KeyboardSwitcher implements KeyboardState.SwitchActions,
|
public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
||||||
NetworkConnectivityUtils.NetworkStateChangeListener {
|
|
||||||
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
|
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
|
||||||
|
|
||||||
private InputView mCurrentInputView;
|
private InputView mCurrentInputView;
|
||||||
|
@ -412,15 +410,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions,
|
||||||
return mCurrentInputView;
|
return mCurrentInputView;
|
||||||
}
|
}
|
||||||
|
|
||||||
// {@link NetworkConnectivityUtils.NetworkStateChangeListener#onNetworkStateChanged(boolean)}.
|
|
||||||
@Override
|
|
||||||
public void onNetworkStateChanged() {
|
|
||||||
if (mKeyboardView == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mKeyboardView.updateShortcutKey(mRichImm.isShortcutImeReady());
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getKeyboardShiftMode() {
|
public int getKeyboardShiftMode() {
|
||||||
final Keyboard keyboard = getKeyboard();
|
final Keyboard keyboard = getKeyboard();
|
||||||
if (keyboard == null) {
|
if (keyboard == null) {
|
||||||
|
|
|
@ -694,25 +694,25 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(final MotionEvent me) {
|
public boolean onTouchEvent(final MotionEvent event) {
|
||||||
if (getKeyboard() == null) {
|
if (getKeyboard() == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (mNonDistinctMultitouchHelper != null) {
|
if (mNonDistinctMultitouchHelper != null) {
|
||||||
if (me.getPointerCount() > 1 && mTimerHandler.isInKeyRepeat()) {
|
if (event.getPointerCount() > 1 && mTimerHandler.isInKeyRepeat()) {
|
||||||
// Key repeating timer will be canceled if 2 or more keys are in action.
|
// Key repeating timer will be canceled if 2 or more keys are in action.
|
||||||
mTimerHandler.cancelKeyRepeatTimers();
|
mTimerHandler.cancelKeyRepeatTimers();
|
||||||
}
|
}
|
||||||
// Non distinct multitouch screen support
|
// Non distinct multitouch screen support
|
||||||
mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector);
|
mNonDistinctMultitouchHelper.processMotionEvent(event, mKeyDetector);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return processMotionEvent(me);
|
return processMotionEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean processMotionEvent(final MotionEvent me) {
|
public boolean processMotionEvent(final MotionEvent event) {
|
||||||
final int index = me.getActionIndex();
|
final int index = event.getActionIndex();
|
||||||
final int id = me.getPointerId(index);
|
final int id = event.getPointerId(index);
|
||||||
final PointerTracker tracker = PointerTracker.getPointerTracker(id);
|
final PointerTracker tracker = PointerTracker.getPointerTracker(id);
|
||||||
// When a more keys panel is showing, we should ignore other fingers' single touch events
|
// When a more keys panel is showing, we should ignore other fingers' single touch events
|
||||||
// other than the finger that is showing the more keys panel.
|
// other than the finger that is showing the more keys panel.
|
||||||
|
@ -720,7 +720,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
|
||||||
&& PointerTracker.getActivePointerTrackerCount() == 1) {
|
&& PointerTracker.getActivePointerTrackerCount() == 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
tracker.processMotionEvent(me, mKeyDetector);
|
tracker.processMotionEvent(event, mKeyDetector);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,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_NOT_A_WORD_INDEX = 0;
|
||||||
private static final int FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX = 1;
|
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_NGRAMS_INDEX = 2;
|
||||||
private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3;
|
private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; // DEPRECATED
|
||||||
private static final int FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX = 4;
|
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().
|
// Format to get probability and historical info from native side via getWordPropertyNative().
|
||||||
|
@ -410,11 +410,9 @@ public final class BinaryDictionary extends Dictionary {
|
||||||
outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
|
outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
|
||||||
outFlags[FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX],
|
outFlags[FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX],
|
||||||
outFlags[FORMAT_WORD_PROPERTY_HAS_NGRAMS_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,
|
outFlags[FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX], outProbabilityInfo,
|
||||||
outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
|
outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
|
||||||
outNgramTargets, outNgramProbabilityInfo, outShortcutTargets,
|
outNgramTargets, outNgramProbabilityInfo);
|
||||||
outShortcutProbabilities);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class GetNextWordPropertyResult {
|
public static class GetNextWordPropertyResult {
|
||||||
|
@ -442,19 +440,16 @@ public final class BinaryDictionary extends Dictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a unigram entry to binary dictionary with unigram attributes in native code.
|
// Add a unigram entry to binary dictionary with unigram attributes in native code.
|
||||||
public boolean addUnigramEntry(final String word, final int probability,
|
public boolean addUnigramEntry(
|
||||||
final String shortcutTarget, final int shortcutProbability,
|
final String word, final int probability, final boolean isBeginningOfSentence,
|
||||||
final boolean isBeginningOfSentence, final boolean isNotAWord,
|
final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
|
||||||
final boolean isPossiblyOffensive, final int timestamp) {
|
|
||||||
if (word == null || (word.isEmpty() && !isBeginningOfSentence)) {
|
if (word == null || (word.isEmpty() && !isBeginningOfSentence)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final int[] codePoints = StringUtils.toCodePointArray(word);
|
final int[] codePoints = StringUtils.toCodePointArray(word);
|
||||||
final int[] shortcutTargetCodePoints = (shortcutTarget != null) ?
|
if (!addUnigramEntryNative(mNativeDict, codePoints, probability,
|
||||||
StringUtils.toCodePointArray(shortcutTarget) : null;
|
null /* shortcutTargetCodePoints */, 0 /* shortcutProbability */,
|
||||||
if (!addUnigramEntryNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints,
|
isBeginningOfSentence, isNotAWord, isPossiblyOffensive, timestamp)) {
|
||||||
shortcutProbability, isBeginningOfSentence, isNotAWord, isPossiblyOffensive,
|
|
||||||
timestamp)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mHasUpdated = true;
|
mHasUpdated = true;
|
||||||
|
|
|
@ -139,8 +139,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
|
||||||
Log.d(TAG, "loadAccountVocabulary: " + word);
|
Log.d(TAG, "loadAccountVocabulary: " + word);
|
||||||
}
|
}
|
||||||
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
||||||
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS, null /* shortcut */,
|
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS,
|
||||||
0 /* shortcutFreq */, false /* isNotAWord */, false /* isPossiblyOffensive */,
|
false /* isNotAWord */, false /* isPossiblyOffensive */,
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,8 +239,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
|
||||||
Log.d(TAG, "addName " + name + ", " + word + ", " + ngramContext);
|
Log.d(TAG, "addName " + name + ", " + word + ", " + ngramContext);
|
||||||
}
|
}
|
||||||
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
||||||
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS,
|
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS, false /* isNotAWord */,
|
||||||
null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */,
|
|
||||||
false /* isPossiblyOffensive */,
|
false /* isPossiblyOffensive */,
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
||||||
if (!ngramContext.isValid() && mUseFirstLastBigrams) {
|
if (!ngramContext.isValid() && mUseFirstLastBigrams) {
|
||||||
|
|
|
@ -297,21 +297,18 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||||
* Adds unigram information of a word to the dictionary. May overwrite an existing entry.
|
* Adds unigram information of a word to the dictionary. May overwrite an existing entry.
|
||||||
*/
|
*/
|
||||||
public void addUnigramEntry(final String word, final int frequency,
|
public void addUnigramEntry(final String word, final int frequency,
|
||||||
final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
|
final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
|
||||||
final boolean isPossiblyOffensive, final int timestamp) {
|
|
||||||
updateDictionaryWithWriteLock(new Runnable() {
|
updateDictionaryWithWriteLock(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
addUnigramLocked(word, frequency, shortcutTarget, shortcutFreq,
|
addUnigramLocked(word, frequency, isNotAWord, isPossiblyOffensive, timestamp);
|
||||||
isNotAWord, isPossiblyOffensive, timestamp);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addUnigramLocked(final String word, final int frequency,
|
protected void addUnigramLocked(final String word, final int frequency,
|
||||||
final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
|
final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
|
||||||
final boolean isPossiblyOffensive, final int timestamp) {
|
if (!mBinaryDictionary.addUnigramEntry(word, frequency,
|
||||||
if (!mBinaryDictionary.addUnigramEntry(word, frequency, shortcutTarget, shortcutFreq,
|
|
||||||
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive, timestamp)) {
|
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive, timestamp)) {
|
||||||
Log.e(TAG, "Cannot add unigram entry. word: " + word);
|
Log.e(TAG, "Cannot add unigram entry. word: " + word);
|
||||||
}
|
}
|
||||||
|
@ -367,31 +364,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dynamically remove the n-gram entry in the dictionary.
|
|
||||||
*/
|
|
||||||
@UsedForTesting
|
|
||||||
public void removeNgramDynamically(@Nonnull final NgramContext ngramContext,
|
|
||||||
final String word) {
|
|
||||||
reloadDictionaryIfRequired();
|
|
||||||
asyncExecuteTaskWithWriteLock(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
final BinaryDictionary binaryDictionary = getBinaryDictionary();
|
|
||||||
if (binaryDictionary == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
|
||||||
if (!binaryDictionary.removeNgramEntry(ngramContext, word)) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.i(TAG, "Cannot remove n-gram entry.");
|
|
||||||
Log.i(TAG, " NgramContext: " + ngramContext + ", word: " + word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update dictionary for the word with the ngramContext.
|
* Update dictionary for the word with the ngramContext.
|
||||||
*/
|
*/
|
||||||
|
@ -408,20 +380,29 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||||
isValidWord, count, timestamp)) {
|
isValidWord, count, timestamp)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.e(TAG, "Cannot update counter. word: " + word
|
Log.e(TAG, "Cannot update counter. word: " + word
|
||||||
+ " context: "+ ngramContext.toString());
|
+ " context: " + ngramContext.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by Sketch.
|
||||||
|
* {@see https://cs.corp.google.com/#android/vendor/unbundled_google/packages/LatinIMEGoogle/tools/sketch/ime-simulator/src/com/android/inputmethod/sketch/imesimulator/ImeSimulator.java&q=updateEntriesForInputEventsCallback&l=286}
|
||||||
|
*/
|
||||||
|
@UsedForTesting
|
||||||
public interface UpdateEntriesForInputEventsCallback {
|
public interface UpdateEntriesForInputEventsCallback {
|
||||||
public void onFinished();
|
public void onFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dynamically update entries according to input events.
|
* Dynamically update entries according to input events.
|
||||||
|
*
|
||||||
|
* Used by Sketch.
|
||||||
|
* {@see https://cs.corp.google.com/#android/vendor/unbundled_google/packages/LatinIMEGoogle/tools/sketch/ime-simulator/src/com/android/inputmethod/sketch/imesimulator/ImeSimulator.java&q=updateEntriesForInputEventsCallback&l=286}
|
||||||
*/
|
*/
|
||||||
|
@UsedForTesting
|
||||||
public void updateEntriesForInputEvents(
|
public void updateEntriesForInputEvents(
|
||||||
@Nonnull final ArrayList<WordInputEventForPersonalization> inputEvents,
|
@Nonnull final ArrayList<WordInputEventForPersonalization> inputEvents,
|
||||||
final UpdateEntriesForInputEventsCallback callback) {
|
final UpdateEntriesForInputEventsCallback callback) {
|
||||||
|
@ -533,11 +514,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected boolean isValidNgramLocked(final NgramContext ngramContext, final String word) {
|
|
||||||
if (mBinaryDictionary == null) return false;
|
|
||||||
return mBinaryDictionary.isValidNgram(ngramContext, word);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the current binary dictionary from internal storage. Assumes the dictionary file
|
* Loads the current binary dictionary from internal storage. Assumes the dictionary file
|
||||||
* exists.
|
* exists.
|
||||||
|
@ -551,6 +527,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
|
||||||
Thread.sleep(15000);
|
Thread.sleep(15000);
|
||||||
Log.w(TAG, "End stress in loading");
|
Log.w(TAG, "End stress in loading");
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
Log.w("Interrupted while loading: " + mDictName, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
|
final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
|
||||||
|
|
|
@ -87,7 +87,6 @@ import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
|
||||||
import com.android.inputmethod.latin.utils.IntentUtils;
|
import com.android.inputmethod.latin.utils.IntentUtils;
|
||||||
import com.android.inputmethod.latin.utils.JniUtils;
|
import com.android.inputmethod.latin.utils.JniUtils;
|
||||||
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
|
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
|
||||||
import com.android.inputmethod.latin.utils.NetworkConnectivityUtils;
|
|
||||||
import com.android.inputmethod.latin.utils.StatsUtils;
|
import com.android.inputmethod.latin.utils.StatsUtils;
|
||||||
import com.android.inputmethod.latin.utils.StatsUtilsManager;
|
import com.android.inputmethod.latin.utils.StatsUtilsManager;
|
||||||
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
||||||
|
@ -565,8 +564,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
loadSettings();
|
loadSettings();
|
||||||
resetDictionaryFacilitatorIfNecessary();
|
resetDictionaryFacilitatorIfNecessary();
|
||||||
|
|
||||||
NetworkConnectivityUtils.onCreate(this /* context */, mKeyboardSwitcher /* listener */);
|
|
||||||
|
|
||||||
// Register to receive ringer mode change.
|
// Register to receive ringer mode change.
|
||||||
final IntentFilter filter = new IntentFilter();
|
final IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
|
||||||
|
@ -703,7 +700,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
mDictionaryFacilitator.closeDictionaries();
|
mDictionaryFacilitator.closeDictionaries();
|
||||||
mSettings.onDestroy();
|
mSettings.onDestroy();
|
||||||
NetworkConnectivityUtils.onDestroy(this /* context */);
|
|
||||||
unregisterReceiver(mRingerModeChangeReceiver);
|
unregisterReceiver(mRingerModeChangeReceiver);
|
||||||
unregisterReceiver(mDictionaryPackInstallReceiver);
|
unregisterReceiver(mDictionaryPackInstallReceiver);
|
||||||
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
|
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
|
||||||
|
@ -717,7 +713,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
unregisterReceiver(mDictionaryPackInstallReceiver);
|
unregisterReceiver(mDictionaryPackInstallReceiver);
|
||||||
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
|
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
|
||||||
unregisterReceiver(mRingerModeChangeReceiver);
|
unregisterReceiver(mRingerModeChangeReceiver);
|
||||||
NetworkConnectivityUtils.onDestroy(this /* context */);
|
|
||||||
mInputLogic.recycle();
|
mInputLogic.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -899,7 +899,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
||||||
* On platforms on which this method is not present, this is a no-op.
|
* On platforms on which this method is not present, this is a no-op.
|
||||||
*/
|
*/
|
||||||
public void maybeMoveTheCursorAroundAndRestoreToWorkaroundABug() {
|
public void maybeMoveTheCursorAroundAndRestoreToWorkaroundABug() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
if (!Constants.JELLY_BEAN_OR_HIGHER) {
|
||||||
if (mExpectedSelStart > 0) {
|
if (mExpectedSelStart > 0) {
|
||||||
mIC.setSelection(mExpectedSelStart - 1, mExpectedSelStart - 1);
|
mIC.setSelection(mExpectedSelStart - 1, mExpectedSelStart - 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
import static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
|
import static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
|
||||||
import static com.android.inputmethod.latin.common.Constants.Subtype.ExtraValue.REQ_NETWORK_CONNECTIVITY;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
@ -36,7 +35,6 @@ import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
|
||||||
import com.android.inputmethod.latin.settings.Settings;
|
import com.android.inputmethod.latin.settings.Settings;
|
||||||
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
|
||||||
import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
|
import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
|
||||||
import com.android.inputmethod.latin.utils.NetworkConnectivityUtils;
|
|
||||||
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -288,24 +286,20 @@ public class RichInputMethodManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
|
public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
|
||||||
return checkIfSubtypeBelongsToImeAndEnabled(getInputMethodInfoOfThisIme(), subtype);
|
return checkIfSubtypeBelongsToList(subtype,
|
||||||
|
getEnabledInputMethodSubtypeList(
|
||||||
|
getInputMethodInfoOfThisIme(),
|
||||||
|
true /* allowsImplicitlySelectedSubtypes */));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
|
public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
|
||||||
final InputMethodSubtype subtype) {
|
final InputMethodSubtype subtype) {
|
||||||
final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
|
final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
|
||||||
final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(
|
final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(subtype,
|
||||||
subtype, getMyEnabledInputMethodSubtypeList(
|
getMyEnabledInputMethodSubtypeList(false /* allowsImplicitlySelectedSubtypes */));
|
||||||
false /* allowsImplicitlySelectedSubtypes */));
|
|
||||||
return subtypeEnabled && !subtypeExplicitlyEnabled;
|
return subtypeEnabled && !subtypeExplicitlyEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkIfSubtypeBelongsToImeAndEnabled(final InputMethodInfo imi,
|
|
||||||
final InputMethodSubtype subtype) {
|
|
||||||
return checkIfSubtypeBelongsToList(subtype, getEnabledInputMethodSubtypeList(imi,
|
|
||||||
true /* allowsImplicitlySelectedSubtypes */));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
|
private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
|
||||||
final List<InputMethodSubtype> subtypes) {
|
final List<InputMethodSubtype> subtypes) {
|
||||||
return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
|
return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
|
||||||
|
@ -564,16 +558,6 @@ public class RichInputMethodManager {
|
||||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShortcutImeEnabled() {
|
|
||||||
if (mShortcutInputMethodInfo == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (mShortcutSubtype == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return checkIfSubtypeBelongsToImeAndEnabled(mShortcutInputMethodInfo, mShortcutSubtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShortcutImeReady() {
|
public boolean isShortcutImeReady() {
|
||||||
if (mShortcutInputMethodInfo == null) {
|
if (mShortcutInputMethodInfo == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -581,9 +565,6 @@ public class RichInputMethodManager {
|
||||||
if (mShortcutSubtype == null) {
|
if (mShortcutSubtype == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) {
|
|
||||||
return NetworkConnectivityUtils.isNetworkConnected();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import android.database.ContentObserver;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
|
||||||
import android.provider.UserDictionary.Words;
|
import android.provider.UserDictionary.Words;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -47,19 +46,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
|
||||||
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
|
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
|
||||||
private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
|
private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
|
||||||
private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
|
private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
|
||||||
// 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[] {
|
private static final String[] PROJECTION_QUERY = new String[] {Words.WORD, Words.FREQUENCY};
|
||||||
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";
|
private static final String NAME = "userunigram";
|
||||||
|
|
||||||
|
@ -171,20 +159,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
|
||||||
requestArguments = localeElements;
|
requestArguments = localeElements;
|
||||||
}
|
}
|
||||||
final String requestString = request.toString();
|
final String requestString = request.toString();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
addWordsFromProjectionLocked(PROJECTION_QUERY, requestString, requestArguments);
|
||||||
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,
|
private void addWordsFromProjectionLocked(final String[] query, String request,
|
||||||
|
@ -219,31 +194,20 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addWordsLocked(final Cursor cursor) {
|
private void addWordsLocked(final Cursor cursor) {
|
||||||
final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
|
|
||||||
if (cursor == null) return;
|
if (cursor == null) return;
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
final int indexWord = cursor.getColumnIndex(Words.WORD);
|
final int indexWord = cursor.getColumnIndex(Words.WORD);
|
||||||
final int indexShortcut = hasShortcutColumn ? cursor.getColumnIndex(Words.SHORTCUT) : 0;
|
|
||||||
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
|
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
|
||||||
while (!cursor.isAfterLast()) {
|
while (!cursor.isAfterLast()) {
|
||||||
final String word = cursor.getString(indexWord);
|
final String word = cursor.getString(indexWord);
|
||||||
final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null;
|
|
||||||
final int frequency = cursor.getInt(indexFrequency);
|
final int frequency = cursor.getInt(indexFrequency);
|
||||||
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
|
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
|
||||||
// Safeguard against adding really long words.
|
// Safeguard against adding really long words.
|
||||||
if (word.length() <= MAX_WORD_LENGTH) {
|
if (word.length() <= MAX_WORD_LENGTH) {
|
||||||
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
||||||
addUnigramLocked(word, adjustedFrequency, null /* shortcutTarget */,
|
addUnigramLocked(word, adjustedFrequency, false /* isNotAWord */,
|
||||||
0 /* shortcutFreq */, false /* isNotAWord */,
|
|
||||||
false /* isPossiblyOffensive */,
|
false /* isPossiblyOffensive */,
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
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();
|
cursor.moveToNext();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,13 +37,11 @@ import javax.annotation.Nullable;
|
||||||
public final class WordProperty implements Comparable<WordProperty> {
|
public final class WordProperty implements Comparable<WordProperty> {
|
||||||
public final String mWord;
|
public final String mWord;
|
||||||
public final ProbabilityInfo mProbabilityInfo;
|
public final ProbabilityInfo mProbabilityInfo;
|
||||||
public final ArrayList<WeightedString> mShortcutTargets;
|
|
||||||
public final ArrayList<NgramProperty> mNgrams;
|
public final ArrayList<NgramProperty> mNgrams;
|
||||||
// TODO: Support mIsBeginningOfSentence.
|
// TODO: Support mIsBeginningOfSentence.
|
||||||
public final boolean mIsBeginningOfSentence;
|
public final boolean mIsBeginningOfSentence;
|
||||||
public final boolean mIsNotAWord;
|
public final boolean mIsNotAWord;
|
||||||
public final boolean mIsPossiblyOffensive;
|
public final boolean mIsPossiblyOffensive;
|
||||||
public final boolean mHasShortcuts;
|
|
||||||
public final boolean mHasNgrams;
|
public final boolean mHasNgrams;
|
||||||
|
|
||||||
private int mHashCode = 0;
|
private int mHashCode = 0;
|
||||||
|
@ -51,12 +49,10 @@ public final class WordProperty implements Comparable<WordProperty> {
|
||||||
// TODO: Support n-gram.
|
// TODO: Support n-gram.
|
||||||
@UsedForTesting
|
@UsedForTesting
|
||||||
public WordProperty(final String word, final ProbabilityInfo probabilityInfo,
|
public WordProperty(final String word, final ProbabilityInfo probabilityInfo,
|
||||||
final ArrayList<WeightedString> shortcutTargets,
|
|
||||||
@Nullable final ArrayList<WeightedString> bigrams,
|
@Nullable final ArrayList<WeightedString> bigrams,
|
||||||
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
||||||
mWord = word;
|
mWord = word;
|
||||||
mProbabilityInfo = probabilityInfo;
|
mProbabilityInfo = probabilityInfo;
|
||||||
mShortcutTargets = shortcutTargets;
|
|
||||||
if (null == bigrams) {
|
if (null == bigrams) {
|
||||||
mNgrams = null;
|
mNgrams = null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,7 +66,6 @@ public final class WordProperty implements Comparable<WordProperty> {
|
||||||
mIsNotAWord = isNotAWord;
|
mIsNotAWord = isNotAWord;
|
||||||
mIsPossiblyOffensive = isPossiblyOffensive;
|
mIsPossiblyOffensive = isPossiblyOffensive;
|
||||||
mHasNgrams = bigrams != null && !bigrams.isEmpty();
|
mHasNgrams = bigrams != null && !bigrams.isEmpty();
|
||||||
mHasShortcuts = shortcutTargets != null && !shortcutTargets.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProbabilityInfo createProbabilityInfoFromArray(final int[] probabilityInfo) {
|
private static ProbabilityInfo createProbabilityInfoFromArray(final int[] probabilityInfo) {
|
||||||
|
@ -84,21 +79,17 @@ public final class WordProperty implements Comparable<WordProperty> {
|
||||||
// Construct word property using information from native code.
|
// Construct word property using information from native code.
|
||||||
// This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY.
|
// This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY.
|
||||||
public WordProperty(final int[] codePoints, final boolean isNotAWord,
|
public WordProperty(final int[] codePoints, final boolean isNotAWord,
|
||||||
final boolean isPossiblyOffensive, final boolean hasBigram, final boolean hasShortcuts,
|
final boolean isPossiblyOffensive, final boolean hasBigram,
|
||||||
final boolean isBeginningOfSentence, final int[] probabilityInfo,
|
final boolean isBeginningOfSentence, final int[] probabilityInfo,
|
||||||
final ArrayList<int[][]> ngramPrevWordsArray,
|
final ArrayList<int[][]> ngramPrevWordsArray,
|
||||||
final ArrayList<boolean[]> ngramPrevWordIsBeginningOfSentenceArray,
|
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);
|
mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
|
||||||
mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo);
|
mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo);
|
||||||
mShortcutTargets = new ArrayList<>();
|
|
||||||
final ArrayList<NgramProperty> ngrams = new ArrayList<>();
|
final ArrayList<NgramProperty> ngrams = new ArrayList<>();
|
||||||
mIsBeginningOfSentence = isBeginningOfSentence;
|
mIsBeginningOfSentence = isBeginningOfSentence;
|
||||||
mIsNotAWord = isNotAWord;
|
mIsNotAWord = isNotAWord;
|
||||||
mIsPossiblyOffensive = isPossiblyOffensive;
|
mIsPossiblyOffensive = isPossiblyOffensive;
|
||||||
mHasShortcuts = hasShortcuts;
|
|
||||||
mHasNgrams = hasBigram;
|
mHasNgrams = hasBigram;
|
||||||
|
|
||||||
final int relatedNgramCount = ngramTargets.size();
|
final int relatedNgramCount = ngramTargets.size();
|
||||||
|
@ -121,14 +112,6 @@ public final class WordProperty implements Comparable<WordProperty> {
|
||||||
ngrams.add(new NgramProperty(ngramTarget, ngramContext));
|
ngrams.add(new NgramProperty(ngramTarget, ngramContext));
|
||||||
}
|
}
|
||||||
mNgrams = ngrams.isEmpty() ? null : ngrams;
|
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
|
// TODO: Remove
|
||||||
|
@ -154,7 +137,6 @@ public final class WordProperty implements Comparable<WordProperty> {
|
||||||
return Arrays.hashCode(new Object[] {
|
return Arrays.hashCode(new Object[] {
|
||||||
word.mWord,
|
word.mWord,
|
||||||
word.mProbabilityInfo,
|
word.mProbabilityInfo,
|
||||||
word.mShortcutTargets,
|
|
||||||
word.mNgrams,
|
word.mNgrams,
|
||||||
word.mIsNotAWord,
|
word.mIsNotAWord,
|
||||||
word.mIsPossiblyOffensive
|
word.mIsPossiblyOffensive
|
||||||
|
@ -185,10 +167,10 @@ public final class WordProperty implements Comparable<WordProperty> {
|
||||||
if (o == this) return true;
|
if (o == this) return true;
|
||||||
if (!(o instanceof WordProperty)) return false;
|
if (!(o instanceof WordProperty)) return false;
|
||||||
WordProperty w = (WordProperty)o;
|
WordProperty w = (WordProperty)o;
|
||||||
return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord)
|
return mProbabilityInfo.equals(w.mProbabilityInfo)
|
||||||
&& mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams)
|
&& mWord.equals(w.mWord) && equals(mNgrams, w.mNgrams)
|
||||||
&& mIsNotAWord == w.mIsNotAWord && mIsPossiblyOffensive == w.mIsPossiblyOffensive
|
&& mIsNotAWord == w.mIsNotAWord && mIsPossiblyOffensive == w.mIsPossiblyOffensive
|
||||||
&& mHasNgrams == w.mHasNgrams && mHasShortcuts && w.mHasNgrams;
|
&& mHasNgrams == w.mHasNgrams;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TDOO: Have a utility method like java.util.Objects.equals.
|
// TDOO: Have a utility method like java.util.Objects.equals.
|
||||||
|
|
|
@ -25,6 +25,7 @@ import android.preference.Preference;
|
||||||
import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
|
import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.RichInputMethodManager;
|
import com.android.inputmethod.latin.RichInputMethodManager;
|
||||||
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "Preferences" settings sub screen.
|
* "Preferences" settings sub screen.
|
||||||
|
@ -72,11 +73,9 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
|
||||||
final Preference voiceInputKeyOption = findPreference(Settings.PREF_VOICE_INPUT_KEY);
|
final Preference voiceInputKeyOption = findPreference(Settings.PREF_VOICE_INPUT_KEY);
|
||||||
if (voiceInputKeyOption != null) {
|
if (voiceInputKeyOption != null) {
|
||||||
RichInputMethodManager.getInstance().refreshSubtypeCaches();
|
RichInputMethodManager.getInstance().refreshSubtypeCaches();
|
||||||
final boolean isShortcutImeEnabled = RichInputMethodManager.getInstance()
|
voiceInputKeyOption.setEnabled(Constants.JELLY_BEAN_OR_HIGHER);
|
||||||
.isShortcutImeEnabled();
|
voiceInputKeyOption.setSummary(Constants.JELLY_BEAN_OR_HIGHER
|
||||||
voiceInputKeyOption.setEnabled(isShortcutImeEnabled);
|
? null : getText(R.string.voice_input_disabled_summary));
|
||||||
voiceInputKeyOption.setSummary(
|
|
||||||
isShortcutImeEnabled ? null : getText(R.string.voice_input_disabled_summary));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import com.android.inputmethod.compat.AppWorkaroundsUtils;
|
||||||
import com.android.inputmethod.latin.InputAttributes;
|
import com.android.inputmethod.latin.InputAttributes;
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.RichInputMethodManager;
|
import com.android.inputmethod.latin.RichInputMethodManager;
|
||||||
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
import com.android.inputmethod.latin.utils.AsyncResultHolder;
|
import com.android.inputmethod.latin.utils.AsyncResultHolder;
|
||||||
import com.android.inputmethod.latin.utils.ResourceUtils;
|
import com.android.inputmethod.latin.utils.ResourceUtils;
|
||||||
import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
|
import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
|
||||||
|
@ -136,7 +137,7 @@ public class SettingsValues {
|
||||||
DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true);
|
DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true);
|
||||||
mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res)
|
mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res)
|
||||||
&& mInputAttributes.mShouldShowVoiceInputKey
|
&& mInputAttributes.mShouldShowVoiceInputKey
|
||||||
&& RichInputMethodManager.getInstance().isShortcutImeEnabled();
|
&& Constants.JELLY_BEAN_OR_HIGHER;
|
||||||
final String autoCorrectionThresholdRawValue = prefs.getString(
|
final String autoCorrectionThresholdRawValue = prefs.getString(
|
||||||
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
|
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
|
||||||
res.getString(R.string.auto_correction_threshold_mode_index_modest));
|
res.getString(R.string.auto_correction_threshold_mode_index_modest));
|
||||||
|
|
|
@ -26,7 +26,6 @@ import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
|
||||||
import com.android.inputmethod.compat.UserDictionaryCompatUtils;
|
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
import com.android.inputmethod.latin.common.LocaleUtils;
|
import com.android.inputmethod.latin.common.LocaleUtils;
|
||||||
|
|
||||||
|
@ -47,10 +46,7 @@ import javax.annotation.Nullable;
|
||||||
public class UserDictionaryAddWordContents {
|
public class UserDictionaryAddWordContents {
|
||||||
public static final String EXTRA_MODE = "mode";
|
public static final String EXTRA_MODE = "mode";
|
||||||
public static final String EXTRA_WORD = "word";
|
public static final String EXTRA_WORD = "word";
|
||||||
public static final String EXTRA_SHORTCUT = "shortcut";
|
|
||||||
public static final String EXTRA_LOCALE = "locale";
|
public static final String EXTRA_LOCALE = "locale";
|
||||||
public static final String EXTRA_ORIGINAL_WORD = "originalWord";
|
|
||||||
public static final String EXTRA_ORIGINAL_SHORTCUT = "originalShortcut";
|
|
||||||
|
|
||||||
public static final int MODE_EDIT = 0;
|
public static final int MODE_EDIT = 0;
|
||||||
public static final int MODE_INSERT = 1;
|
public static final int MODE_INSERT = 1;
|
||||||
|
@ -63,20 +59,12 @@ public class UserDictionaryAddWordContents {
|
||||||
|
|
||||||
private final int mMode; // Either MODE_EDIT or MODE_INSERT
|
private final int mMode; // Either MODE_EDIT or MODE_INSERT
|
||||||
private final EditText mWordEditText;
|
private final EditText mWordEditText;
|
||||||
private final EditText mShortcutEditText;
|
|
||||||
private String mLocale;
|
private String mLocale;
|
||||||
private final String mOldWord;
|
private final String mOldWord;
|
||||||
private final String mOldShortcut;
|
|
||||||
private String mSavedWord;
|
private String mSavedWord;
|
||||||
private String mSavedShortcut;
|
|
||||||
|
|
||||||
/* package */ UserDictionaryAddWordContents(final View view, final Bundle args) {
|
/* package */ UserDictionaryAddWordContents(final View view, final Bundle args) {
|
||||||
mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
|
mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
|
||||||
mShortcutEditText = (EditText)view.findViewById(R.id.user_dictionary_add_shortcut);
|
|
||||||
if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
|
|
||||||
mShortcutEditText.setVisibility(View.GONE);
|
|
||||||
view.findViewById(R.id.user_dictionary_add_shortcut_label).setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
final String word = args.getString(EXTRA_WORD);
|
final String word = args.getString(EXTRA_WORD);
|
||||||
if (null != word) {
|
if (null != word) {
|
||||||
mWordEditText.setText(word);
|
mWordEditText.setText(word);
|
||||||
|
@ -84,17 +72,6 @@ public class UserDictionaryAddWordContents {
|
||||||
// it's too long to be edited.
|
// it's too long to be edited.
|
||||||
mWordEditText.setSelection(mWordEditText.getText().length());
|
mWordEditText.setSelection(mWordEditText.getText().length());
|
||||||
}
|
}
|
||||||
final String shortcut;
|
|
||||||
if (UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
|
|
||||||
shortcut = args.getString(EXTRA_SHORTCUT);
|
|
||||||
if (null != shortcut && null != mShortcutEditText) {
|
|
||||||
mShortcutEditText.setText(shortcut);
|
|
||||||
}
|
|
||||||
mOldShortcut = args.getString(EXTRA_SHORTCUT);
|
|
||||||
} else {
|
|
||||||
shortcut = null;
|
|
||||||
mOldShortcut = null;
|
|
||||||
}
|
|
||||||
mMode = args.getInt(EXTRA_MODE); // default return value for #getInt() is 0 = MODE_EDIT
|
mMode = args.getInt(EXTRA_MODE); // default return value for #getInt() is 0 = MODE_EDIT
|
||||||
mOldWord = args.getString(EXTRA_WORD);
|
mOldWord = args.getString(EXTRA_WORD);
|
||||||
updateLocale(args.getString(EXTRA_LOCALE));
|
updateLocale(args.getString(EXTRA_LOCALE));
|
||||||
|
@ -103,10 +80,8 @@ public class UserDictionaryAddWordContents {
|
||||||
/* package */ UserDictionaryAddWordContents(final View view,
|
/* package */ UserDictionaryAddWordContents(final View view,
|
||||||
final UserDictionaryAddWordContents oldInstanceToBeEdited) {
|
final UserDictionaryAddWordContents oldInstanceToBeEdited) {
|
||||||
mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
|
mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
|
||||||
mShortcutEditText = (EditText)view.findViewById(R.id.user_dictionary_add_shortcut);
|
|
||||||
mMode = MODE_EDIT;
|
mMode = MODE_EDIT;
|
||||||
mOldWord = oldInstanceToBeEdited.mSavedWord;
|
mOldWord = oldInstanceToBeEdited.mSavedWord;
|
||||||
mOldShortcut = oldInstanceToBeEdited.mSavedShortcut;
|
|
||||||
updateLocale(mLocale);
|
updateLocale(mLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,13 +93,6 @@ public class UserDictionaryAddWordContents {
|
||||||
|
|
||||||
/* package */ void saveStateIntoBundle(final Bundle outState) {
|
/* package */ void saveStateIntoBundle(final Bundle outState) {
|
||||||
outState.putString(EXTRA_WORD, mWordEditText.getText().toString());
|
outState.putString(EXTRA_WORD, mWordEditText.getText().toString());
|
||||||
outState.putString(EXTRA_ORIGINAL_WORD, mOldWord);
|
|
||||||
if (null != mShortcutEditText) {
|
|
||||||
outState.putString(EXTRA_SHORTCUT, mShortcutEditText.getText().toString());
|
|
||||||
}
|
|
||||||
if (null != mOldShortcut) {
|
|
||||||
outState.putString(EXTRA_ORIGINAL_SHORTCUT, mOldShortcut);
|
|
||||||
}
|
|
||||||
outState.putString(EXTRA_LOCALE, mLocale);
|
outState.putString(EXTRA_LOCALE, mLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +100,7 @@ public class UserDictionaryAddWordContents {
|
||||||
if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) {
|
if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) {
|
||||||
// Mode edit: remove the old entry.
|
// Mode edit: remove the old entry.
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
UserDictionarySettings.deleteWord(mOldWord, mOldShortcut, resolver);
|
UserDictionarySettings.deleteWord(mOldWord, resolver);
|
||||||
}
|
}
|
||||||
// If we are in add mode, nothing was added, so we don't need to do anything.
|
// If we are in add mode, nothing was added, so we don't need to do anything.
|
||||||
}
|
}
|
||||||
|
@ -143,50 +111,31 @@ public class UserDictionaryAddWordContents {
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) {
|
if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) {
|
||||||
// Mode edit: remove the old entry.
|
// Mode edit: remove the old entry.
|
||||||
UserDictionarySettings.deleteWord(mOldWord, mOldShortcut, resolver);
|
UserDictionarySettings.deleteWord(mOldWord, resolver);
|
||||||
}
|
}
|
||||||
final String newWord = mWordEditText.getText().toString();
|
final String newWord = mWordEditText.getText().toString();
|
||||||
final String newShortcut;
|
|
||||||
if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
|
|
||||||
newShortcut = null;
|
|
||||||
} else if (null == mShortcutEditText) {
|
|
||||||
newShortcut = null;
|
|
||||||
} else {
|
|
||||||
final String tmpShortcut = mShortcutEditText.getText().toString();
|
|
||||||
if (TextUtils.isEmpty(tmpShortcut)) {
|
|
||||||
newShortcut = null;
|
|
||||||
} else {
|
|
||||||
newShortcut = tmpShortcut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (TextUtils.isEmpty(newWord)) {
|
if (TextUtils.isEmpty(newWord)) {
|
||||||
// If the word is somehow empty, don't insert it.
|
// If the word is somehow empty, don't insert it.
|
||||||
return CODE_CANCEL;
|
return CODE_CANCEL;
|
||||||
}
|
}
|
||||||
mSavedWord = newWord;
|
mSavedWord = newWord;
|
||||||
mSavedShortcut = newShortcut;
|
// If the word already exists in the database, then we should not insert.
|
||||||
// If there is no shortcut, and the word already exists in the database, then we
|
if (hasWord(newWord, context)) {
|
||||||
// should not insert, because either A. the word exists with no shortcut, in which
|
|
||||||
// case the exact same thing we want to insert is already there, or B. the word
|
|
||||||
// exists with at least one shortcut, in which case it has priority on our word.
|
|
||||||
if (TextUtils.isEmpty(newShortcut) && hasWord(newWord, context)) {
|
|
||||||
return CODE_ALREADY_PRESENT;
|
return CODE_ALREADY_PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disallow duplicates. If the same word with no shortcut is defined, remove it; if
|
// Disallow duplicates. If the same word is defined, remove it.
|
||||||
// the same word with the same shortcut is defined, remove it; but we don't mind if
|
UserDictionarySettings.deleteWord(newWord, resolver);
|
||||||
// there is the same word with a different, non-empty shortcut.
|
|
||||||
UserDictionarySettings.deleteWord(newWord, null, resolver);
|
|
||||||
if (!TextUtils.isEmpty(newShortcut)) {
|
|
||||||
// If newShortcut is empty we just deleted this, no need to do it again
|
|
||||||
UserDictionarySettings.deleteWord(newWord, newShortcut, resolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
// In this class we use the empty string to represent 'all locales' and mLocale cannot
|
// In this class we use the empty string to represent 'all locales' and mLocale cannot
|
||||||
// be null. However the addWord method takes null to mean 'all locales'.
|
// be null. However the addWord method takes null to mean 'all locales'.
|
||||||
UserDictionaryCompatUtils.addWord(context, newWord.toString(),
|
final Locale locale = TextUtils.isEmpty(mLocale) ?
|
||||||
FREQUENCY_FOR_USER_DICTIONARY_ADDS, newShortcut, TextUtils.isEmpty(mLocale) ?
|
null : LocaleUtils.constructLocaleFromString(mLocale);
|
||||||
null : LocaleUtils.constructLocaleFromString(mLocale));
|
final Locale currentLocale = context.getResources().getConfiguration().locale;
|
||||||
|
final boolean useCurrentLocale = currentLocale.equals(locale);
|
||||||
|
UserDictionary.Words.addWord(context, newWord.toString(),
|
||||||
|
FREQUENCY_FOR_USER_DICTIONARY_ADDS, null /* shortcut */,
|
||||||
|
useCurrentLocale ? Locale.getDefault() : null);
|
||||||
|
|
||||||
return CODE_WORD_ADDED;
|
return CODE_WORD_ADDED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
|
|
||||||
import com.android.inputmethod.latin.R;
|
import com.android.inputmethod.latin.R;
|
||||||
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
import com.android.inputmethod.latin.common.LocaleUtils;
|
import com.android.inputmethod.latin.common.LocaleUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -74,7 +75,7 @@ public class UserDictionaryList extends PreferenceFragment {
|
||||||
} finally {
|
} finally {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
|
if (!Constants.JELLY_BEAN_OR_HIGHER) {
|
||||||
// For ICS, we need to show "For all languages" in case that the keyboard locale
|
// For ICS, we need to show "For all languages" in case that the keyboard locale
|
||||||
// is different from the system locale
|
// is different from the system locale
|
||||||
localeSet.add("");
|
localeSet.add("");
|
||||||
|
|
|
@ -48,42 +48,18 @@ import java.util.Locale;
|
||||||
|
|
||||||
public class UserDictionarySettings extends ListFragment {
|
public class UserDictionarySettings extends ListFragment {
|
||||||
|
|
||||||
public static final boolean IS_SHORTCUT_API_SUPPORTED =
|
private static final String[] QUERY_PROJECTION = {
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
|
UserDictionary.Words._ID, UserDictionary.Words.WORD
|
||||||
|
|
||||||
private static final String[] QUERY_PROJECTION_SHORTCUT_UNSUPPORTED =
|
|
||||||
{ UserDictionary.Words._ID, UserDictionary.Words.WORD};
|
|
||||||
private static final String[] QUERY_PROJECTION_SHORTCUT_SUPPORTED =
|
|
||||||
{ UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT};
|
|
||||||
private static final String[] QUERY_PROJECTION =
|
|
||||||
IS_SHORTCUT_API_SUPPORTED ?
|
|
||||||
QUERY_PROJECTION_SHORTCUT_SUPPORTED : QUERY_PROJECTION_SHORTCUT_UNSUPPORTED;
|
|
||||||
|
|
||||||
// The index of the shortcut in the above array.
|
|
||||||
private static final int INDEX_SHORTCUT = 2;
|
|
||||||
|
|
||||||
private static final String[] ADAPTER_FROM_SHORTCUT_UNSUPPORTED = {
|
|
||||||
UserDictionary.Words.WORD,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] ADAPTER_FROM_SHORTCUT_SUPPORTED = {
|
private static final String[] ADAPTER_FROM = {
|
||||||
UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT
|
UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] ADAPTER_FROM = IS_SHORTCUT_API_SUPPORTED ?
|
private static final int[] ADAPTER_TO = {
|
||||||
ADAPTER_FROM_SHORTCUT_SUPPORTED : ADAPTER_FROM_SHORTCUT_UNSUPPORTED;
|
|
||||||
|
|
||||||
private static final int[] ADAPTER_TO_SHORTCUT_UNSUPPORTED = {
|
|
||||||
android.R.id.text1,
|
android.R.id.text1,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int[] ADAPTER_TO_SHORTCUT_SUPPORTED = {
|
|
||||||
android.R.id.text1, android.R.id.text2
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final int[] ADAPTER_TO = IS_SHORTCUT_API_SUPPORTED ?
|
|
||||||
ADAPTER_TO_SHORTCUT_SUPPORTED : ADAPTER_TO_SHORTCUT_UNSUPPORTED;
|
|
||||||
|
|
||||||
// Either the locale is empty (means the word is applicable to all locales)
|
// Either the locale is empty (means the word is applicable to all locales)
|
||||||
// or the word equals our current locale
|
// or the word equals our current locale
|
||||||
private static final String QUERY_SELECTION =
|
private static final String QUERY_SELECTION =
|
||||||
|
@ -91,13 +67,7 @@ public class UserDictionarySettings extends ListFragment {
|
||||||
private static final String QUERY_SELECTION_ALL_LOCALES =
|
private static final String QUERY_SELECTION_ALL_LOCALES =
|
||||||
UserDictionary.Words.LOCALE + " is null";
|
UserDictionary.Words.LOCALE + " is null";
|
||||||
|
|
||||||
private static final String DELETE_SELECTION_WITH_SHORTCUT = UserDictionary.Words.WORD
|
private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?";
|
||||||
+ "=? AND " + UserDictionary.Words.SHORTCUT + "=?";
|
|
||||||
private static final String DELETE_SELECTION_WITHOUT_SHORTCUT = UserDictionary.Words.WORD
|
|
||||||
+ "=? AND " + UserDictionary.Words.SHORTCUT + " is null OR "
|
|
||||||
+ UserDictionary.Words.SHORTCUT + "=''";
|
|
||||||
private static final String DELETE_SELECTION_SHORTCUT_UNSUPPORTED =
|
|
||||||
UserDictionary.Words.WORD + "=?";
|
|
||||||
|
|
||||||
private static final int OPTIONS_MENU_ADD = Menu.FIRST;
|
private static final int OPTIONS_MENU_ADD = Menu.FIRST;
|
||||||
|
|
||||||
|
@ -192,20 +162,18 @@ public class UserDictionarySettings extends ListFragment {
|
||||||
@Override
|
@Override
|
||||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
final String word = getWord(position);
|
final String word = getWord(position);
|
||||||
final String shortcut = getShortcut(position);
|
|
||||||
if (word != null) {
|
if (word != null) {
|
||||||
showAddOrEditDialog(word, shortcut);
|
showAddOrEditDialog(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
final Locale systemLocale = getResources().getConfiguration().locale;
|
final Locale systemLocale = getResources().getConfiguration().locale;
|
||||||
if (!TextUtils.isEmpty(mLocale) && !mLocale.equals(systemLocale.toString())) {
|
if (!TextUtils.isEmpty(mLocale) && !mLocale.equals(systemLocale.toString())) {
|
||||||
// Hide the add button for ICS because it doesn't support specifying a locale
|
// Hide the add button for ICS because it doesn't support specifying a locale
|
||||||
// for an entry. This new "locale"-aware API has been added in conjunction
|
// for an entry.
|
||||||
// with the shortcut API.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +187,7 @@ public class UserDictionarySettings extends ListFragment {
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
if (item.getItemId() == OPTIONS_MENU_ADD) {
|
if (item.getItemId() == OPTIONS_MENU_ADD) {
|
||||||
showAddOrEditDialog(null, null);
|
showAddOrEditDialog(null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -228,18 +196,15 @@ public class UserDictionarySettings extends ListFragment {
|
||||||
/**
|
/**
|
||||||
* Add or edit a word. If editingWord is null, it's an add; otherwise, it's an edit.
|
* Add or edit a word. If editingWord is null, it's an add; otherwise, it's an edit.
|
||||||
* @param editingWord the word to edit, or null if it's an add.
|
* @param editingWord the word to edit, or null if it's an add.
|
||||||
* @param editingShortcut the shortcut for this entry, or null if none.
|
|
||||||
*/
|
*/
|
||||||
private void showAddOrEditDialog(final String editingWord, final String editingShortcut) {
|
private void showAddOrEditDialog(final String editingWord) {
|
||||||
final Bundle args = new Bundle();
|
final Bundle args = new Bundle();
|
||||||
args.putInt(UserDictionaryAddWordContents.EXTRA_MODE, null == editingWord
|
args.putInt(UserDictionaryAddWordContents.EXTRA_MODE, null == editingWord
|
||||||
? UserDictionaryAddWordContents.MODE_INSERT
|
? UserDictionaryAddWordContents.MODE_INSERT
|
||||||
: UserDictionaryAddWordContents.MODE_EDIT);
|
: UserDictionaryAddWordContents.MODE_EDIT);
|
||||||
args.putString(UserDictionaryAddWordContents.EXTRA_WORD, editingWord);
|
args.putString(UserDictionaryAddWordContents.EXTRA_WORD, editingWord);
|
||||||
args.putString(UserDictionaryAddWordContents.EXTRA_SHORTCUT, editingShortcut);
|
|
||||||
args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale);
|
args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale);
|
||||||
android.preference.PreferenceActivity pa =
|
getActivity();
|
||||||
(android.preference.PreferenceActivity)getActivity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getWord(final int position) {
|
private String getWord(final int position) {
|
||||||
|
@ -252,31 +217,8 @@ public class UserDictionarySettings extends ListFragment {
|
||||||
mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD));
|
mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getShortcut(final int position) {
|
public static void deleteWord(final String word, final ContentResolver resolver) {
|
||||||
if (!IS_SHORTCUT_API_SUPPORTED) return null;
|
resolver.delete(UserDictionary.Words.CONTENT_URI, DELETE_SELECTION, new String[] { word });
|
||||||
if (null == mCursor) return null;
|
|
||||||
mCursor.moveToPosition(position);
|
|
||||||
// Handle a possible race-condition
|
|
||||||
if (mCursor.isAfterLast()) return null;
|
|
||||||
|
|
||||||
return mCursor.getString(
|
|
||||||
mCursor.getColumnIndexOrThrow(UserDictionary.Words.SHORTCUT));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void deleteWord(final String word, final String shortcut,
|
|
||||||
final ContentResolver resolver) {
|
|
||||||
if (!IS_SHORTCUT_API_SUPPORTED) {
|
|
||||||
resolver.delete(UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_SHORTCUT_UNSUPPORTED,
|
|
||||||
new String[] { word });
|
|
||||||
} else if (TextUtils.isEmpty(shortcut)) {
|
|
||||||
resolver.delete(
|
|
||||||
UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITHOUT_SHORTCUT,
|
|
||||||
new String[] { word });
|
|
||||||
} else {
|
|
||||||
resolver.delete(
|
|
||||||
UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITH_SHORTCUT,
|
|
||||||
new String[] { word, shortcut });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer {
|
private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer {
|
||||||
|
@ -286,22 +228,7 @@ public class UserDictionarySettings extends ListFragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setViewValue(final View v, final Cursor c, final int columnIndex) {
|
public boolean setViewValue(final View v, final Cursor c, final int columnIndex) {
|
||||||
if (!IS_SHORTCUT_API_SUPPORTED) {
|
// just let SimpleCursorAdapter set the view values
|
||||||
// just let SimpleCursorAdapter set the view values
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (columnIndex == INDEX_SHORTCUT) {
|
|
||||||
final String shortcut = c.getString(INDEX_SHORTCUT);
|
|
||||||
if (TextUtils.isEmpty(shortcut)) {
|
|
||||||
v.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
((TextView)v).setText(shortcut);
|
|
||||||
v.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
v.invalidate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,6 @@ package com.android.inputmethod.latin.utils;
|
||||||
import com.android.inputmethod.latin.makedict.DictionaryHeader;
|
import com.android.inputmethod.latin.makedict.DictionaryHeader;
|
||||||
import com.android.inputmethod.latin.makedict.NgramProperty;
|
import com.android.inputmethod.latin.makedict.NgramProperty;
|
||||||
import com.android.inputmethod.latin.makedict.ProbabilityInfo;
|
import com.android.inputmethod.latin.makedict.ProbabilityInfo;
|
||||||
import com.android.inputmethod.latin.makedict.WeightedString;
|
|
||||||
import com.android.inputmethod.latin.makedict.WordProperty;
|
import com.android.inputmethod.latin.makedict.WordProperty;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -29,7 +28,6 @@ public class CombinedFormatUtils {
|
||||||
public static final String BIGRAM_TAG = "bigram";
|
public static final String BIGRAM_TAG = "bigram";
|
||||||
public static final String NGRAM_TAG = "ngram";
|
public static final String NGRAM_TAG = "ngram";
|
||||||
public static final String NGRAM_PREV_WORD_TAG = "prev_word";
|
public static final String NGRAM_PREV_WORD_TAG = "prev_word";
|
||||||
public static final String SHORTCUT_TAG = "shortcut";
|
|
||||||
public static final String PROBABILITY_TAG = "f";
|
public static final String PROBABILITY_TAG = "f";
|
||||||
public static final String HISTORICAL_INFO_TAG = "historicalInfo";
|
public static final String HISTORICAL_INFO_TAG = "historicalInfo";
|
||||||
public static final String HISTORICAL_INFO_SEPARATOR = ":";
|
public static final String HISTORICAL_INFO_SEPARATOR = ":";
|
||||||
|
@ -71,14 +69,6 @@ public class CombinedFormatUtils {
|
||||||
builder.append("," + POSSIBLY_OFFENSIVE_TAG + "=" + TRUE_VALUE);
|
builder.append("," + POSSIBLY_OFFENSIVE_TAG + "=" + TRUE_VALUE);
|
||||||
}
|
}
|
||||||
builder.append("\n");
|
builder.append("\n");
|
||||||
if (wordProperty.mHasShortcuts) {
|
|
||||||
for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
builder.append(" " + SHORTCUT_TAG + "=" + shortcutTarget.mWord);
|
|
||||||
builder.append(",");
|
|
||||||
builder.append(formatProbabilityInfo(shortcutTarget.mProbabilityInfo));
|
|
||||||
builder.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wordProperty.mHasNgrams) {
|
if (wordProperty.mHasNgrams) {
|
||||||
for (final NgramProperty ngramProperty : wordProperty.mNgrams) {
|
for (final NgramProperty ngramProperty : wordProperty.mNgrams) {
|
||||||
builder.append(" " + NGRAM_TAG + "=" + ngramProperty.mTargetWord.mWord);
|
builder.append(" " + NGRAM_TAG + "=" + ngramProperty.mTargetWord.mWord);
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2014 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.inputmethod.latin.utils;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class keeps track of the network connectivity state by receiving the system intent
|
|
||||||
* {@link ConnectivityManager#CONNECTIVITY_ACTION}, and invokes an registered call back to notify
|
|
||||||
* changes of the network connectivity state.
|
|
||||||
*/
|
|
||||||
public final class NetworkConnectivityUtils {
|
|
||||||
private static NetworkConnectivityReceiver sNetworkConnectivityReceiver;
|
|
||||||
|
|
||||||
public interface NetworkStateChangeListener {
|
|
||||||
/**
|
|
||||||
* Called when the network connectivity state has changed.
|
|
||||||
*/
|
|
||||||
public void onNetworkStateChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class NetworkConnectivityReceiver extends BroadcastReceiver {
|
|
||||||
@Nonnull
|
|
||||||
private final NetworkStateChangeListener mListener;
|
|
||||||
private boolean mIsNetworkConnected;
|
|
||||||
|
|
||||||
public NetworkConnectivityReceiver(@Nonnull final NetworkStateChangeListener listener,
|
|
||||||
final boolean isNetworkConnected) {
|
|
||||||
mListener = listener;
|
|
||||||
mIsNetworkConnected = isNetworkConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized boolean isNetworkConnected() {
|
|
||||||
return mIsNetworkConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
|
||||||
final String action = intent.getAction();
|
|
||||||
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
|
|
||||||
final boolean noConnection = intent.getBooleanExtra(
|
|
||||||
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
|
|
||||||
synchronized (this) {
|
|
||||||
mIsNetworkConnected = !noConnection;
|
|
||||||
}
|
|
||||||
mListener.onNetworkStateChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private NetworkConnectivityUtils() {
|
|
||||||
// This utility class is not publicly instantiable.
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onCreate(@Nonnull final Context context,
|
|
||||||
@Nonnull final NetworkStateChangeListener listener) {
|
|
||||||
final ConnectivityManager connectivityManager =
|
|
||||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
final NetworkInfo info = connectivityManager.getActiveNetworkInfo();
|
|
||||||
final boolean isNetworkConnected = (info != null && info.isConnected());
|
|
||||||
|
|
||||||
// Register {@link BroadcastReceiver} for the network connectivity state change.
|
|
||||||
final NetworkConnectivityReceiver receiver = new NetworkConnectivityReceiver(
|
|
||||||
listener, isNetworkConnected);
|
|
||||||
final IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
|
||||||
context.registerReceiver(receiver, filter);
|
|
||||||
|
|
||||||
sNetworkConnectivityReceiver = receiver;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onDestroy(final Context context) {
|
|
||||||
context.unregisterReceiver(sNetworkConnectivityReceiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isNetworkConnected() {
|
|
||||||
final NetworkConnectivityReceiver receiver = sNetworkConnectivityReceiver;
|
|
||||||
return receiver != null && receiver.isNetworkConnected();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,19 +17,20 @@
|
||||||
package com.android.inputmethod.compat;
|
package com.android.inputmethod.compat;
|
||||||
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.Build;
|
|
||||||
import android.test.AndroidTestCase;
|
import android.test.AndroidTestCase;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
|
|
||||||
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public class LocaleSpanCompatUtilsTests extends AndroidTestCase {
|
public class LocaleSpanCompatUtilsTests extends AndroidTestCase {
|
||||||
public void testInstantiatable() {
|
public void testInstantiatable() {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
if (!Constants.JELLY_BEAN_MR1_OR_HIGHER) {
|
||||||
// LocaleSpan isn't yet available.
|
// LocaleSpan isn't yet available.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,14 @@
|
||||||
|
|
||||||
package com.android.inputmethod.keyboard.layout;
|
package com.android.inputmethod.keyboard.layout;
|
||||||
|
|
||||||
import android.os.Build;
|
import com.android.inputmethod.latin.common.Constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class offers label strings of Devanagari letters that need the dotted circle to draw
|
* This class offers label strings of Devanagari letters that need the dotted circle to draw
|
||||||
* its glyph.
|
* its glyph.
|
||||||
*/
|
*/
|
||||||
class DevanagariLetterConstants {
|
class DevanagariLetterConstants {
|
||||||
private static final boolean NEEDS_DOTTED_CIRCLE =
|
private static final boolean NEEDS_DOTTED_CIRCLE = !Constants.JELLY_BEAN_OR_HIGHER;
|
||||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN;
|
|
||||||
// U+25CC: "◌" DOTTED CIRCLE
|
// U+25CC: "◌" DOTTED CIRCLE
|
||||||
private static final String DOTTED_CIRCLE = NEEDS_DOTTED_CIRCLE ? "\u25CC" : "";
|
private static final String DOTTED_CIRCLE = NEEDS_DOTTED_CIRCLE ? "\u25CC" : "";
|
||||||
|
|
||||||
|
|
|
@ -700,8 +700,7 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
|
||||||
final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
|
final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
|
||||||
final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
|
final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
|
||||||
|
|
||||||
binaryDictionary.addUnigramEntry("", DUMMY_PROBABILITY, "" /* shortcutTarget */,
|
binaryDictionary.addUnigramEntry("", DUMMY_PROBABILITY,
|
||||||
Dictionary.NOT_A_PROBABILITY /* shortcutProbability */,
|
|
||||||
true /* isBeginningOfSentence */, true /* isNotAWord */,
|
true /* isBeginningOfSentence */, true /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */, mCurrentTime);
|
false /* isPossiblyOffensive */, mCurrentTime);
|
||||||
final NgramContext beginningOfSentenceContext = NgramContext.BEGINNING_OF_SENTENCE;
|
final NgramContext beginningOfSentenceContext = NgramContext.BEGINNING_OF_SENTENCE;
|
||||||
|
|
|
@ -182,8 +182,7 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
addUnigramWord(binaryDictionary, validLongWord, probability);
|
addUnigramWord(binaryDictionary, validLongWord, probability);
|
||||||
addUnigramWord(binaryDictionary, invalidLongWord, probability);
|
addUnigramWord(binaryDictionary, invalidLongWord, probability);
|
||||||
// Too long short cut.
|
// Too long short cut.
|
||||||
binaryDictionary.addUnigramEntry("a", probability, invalidLongWord,
|
binaryDictionary.addUnigramEntry("a", probability, false /* isBeginningOfSentence */,
|
||||||
10 /* shortcutProbability */, false /* isBeginningOfSentence */,
|
|
||||||
false /* isNotAWord */, false /* isPossiblyOffensive */,
|
false /* isNotAWord */, false /* isPossiblyOffensive */,
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
||||||
addUnigramWord(binaryDictionary, "abc", probability);
|
addUnigramWord(binaryDictionary, "abc", probability);
|
||||||
|
@ -201,8 +200,7 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
|
|
||||||
private static void addUnigramWord(final BinaryDictionary binaryDictionary, final String word,
|
private static void addUnigramWord(final BinaryDictionary binaryDictionary, final String word,
|
||||||
final int probability) {
|
final int probability) {
|
||||||
binaryDictionary.addUnigramEntry(word, probability, "" /* shortcutTarget */,
|
binaryDictionary.addUnigramEntry(word, probability,
|
||||||
Dictionary.NOT_A_PROBABILITY /* shortcutProbability */,
|
|
||||||
false /* isBeginningOfSentence */, false /* isNotAWord */,
|
false /* isBeginningOfSentence */, false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */,
|
false /* isPossiblyOffensive */,
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */);
|
BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */);
|
||||||
|
@ -884,7 +882,6 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
final boolean isPossiblyOffensive = random.nextBoolean();
|
final boolean isPossiblyOffensive = random.nextBoolean();
|
||||||
// TODO: Add tests for historical info.
|
// TODO: Add tests for historical info.
|
||||||
binaryDictionary.addUnigramEntry(word, unigramProbability,
|
binaryDictionary.addUnigramEntry(word, unigramProbability,
|
||||||
null /* shortcutTarget */, Dictionary.NOT_A_PROBABILITY,
|
|
||||||
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive,
|
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive,
|
||||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
||||||
if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) {
|
if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) {
|
||||||
|
@ -899,9 +896,7 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
assertEquals(isNotAWord, wordProperty.mIsNotAWord);
|
assertEquals(isNotAWord, wordProperty.mIsNotAWord);
|
||||||
assertEquals(isPossiblyOffensive, wordProperty.mIsPossiblyOffensive);
|
assertEquals(isPossiblyOffensive, wordProperty.mIsPossiblyOffensive);
|
||||||
assertEquals(false, wordProperty.mHasNgrams);
|
assertEquals(false, wordProperty.mHasNgrams);
|
||||||
assertEquals(false, wordProperty.mHasShortcuts);
|
|
||||||
assertEquals(unigramProbability, wordProperty.mProbabilityInfo.mProbability);
|
assertEquals(unigramProbability, wordProperty.mProbabilityInfo.mProbability);
|
||||||
assertTrue(wordProperty.mShortcutTargets.isEmpty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < BIGRAM_COUNT; i++) {
|
for (int i = 0; i < BIGRAM_COUNT; i++) {
|
||||||
|
@ -1035,137 +1030,10 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
assertTrue(bigramSet.isEmpty());
|
assertTrue(bigramSet.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAddShortcuts() {
|
|
||||||
for (final int formatVersion : DICT_FORMAT_VERSIONS) {
|
|
||||||
testAddShortcuts(formatVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testAddShortcuts(final int formatVersion) {
|
|
||||||
final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
|
|
||||||
|
|
||||||
final int unigramProbability = 100;
|
|
||||||
final int shortcutProbability = 10;
|
|
||||||
binaryDictionary.addUnigramEntry("aaa", unigramProbability, "zzz",
|
|
||||||
shortcutProbability, false /* isBeginningOfSentence */,
|
|
||||||
false /* isNotAWord */, false /* isPossiblyOffensive */, 0 /* timestamp */);
|
|
||||||
WordProperty wordProperty = binaryDictionary.getWordProperty("aaa",
|
|
||||||
false /* isBeginningOfSentence */);
|
|
||||||
assertEquals(1, wordProperty.mShortcutTargets.size());
|
|
||||||
assertEquals("zzz", wordProperty.mShortcutTargets.get(0).mWord);
|
|
||||||
assertEquals(shortcutProbability, wordProperty.mShortcutTargets.get(0).getProbability());
|
|
||||||
final int updatedShortcutProbability = 2;
|
|
||||||
binaryDictionary.addUnigramEntry("aaa", unigramProbability, "zzz",
|
|
||||||
updatedShortcutProbability, false /* isBeginningOfSentence */,
|
|
||||||
false /* isNotAWord */, false /* isPossiblyOffensive */, 0 /* timestamp */);
|
|
||||||
wordProperty = binaryDictionary.getWordProperty("aaa",
|
|
||||||
false /* isBeginningOfSentence */);
|
|
||||||
assertEquals(1, wordProperty.mShortcutTargets.size());
|
|
||||||
assertEquals("zzz", wordProperty.mShortcutTargets.get(0).mWord);
|
|
||||||
assertEquals(updatedShortcutProbability,
|
|
||||||
wordProperty.mShortcutTargets.get(0).getProbability());
|
|
||||||
binaryDictionary.addUnigramEntry("aaa", unigramProbability, "yyy",
|
|
||||||
shortcutProbability, false /* isBeginningOfSentence */, false /* isNotAWord */,
|
|
||||||
false /* isPossiblyOffensive */, 0 /* timestamp */);
|
|
||||||
final HashMap<String, Integer> shortcutTargets = new HashMap<>();
|
|
||||||
shortcutTargets.put("zzz", updatedShortcutProbability);
|
|
||||||
shortcutTargets.put("yyy", shortcutProbability);
|
|
||||||
wordProperty = binaryDictionary.getWordProperty("aaa",
|
|
||||||
false /* isBeginningOfSentence */);
|
|
||||||
assertEquals(2, wordProperty.mShortcutTargets.size());
|
|
||||||
for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord));
|
|
||||||
assertEquals((int)shortcutTargets.get(shortcutTarget.mWord),
|
|
||||||
shortcutTarget.getProbability());
|
|
||||||
shortcutTargets.remove(shortcutTarget.mWord);
|
|
||||||
}
|
|
||||||
shortcutTargets.put("zzz", updatedShortcutProbability);
|
|
||||||
shortcutTargets.put("yyy", shortcutProbability);
|
|
||||||
binaryDictionary.flushWithGC();
|
|
||||||
wordProperty = binaryDictionary.getWordProperty("aaa",
|
|
||||||
false /* isBeginningOfSentence */);
|
|
||||||
assertEquals(2, wordProperty.mShortcutTargets.size());
|
|
||||||
for (WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord));
|
|
||||||
assertEquals((int)shortcutTargets.get(shortcutTarget.mWord),
|
|
||||||
shortcutTarget.getProbability());
|
|
||||||
shortcutTargets.remove(shortcutTarget.mWord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testAddManyShortcuts() {
|
|
||||||
for (final int formatVersion : DICT_FORMAT_VERSIONS) {
|
|
||||||
testAddManyShortcuts(formatVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testAddManyShortcuts(final int formatVersion) {
|
|
||||||
final long seed = System.currentTimeMillis();
|
|
||||||
final Random random = new Random(seed);
|
|
||||||
final int UNIGRAM_COUNT = 1000;
|
|
||||||
final int SHORTCUT_COUNT = 10000;
|
|
||||||
final int codePointSetSize = 20;
|
|
||||||
final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
|
|
||||||
|
|
||||||
final ArrayList<String> words = new ArrayList<>();
|
|
||||||
final HashMap<String, Integer> unigramProbabilities = new HashMap<>();
|
|
||||||
final HashMap<String, HashMap<String, Integer>> shortcutTargets = new HashMap<>();
|
|
||||||
final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion);
|
|
||||||
|
|
||||||
for (int i = 0; i < UNIGRAM_COUNT; i++) {
|
|
||||||
final String word = CodePointUtils.generateWord(random, codePointSet);
|
|
||||||
final int unigramProbability = random.nextInt(0xFF);
|
|
||||||
addUnigramWord(binaryDictionary, word, unigramProbability);
|
|
||||||
words.add(word);
|
|
||||||
unigramProbabilities.put(word, unigramProbability);
|
|
||||||
if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) {
|
|
||||||
binaryDictionary.flushWithGC();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < SHORTCUT_COUNT; i++) {
|
|
||||||
final String shortcutTarget = CodePointUtils.generateWord(random, codePointSet);
|
|
||||||
final int shortcutProbability = random.nextInt(0xF);
|
|
||||||
final String word = words.get(random.nextInt(words.size()));
|
|
||||||
final int unigramProbability = unigramProbabilities.get(word);
|
|
||||||
binaryDictionary.addUnigramEntry(word, unigramProbability, shortcutTarget,
|
|
||||||
shortcutProbability, false /* isBeginningOfSentence */, false /* isNotAWord */,
|
|
||||||
false /* isPossiblyOffensive */, 0 /* timestamp */);
|
|
||||||
if (shortcutTargets.containsKey(word)) {
|
|
||||||
final HashMap<String, Integer> shortcutTargetsOfWord = shortcutTargets.get(word);
|
|
||||||
shortcutTargetsOfWord.put(shortcutTarget, shortcutProbability);
|
|
||||||
} else {
|
|
||||||
final HashMap<String, Integer> shortcutTargetsOfWord = new HashMap<>();
|
|
||||||
shortcutTargetsOfWord.put(shortcutTarget, shortcutProbability);
|
|
||||||
shortcutTargets.put(word, shortcutTargetsOfWord);
|
|
||||||
}
|
|
||||||
if (binaryDictionary.needsToRunGC(true /* mindsBlockByGC */)) {
|
|
||||||
binaryDictionary.flushWithGC();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final String word : words) {
|
|
||||||
final WordProperty wordProperty = binaryDictionary.getWordProperty(word,
|
|
||||||
false /* isBeginningOfSentence */);
|
|
||||||
assertEquals((int)unigramProbabilities.get(word),
|
|
||||||
wordProperty.mProbabilityInfo.mProbability);
|
|
||||||
if (!shortcutTargets.containsKey(word)) {
|
|
||||||
// The word does not have shortcut targets.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
assertEquals(shortcutTargets.get(word).size(), wordProperty.mShortcutTargets.size());
|
|
||||||
for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
final String targetCodePonts = shortcutTarget.mWord;
|
|
||||||
assertEquals((int)shortcutTargets.get(word).get(targetCodePonts),
|
|
||||||
shortcutTarget.getProbability());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testPossiblyOffensiveAttributeMaintained() {
|
public void testPossiblyOffensiveAttributeMaintained() {
|
||||||
final BinaryDictionary binaryDictionary =
|
final BinaryDictionary binaryDictionary =
|
||||||
getEmptyBinaryDictionary(FormatSpec.VERSION403);
|
getEmptyBinaryDictionary(FormatSpec.VERSION403);
|
||||||
binaryDictionary.addUnigramEntry("ddd", 100, null, Dictionary.NOT_A_PROBABILITY,
|
binaryDictionary.addUnigramEntry("ddd", 100, false, true, true, 0);
|
||||||
false, true, true, 0);
|
|
||||||
WordProperty wordProperty = binaryDictionary.getWordProperty("ddd", false);
|
WordProperty wordProperty = binaryDictionary.getWordProperty("ddd", false);
|
||||||
assertEquals(true, wordProperty.mIsPossiblyOffensive);
|
assertEquals(true, wordProperty.mIsPossiblyOffensive);
|
||||||
}
|
}
|
||||||
|
@ -1184,11 +1052,11 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
final int bigramProbability = 150;
|
final int bigramProbability = 150;
|
||||||
addBigramWords(binaryDictionary, "aaa", "bbb", bigramProbability);
|
addBigramWords(binaryDictionary, "aaa", "bbb", bigramProbability);
|
||||||
final int shortcutProbability = 10;
|
final int shortcutProbability = 10;
|
||||||
binaryDictionary.addUnigramEntry("ccc", unigramProbability, "xxx", shortcutProbability,
|
binaryDictionary.addUnigramEntry("ccc", unigramProbability,
|
||||||
false /* isBeginningOfSentence */, false /* isNotAWord */,
|
false /* isBeginningOfSentence */, false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */, 0 /* timestamp */);
|
false /* isPossiblyOffensive */, 0 /* timestamp */);
|
||||||
binaryDictionary.addUnigramEntry("ddd", unigramProbability, null /* shortcutTarget */,
|
binaryDictionary.addUnigramEntry("ddd", unigramProbability,
|
||||||
Dictionary.NOT_A_PROBABILITY, false /* isBeginningOfSentence */,
|
false /* isBeginningOfSentence */,
|
||||||
true /* isNotAWord */, true /* isPossiblyOffensive */, 0 /* timestamp */);
|
true /* isNotAWord */, true /* isPossiblyOffensive */, 0 /* timestamp */);
|
||||||
binaryDictionary.addNgramEntry(NgramContext.BEGINNING_OF_SENTENCE,
|
binaryDictionary.addNgramEntry(NgramContext.BEGINNING_OF_SENTENCE,
|
||||||
"aaa", bigramProbability, 0 /* timestamp */);
|
"aaa", bigramProbability, 0 /* timestamp */);
|
||||||
|
@ -1207,8 +1075,6 @@ public class BinaryDictionaryTests extends AndroidTestCase {
|
||||||
assertTrue(isValidBigram(binaryDictionary, "aaa", "bbb"));
|
assertTrue(isValidBigram(binaryDictionary, "aaa", "bbb"));
|
||||||
WordProperty wordProperty = binaryDictionary.getWordProperty("ccc",
|
WordProperty wordProperty = binaryDictionary.getWordProperty("ccc",
|
||||||
false /* isBeginningOfSentence */);
|
false /* isBeginningOfSentence */);
|
||||||
assertEquals(1, wordProperty.mShortcutTargets.size());
|
|
||||||
assertEquals("xxx", wordProperty.mShortcutTargets.get(0).mWord);
|
|
||||||
wordProperty = binaryDictionary.getWordProperty("ddd",
|
wordProperty = binaryDictionary.getWordProperty("ddd",
|
||||||
false /* isBeginningOfSentence */);
|
false /* isBeginningOfSentence */);
|
||||||
assertTrue(wordProperty.mIsPossiblyOffensive);
|
assertTrue(wordProperty.mIsPossiblyOffensive);
|
||||||
|
|
|
@ -35,19 +35,19 @@ public class FusionDictionaryTests extends AndroidTestCase {
|
||||||
FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
||||||
new DictionaryOptions(new HashMap<String,String>()));
|
new DictionaryOptions(new HashMap<String,String>()));
|
||||||
|
|
||||||
dict.add("abc", new ProbabilityInfo(10), null, false /* isNotAWord */,
|
dict.add("abc", new ProbabilityInfo(10), false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
|
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
|
||||||
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "abc"));
|
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "abc"));
|
||||||
|
|
||||||
dict.add("aa", new ProbabilityInfo(10), null, false /* isNotAWord */,
|
dict.add("aa", new ProbabilityInfo(10), false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
|
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
|
||||||
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aa"));
|
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aa"));
|
||||||
|
|
||||||
dict.add("babcd", new ProbabilityInfo(10), null, false /* isNotAWord */,
|
dict.add("babcd", new ProbabilityInfo(10), false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
dict.add("bacde", new ProbabilityInfo(10), null, false /* isNotAWord */,
|
dict.add("bacde", new ProbabilityInfo(10), false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba"));
|
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba"));
|
||||||
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd"));
|
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd"));
|
||||||
|
|
|
@ -57,15 +57,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
private static final int UNIGRAM_FREQ = 10;
|
private static final int UNIGRAM_FREQ = 10;
|
||||||
private static final int BIGRAM_FREQ = 50;
|
private static final int BIGRAM_FREQ = 50;
|
||||||
private static final int TOLERANCE_OF_BIGRAM_FREQ = 5;
|
private static final int TOLERANCE_OF_BIGRAM_FREQ = 5;
|
||||||
private static final int NUM_OF_NODES_HAVING_SHORTCUTS = 50;
|
|
||||||
private static final int NUM_OF_SHORTCUTS = 5;
|
|
||||||
|
|
||||||
private static final ArrayList<String> sWords = new ArrayList<>();
|
private static final ArrayList<String> sWords = new ArrayList<>();
|
||||||
private static final ArrayList<String> sWordsWithVariousCodePoints = new ArrayList<>();
|
private static final ArrayList<String> sWordsWithVariousCodePoints = new ArrayList<>();
|
||||||
private static final SparseArray<List<Integer>> sEmptyBigrams = new SparseArray<>();
|
private static final SparseArray<List<Integer>> sEmptyBigrams = new SparseArray<>();
|
||||||
private static final SparseArray<List<Integer>> sStarBigrams = new SparseArray<>();
|
private static final SparseArray<List<Integer>> sStarBigrams = new SparseArray<>();
|
||||||
private static final SparseArray<List<Integer>> sChainBigrams = new SparseArray<>();
|
private static final SparseArray<List<Integer>> sChainBigrams = new SparseArray<>();
|
||||||
private static final HashMap<String, List<String>> sShortcuts = new HashMap<>();
|
|
||||||
|
|
||||||
final Random mRandom;
|
final Random mRandom;
|
||||||
|
|
||||||
|
@ -95,16 +92,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
for (int i = 1; i < maxBigrams; ++i) {
|
for (int i = 1; i < maxBigrams; ++i) {
|
||||||
sStarBigrams.get(0).add(i);
|
sStarBigrams.get(0).add(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
sShortcuts.clear();
|
|
||||||
for (int i = 0; i < NUM_OF_NODES_HAVING_SHORTCUTS; ++i) {
|
|
||||||
final int from = Math.abs(mRandom.nextInt()) % sWords.size();
|
|
||||||
sShortcuts.put(sWords.get(from), new ArrayList<String>());
|
|
||||||
for (int j = 0; j < NUM_OF_SHORTCUTS; ++j) {
|
|
||||||
final int to = Math.abs(mRandom.nextInt()) % sWords.size();
|
|
||||||
sShortcuts.get(sWords.get(from)).add(sWords.get(to));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -142,17 +129,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
* Adds unigrams to the dictionary.
|
* Adds unigrams to the dictionary.
|
||||||
*/
|
*/
|
||||||
private static void addUnigrams(final int number, final FusionDictionary dict,
|
private static void addUnigrams(final int number, final FusionDictionary dict,
|
||||||
final List<String> words, final HashMap<String, List<String>> shortcutMap) {
|
final List<String> words) {
|
||||||
for (int i = 0; i < number; ++i) {
|
for (int i = 0; i < number; ++i) {
|
||||||
final String word = words.get(i);
|
final String word = words.get(i);
|
||||||
final ArrayList<WeightedString> shortcuts = new ArrayList<>();
|
final ArrayList<WeightedString> shortcuts = new ArrayList<>();
|
||||||
if (shortcutMap != null && shortcutMap.containsKey(word)) {
|
dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ), false /* isNotAWord */,
|
||||||
for (final String shortcut : shortcutMap.get(word)) {
|
|
||||||
shortcuts.add(new WeightedString(shortcut, UNIGRAM_FREQ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ),
|
|
||||||
(shortcutMap == null) ? null : shortcuts, false /* isNotAWord */,
|
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,8 +181,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkDictionary(final FusionDictionary dict, final List<String> words,
|
private static void checkDictionary(final FusionDictionary dict, final List<String> words,
|
||||||
final SparseArray<List<Integer>> bigrams,
|
final SparseArray<List<Integer>> bigrams) {
|
||||||
final HashMap<String, List<String>> shortcutMap) {
|
|
||||||
assertNotNull(dict);
|
assertNotNull(dict);
|
||||||
|
|
||||||
// check unigram
|
// check unigram
|
||||||
|
@ -219,19 +199,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
assertNotNull(words.get(w1) + "," + words.get(w2), ptNode.getBigram(words.get(w2)));
|
assertNotNull(words.get(w1) + "," + words.get(w2), ptNode.getBigram(words.get(w2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check shortcut
|
|
||||||
if (shortcutMap != null) {
|
|
||||||
for (final Entry<String, List<String>> entry : shortcutMap.entrySet()) {
|
|
||||||
assertTrue(words.contains(entry.getKey()));
|
|
||||||
final PtNode ptNode = FusionDictionary.findWordInTree(dict.mRootNodeArray,
|
|
||||||
entry.getKey());
|
|
||||||
for (final String word : entry.getValue()) {
|
|
||||||
assertNotNull("shortcut not found: " + entry.getKey() + ", " + word,
|
|
||||||
ptNode.getShortcut(word));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String outputOptions(final int bufferType,
|
private static String outputOptions(final int bufferType,
|
||||||
|
@ -244,8 +211,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
// Tests for readDictionaryBinary and writeDictionaryBinary
|
// Tests for readDictionaryBinary and writeDictionaryBinary
|
||||||
|
|
||||||
private static long timeReadingAndCheckDict(final File file, final List<String> words,
|
private static long timeReadingAndCheckDict(final File file, final List<String> words,
|
||||||
final SparseArray<List<Integer>> bigrams,
|
final SparseArray<List<Integer>> bigrams, final int bufferType) {
|
||||||
final HashMap<String, List<String>> shortcutMap, final int bufferType) {
|
|
||||||
long now, diff = -1;
|
long now, diff = -1;
|
||||||
|
|
||||||
FusionDictionary dict = null;
|
FusionDictionary dict = null;
|
||||||
|
@ -261,13 +227,13 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
Log.e(TAG, "Unsupported format", e);
|
Log.e(TAG, "Unsupported format", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkDictionary(dict, words, bigrams, shortcutMap);
|
checkDictionary(dict, words, bigrams);
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests for readDictionaryBinary and writeDictionaryBinary
|
// Tests for readDictionaryBinary and writeDictionaryBinary
|
||||||
private String runReadAndWrite(final List<String> words,
|
private String runReadAndWrite(final List<String> words,
|
||||||
final SparseArray<List<Integer>> bigrams, final HashMap<String, List<String>> shortcuts,
|
final SparseArray<List<Integer>> bigrams,
|
||||||
final int bufferType, final FormatSpec.FormatOptions formatOptions,
|
final int bufferType, final FormatSpec.FormatOptions formatOptions,
|
||||||
final String message) {
|
final String message) {
|
||||||
|
|
||||||
|
@ -278,12 +244,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
|
|
||||||
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(words.size(), dict, words, shortcuts);
|
addUnigrams(words.size(), dict, words);
|
||||||
addBigrams(dict, words, bigrams);
|
addBigrams(dict, words, bigrams);
|
||||||
checkDictionary(dict, words, bigrams, shortcuts);
|
checkDictionary(dict, words, bigrams);
|
||||||
|
|
||||||
final long write = timeWritingDictToFile(file, dict, formatOptions);
|
final long write = timeWritingDictToFile(file, dict, formatOptions);
|
||||||
final long read = timeReadingAndCheckDict(file, words, bigrams, shortcuts, bufferType);
|
final long read = timeReadingAndCheckDict(file, words, bigrams, bufferType);
|
||||||
|
|
||||||
return "PROF: read=" + read + "ms, write=" + write + "ms :" + message
|
return "PROF: read=" + read + "ms, write=" + write + "ms :" + message
|
||||||
+ " : " + outputOptions(bufferType, formatOptions);
|
+ " : " + outputOptions(bufferType, formatOptions);
|
||||||
|
@ -291,20 +257,20 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
|
|
||||||
private void runReadAndWriteTests(final List<String> results, final int bufferType,
|
private void runReadAndWriteTests(final List<String> results, final int bufferType,
|
||||||
final FormatSpec.FormatOptions formatOptions) {
|
final FormatSpec.FormatOptions formatOptions) {
|
||||||
results.add(runReadAndWrite(sWords, sEmptyBigrams, null /* shortcuts */, bufferType,
|
results.add(runReadAndWrite(sWords, sEmptyBigrams, bufferType,
|
||||||
formatOptions, "unigram"));
|
formatOptions, "unigram"));
|
||||||
results.add(runReadAndWrite(sWords, sChainBigrams, null /* shortcuts */, bufferType,
|
results.add(runReadAndWrite(sWords, sChainBigrams, bufferType,
|
||||||
formatOptions, "chain"));
|
formatOptions, "chain"));
|
||||||
results.add(runReadAndWrite(sWords, sStarBigrams, null /* shortcuts */, bufferType,
|
results.add(runReadAndWrite(sWords, sStarBigrams, bufferType,
|
||||||
formatOptions, "star"));
|
formatOptions, "star"));
|
||||||
results.add(runReadAndWrite(sWords, sEmptyBigrams, sShortcuts, bufferType, formatOptions,
|
results.add(runReadAndWrite(sWords, sEmptyBigrams, bufferType, formatOptions,
|
||||||
"unigram with shortcuts"));
|
"unigram with shortcuts"));
|
||||||
results.add(runReadAndWrite(sWords, sChainBigrams, sShortcuts, bufferType, formatOptions,
|
results.add(runReadAndWrite(sWords, sChainBigrams, bufferType, formatOptions,
|
||||||
"chain with shortcuts"));
|
"chain with shortcuts"));
|
||||||
results.add(runReadAndWrite(sWords, sStarBigrams, sShortcuts, bufferType, formatOptions,
|
results.add(runReadAndWrite(sWords, sStarBigrams, bufferType, formatOptions,
|
||||||
"star with shortcuts"));
|
"star with shortcuts"));
|
||||||
results.add(runReadAndWrite(sWordsWithVariousCodePoints, sEmptyBigrams,
|
results.add(runReadAndWrite(sWordsWithVariousCodePoints, sEmptyBigrams,
|
||||||
null /* shortcuts */, bufferType, formatOptions,
|
bufferType, formatOptions,
|
||||||
"unigram with various code points"));
|
"unigram with various code points"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +292,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
FormatSpec.MINIMUM_SUPPORTED_STATIC_VERSION);
|
FormatSpec.MINIMUM_SUPPORTED_STATIC_VERSION);
|
||||||
final FusionDictionary sourcedict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary sourcedict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(words.size(), sourcedict, words, null /* shortcutMap */);
|
addUnigrams(words.size(), sourcedict, words);
|
||||||
dictEncoder.writeDictionary(sourcedict, formatOptions);
|
dictEncoder.writeDictionary(sourcedict, formatOptions);
|
||||||
|
|
||||||
// Read the dictionary
|
// Read the dictionary
|
||||||
|
@ -472,7 +438,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
// making the dictionary from lists of words.
|
// making the dictionary from lists of words.
|
||||||
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(words.size(), dict, words, null /* shortcutMap */);
|
addUnigrams(words.size(), dict, words);
|
||||||
addBigrams(dict, words, bigrams);
|
addBigrams(dict, words, bigrams);
|
||||||
|
|
||||||
timeWritingDictToFile(file, dict, formatOptions);
|
timeWritingDictToFile(file, dict, formatOptions);
|
||||||
|
@ -482,7 +448,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
// TODO: Abandon the Java code, and implement the v4 dictionary reading code in native.
|
// TODO: Abandon the Java code, and implement the v4 dictionary reading code in native.
|
||||||
long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType,
|
long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType,
|
||||||
!formatOptions.mHasTimestamp /* checkProbability */);
|
!formatOptions.mHasTimestamp /* checkProbability */);
|
||||||
long fullReading = timeReadingAndCheckDict(file, words, bigrams, null /* shortcutMap */,
|
long fullReading = timeReadingAndCheckDict(file, words, bigrams,
|
||||||
bufferType);
|
bufferType);
|
||||||
|
|
||||||
return "readDictionaryBinary=" + fullReading + ", readUnigramsAndBigramsBinary=" + wordMap
|
return "readDictionaryBinary=" + fullReading + ", readUnigramsAndBigramsBinary=" + wordMap
|
||||||
|
@ -567,7 +533,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
|
|
||||||
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */);
|
addUnigrams(sWords.size(), dict, sWords);
|
||||||
addBigrams(dict, words, bigrams);
|
addBigrams(dict, words, bigrams);
|
||||||
timeWritingDictToFile(file, dict, formatOptions);
|
timeWritingDictToFile(file, dict, formatOptions);
|
||||||
|
|
||||||
|
@ -636,12 +602,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
public void testVer2DictGetWordProperty() {
|
public void testVer2DictGetWordProperty() {
|
||||||
final FormatOptions formatOptions = BinaryDictUtils.STATIC_OPTIONS;
|
final FormatOptions formatOptions = BinaryDictUtils.STATIC_OPTIONS;
|
||||||
final ArrayList<String> words = sWords;
|
final ArrayList<String> words = sWords;
|
||||||
final HashMap<String, List<String>> shortcuts = sShortcuts;
|
|
||||||
final String dictName = "testGetWordProperty";
|
final String dictName = "testGetWordProperty";
|
||||||
final String dictVersion = Long.toString(System.currentTimeMillis());
|
final String dictVersion = Long.toString(System.currentTimeMillis());
|
||||||
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(words.size(), dict, words, shortcuts);
|
addUnigrams(words.size(), dict, words);
|
||||||
addBigrams(dict, words, sEmptyBigrams);
|
addBigrams(dict, words, sEmptyBigrams);
|
||||||
final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions,
|
final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions,
|
||||||
getContext().getCacheDir());
|
getContext().getCacheDir());
|
||||||
|
@ -655,30 +620,18 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
false /* isBeginningOfSentence */);
|
false /* isBeginningOfSentence */);
|
||||||
assertEquals(word, wordProperty.mWord);
|
assertEquals(word, wordProperty.mWord);
|
||||||
assertEquals(UNIGRAM_FREQ, wordProperty.getProbability());
|
assertEquals(UNIGRAM_FREQ, wordProperty.getProbability());
|
||||||
if (shortcuts.containsKey(word)) {
|
|
||||||
assertEquals(shortcuts.get(word).size(), wordProperty.mShortcutTargets.size());
|
|
||||||
final List<String> shortcutList = shortcuts.get(word);
|
|
||||||
assertTrue(wordProperty.mHasShortcuts);
|
|
||||||
for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
assertTrue(shortcutList.contains(shortcutTarget.mWord));
|
|
||||||
assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability());
|
|
||||||
shortcutList.remove(shortcutTarget.mWord);
|
|
||||||
}
|
|
||||||
assertTrue(shortcutList.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testVer2DictIteration() {
|
public void testVer2DictIteration() {
|
||||||
final FormatOptions formatOptions = BinaryDictUtils.STATIC_OPTIONS;
|
final FormatOptions formatOptions = BinaryDictUtils.STATIC_OPTIONS;
|
||||||
final ArrayList<String> words = sWords;
|
final ArrayList<String> words = sWords;
|
||||||
final HashMap<String, List<String>> shortcuts = sShortcuts;
|
|
||||||
final SparseArray<List<Integer>> bigrams = sEmptyBigrams;
|
final SparseArray<List<Integer>> bigrams = sEmptyBigrams;
|
||||||
final String dictName = "testGetWordProperty";
|
final String dictName = "testGetWordProperty";
|
||||||
final String dictVersion = Long.toString(System.currentTimeMillis());
|
final String dictVersion = Long.toString(System.currentTimeMillis());
|
||||||
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(words.size(), dict, words, shortcuts);
|
addUnigrams(words.size(), dict, words);
|
||||||
addBigrams(dict, words, bigrams);
|
addBigrams(dict, words, bigrams);
|
||||||
final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions,
|
final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions,
|
||||||
getContext().getCacheDir());
|
getContext().getCacheDir());
|
||||||
|
@ -708,17 +661,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
final String word0 = wordProperty.mWord;
|
final String word0 = wordProperty.mWord;
|
||||||
assertEquals(UNIGRAM_FREQ, wordProperty.mProbabilityInfo.mProbability);
|
assertEquals(UNIGRAM_FREQ, wordProperty.mProbabilityInfo.mProbability);
|
||||||
wordSet.remove(word0);
|
wordSet.remove(word0);
|
||||||
if (shortcuts.containsKey(word0)) {
|
|
||||||
assertEquals(shortcuts.get(word0).size(), wordProperty.mShortcutTargets.size());
|
|
||||||
final List<String> shortcutList = shortcuts.get(word0);
|
|
||||||
assertNotNull(wordProperty.mShortcutTargets);
|
|
||||||
for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
assertTrue(shortcutList.contains(shortcutTarget.mWord));
|
|
||||||
assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability());
|
|
||||||
shortcutList.remove(shortcutTarget.mWord);
|
|
||||||
}
|
|
||||||
assertTrue(shortcutList.isEmpty());
|
|
||||||
}
|
|
||||||
if (wordProperty.mHasNgrams) {
|
if (wordProperty.mHasNgrams) {
|
||||||
for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
|
for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
|
||||||
final String word1 = bigramTarget.mWord;
|
final String word1 = bigramTarget.mWord;
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin.makedict;
|
package com.android.inputmethod.latin.makedict;
|
||||||
|
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
|
||||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
|
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
|
||||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
|
||||||
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
|
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
|
||||||
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
|
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
|
||||||
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
|
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
|
||||||
|
@ -91,38 +89,6 @@ public class BinaryDictEncoderUtils {
|
||||||
return BinaryDictIOUtils.getPtNodeCountSize(nodeArray.mData.size());
|
return BinaryDictIOUtils.getPtNodeCountSize(nodeArray.mData.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the size of a shortcut in bytes.
|
|
||||||
*/
|
|
||||||
private static int getShortcutSize(final WeightedString shortcut,
|
|
||||||
final HashMap<Integer, Integer> codePointToOneByteCodeMap) {
|
|
||||||
int size = FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE;
|
|
||||||
final String word = shortcut.mWord;
|
|
||||||
final int length = word.length();
|
|
||||||
for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
|
|
||||||
final int codePoint = word.codePointAt(i);
|
|
||||||
size += CharEncoding.getCharSize(codePoint, codePointToOneByteCodeMap);
|
|
||||||
}
|
|
||||||
size += FormatSpec.PTNODE_TERMINATOR_SIZE;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the size of a shortcut list in bytes.
|
|
||||||
*
|
|
||||||
* This is known in advance and does not change according to position in the file
|
|
||||||
* like address lists do.
|
|
||||||
*/
|
|
||||||
static int getShortcutListSize(final ArrayList<WeightedString> shortcutList,
|
|
||||||
final HashMap<Integer, Integer> codePointToOneByteCodeMap) {
|
|
||||||
if (null == shortcutList || shortcutList.isEmpty()) return 0;
|
|
||||||
int size = FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE;
|
|
||||||
for (final WeightedString shortcut : shortcutList) {
|
|
||||||
size += getShortcutSize(shortcut, codePointToOneByteCodeMap);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the maximum size of a PtNode, assuming 3-byte addresses for everything.
|
* Compute the maximum size of a PtNode, assuming 3-byte addresses for everything.
|
||||||
*
|
*
|
||||||
|
@ -137,8 +103,6 @@ public class BinaryDictEncoderUtils {
|
||||||
size += FormatSpec.PTNODE_FREQUENCY_SIZE;
|
size += FormatSpec.PTNODE_FREQUENCY_SIZE;
|
||||||
}
|
}
|
||||||
size += FormatSpec.PTNODE_MAX_ADDRESS_SIZE; // For children address
|
size += FormatSpec.PTNODE_MAX_ADDRESS_SIZE; // For children address
|
||||||
// TODO: Use codePointToOneByteCodeMap for shortcuts.
|
|
||||||
size += getShortcutListSize(ptNode.mShortcutTargets, null /* codePointToOneByteCodeMap */);
|
|
||||||
if (null != ptNode.mBigrams) {
|
if (null != ptNode.mBigrams) {
|
||||||
size += (FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE
|
size += (FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE
|
||||||
+ FormatSpec.PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE)
|
+ FormatSpec.PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE)
|
||||||
|
@ -241,27 +205,6 @@ public class BinaryDictEncoderUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedForTesting
|
|
||||||
static void writeUIntToDictBuffer(final DictBuffer dictBuffer, final int value,
|
|
||||||
final int size) {
|
|
||||||
switch(size) {
|
|
||||||
case 4:
|
|
||||||
dictBuffer.put((byte) ((value >> 24) & 0xFF));
|
|
||||||
/* fall through */
|
|
||||||
case 3:
|
|
||||||
dictBuffer.put((byte) ((value >> 16) & 0xFF));
|
|
||||||
/* fall through */
|
|
||||||
case 2:
|
|
||||||
dictBuffer.put((byte) ((value >> 8) & 0xFF));
|
|
||||||
/* fall through */
|
|
||||||
case 1:
|
|
||||||
dictBuffer.put((byte) (value & 0xFF));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* nop */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End utility methods
|
// End utility methods
|
||||||
|
|
||||||
// This method is responsible for finding a nice ordering of the nodes that favors run-time
|
// This method is responsible for finding a nice ordering of the nodes that favors run-time
|
||||||
|
@ -391,9 +334,6 @@ public class BinaryDictEncoderUtils {
|
||||||
nodeSize += getByteSize(getOffsetToTargetNodeArrayDuringUpdate(ptNodeArray,
|
nodeSize += getByteSize(getOffsetToTargetNodeArrayDuringUpdate(ptNodeArray,
|
||||||
nodeSize + size, ptNode.mChildren));
|
nodeSize + size, ptNode.mChildren));
|
||||||
}
|
}
|
||||||
// TODO: Use codePointToOneByteCodeMap for shortcuts.
|
|
||||||
nodeSize += getShortcutListSize(ptNode.mShortcutTargets,
|
|
||||||
null /* codePointToOneByteCodeMap */);
|
|
||||||
if (null != ptNode.mBigrams) {
|
if (null != ptNode.mBigrams) {
|
||||||
for (WeightedString bigram : ptNode.mBigrams) {
|
for (WeightedString bigram : ptNode.mBigrams) {
|
||||||
final int offset = getOffsetToTargetPtNodeDuringUpdate(ptNodeArray,
|
final int offset = getOffsetToTargetPtNodeDuringUpdate(ptNodeArray,
|
||||||
|
@ -568,14 +508,13 @@ public class BinaryDictEncoderUtils {
|
||||||
* @param hasMultipleChars whether the PtNode has multiple chars.
|
* @param hasMultipleChars whether the PtNode has multiple chars.
|
||||||
* @param isTerminal whether the PtNode is terminal.
|
* @param isTerminal whether the PtNode is terminal.
|
||||||
* @param childrenAddressSize the size of a children address.
|
* @param childrenAddressSize the size of a children address.
|
||||||
* @param hasShortcuts whether the PtNode has shortcuts.
|
|
||||||
* @param hasBigrams whether the PtNode has bigrams.
|
* @param hasBigrams whether the PtNode has bigrams.
|
||||||
* @param isNotAWord whether the PtNode is not a word.
|
* @param isNotAWord whether the PtNode is not a word.
|
||||||
* @param isPossiblyOffensive whether the PtNode is a possibly offensive entry.
|
* @param isPossiblyOffensive whether the PtNode is a possibly offensive entry.
|
||||||
* @return the flags
|
* @return the flags
|
||||||
*/
|
*/
|
||||||
static int makePtNodeFlags(final boolean hasMultipleChars, final boolean isTerminal,
|
static int makePtNodeFlags(final boolean hasMultipleChars, final boolean isTerminal,
|
||||||
final int childrenAddressSize, final boolean hasShortcuts, final boolean hasBigrams,
|
final int childrenAddressSize, final boolean hasBigrams,
|
||||||
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
||||||
byte flags = 0;
|
byte flags = 0;
|
||||||
if (hasMultipleChars) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS;
|
if (hasMultipleChars) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS;
|
||||||
|
@ -596,7 +535,6 @@ public class BinaryDictEncoderUtils {
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Node with a strange address");
|
throw new RuntimeException("Node with a strange address");
|
||||||
}
|
}
|
||||||
if (hasShortcuts) flags |= FormatSpec.FLAG_HAS_SHORTCUT_TARGETS;
|
|
||||||
if (hasBigrams) flags |= FormatSpec.FLAG_HAS_BIGRAMS;
|
if (hasBigrams) flags |= FormatSpec.FLAG_HAS_BIGRAMS;
|
||||||
if (isNotAWord) flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
|
if (isNotAWord) flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
|
||||||
if (isPossiblyOffensive) flags |= FormatSpec.FLAG_IS_POSSIBLY_OFFENSIVE;
|
if (isPossiblyOffensive) flags |= FormatSpec.FLAG_IS_POSSIBLY_OFFENSIVE;
|
||||||
|
@ -606,7 +544,6 @@ public class BinaryDictEncoderUtils {
|
||||||
/* package */ static byte makePtNodeFlags(final PtNode node, final int childrenOffset) {
|
/* package */ static byte makePtNodeFlags(final PtNode node, final int childrenOffset) {
|
||||||
return (byte) makePtNodeFlags(node.mChars.length > 1, node.isTerminal(),
|
return (byte) makePtNodeFlags(node.mChars.length > 1, node.isTerminal(),
|
||||||
getByteSize(childrenOffset),
|
getByteSize(childrenOffset),
|
||||||
node.mShortcutTargets != null && !node.mShortcutTargets.isEmpty(),
|
|
||||||
node.mBigrams != null && !node.mBigrams.isEmpty(),
|
node.mBigrams != null && !node.mBigrams.isEmpty(),
|
||||||
node.mIsNotAWord, node.mIsPossiblyOffensive);
|
node.mIsNotAWord, node.mIsPossiblyOffensive);
|
||||||
}
|
}
|
||||||
|
@ -621,7 +558,7 @@ public class BinaryDictEncoderUtils {
|
||||||
* @param word the second bigram, for debugging purposes
|
* @param word the second bigram, for debugging purposes
|
||||||
* @return the flags
|
* @return the flags
|
||||||
*/
|
*/
|
||||||
/* package */ static final int makeBigramFlags(final boolean more, final int offset,
|
/* package */ static int makeBigramFlags(final boolean more, final int offset,
|
||||||
final int bigramFrequency, final int unigramFrequency, final String word) {
|
final int bigramFrequency, final int unigramFrequency, final String word) {
|
||||||
int bigramFlags = (more ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0)
|
int bigramFlags = (more ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0)
|
||||||
+ (offset < 0 ? FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE : 0);
|
+ (offset < 0 ? FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE : 0);
|
||||||
|
@ -690,19 +627,7 @@ public class BinaryDictEncoderUtils {
|
||||||
return discretizedFrequency > 0 ? discretizedFrequency : 0;
|
return discretizedFrequency > 0 ? discretizedFrequency : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* package */ static int getChildrenPosition(final PtNode ptNode,
|
||||||
* Makes the flag value for a shortcut.
|
|
||||||
*
|
|
||||||
* @param more whether there are more attributes after this one.
|
|
||||||
* @param frequency the frequency of the attribute, 0..15
|
|
||||||
* @return the flags
|
|
||||||
*/
|
|
||||||
static final int makeShortcutFlags(final boolean more, final int frequency) {
|
|
||||||
return (more ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0)
|
|
||||||
+ (frequency & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ static final int getChildrenPosition(final PtNode ptNode,
|
|
||||||
final HashMap<Integer, Integer> codePointToOneByteCodeMap) {
|
final HashMap<Integer, Integer> codePointToOneByteCodeMap) {
|
||||||
int positionOfChildrenPosField = ptNode.mCachedAddressAfterUpdate
|
int positionOfChildrenPosField = ptNode.mCachedAddressAfterUpdate
|
||||||
+ getNodeHeaderSize(ptNode, codePointToOneByteCodeMap);
|
+ getNodeHeaderSize(ptNode, codePointToOneByteCodeMap);
|
||||||
|
|
|
@ -82,7 +82,6 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
public static final class PtNode {
|
public static final class PtNode {
|
||||||
private static final int NOT_A_TERMINAL = -1;
|
private static final int NOT_A_TERMINAL = -1;
|
||||||
final int mChars[];
|
final int mChars[];
|
||||||
ArrayList<WeightedString> mShortcutTargets;
|
|
||||||
ArrayList<WeightedString> mBigrams;
|
ArrayList<WeightedString> mBigrams;
|
||||||
// null == mProbabilityInfo indicates this is not a terminal.
|
// null == mProbabilityInfo indicates this is not a terminal.
|
||||||
ProbabilityInfo mProbabilityInfo;
|
ProbabilityInfo mProbabilityInfo;
|
||||||
|
@ -100,26 +99,23 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
int mCachedAddressBeforeUpdate; // The address of this PtNode (before update)
|
int mCachedAddressBeforeUpdate; // The address of this PtNode (before update)
|
||||||
int mCachedAddressAfterUpdate; // The address of this PtNode (after update)
|
int mCachedAddressAfterUpdate; // The address of this PtNode (after update)
|
||||||
|
|
||||||
public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
|
public PtNode(final int[] chars, final ArrayList<WeightedString> bigrams,
|
||||||
final ArrayList<WeightedString> bigrams, final ProbabilityInfo probabilityInfo,
|
final ProbabilityInfo probabilityInfo, final boolean isNotAWord,
|
||||||
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
final boolean isPossiblyOffensive) {
|
||||||
mChars = chars;
|
mChars = chars;
|
||||||
mProbabilityInfo = probabilityInfo;
|
mProbabilityInfo = probabilityInfo;
|
||||||
mTerminalId = probabilityInfo == null ? NOT_A_TERMINAL : probabilityInfo.mProbability;
|
mTerminalId = probabilityInfo == null ? NOT_A_TERMINAL : probabilityInfo.mProbability;
|
||||||
mShortcutTargets = shortcutTargets;
|
|
||||||
mBigrams = bigrams;
|
mBigrams = bigrams;
|
||||||
mChildren = null;
|
mChildren = null;
|
||||||
mIsNotAWord = isNotAWord;
|
mIsNotAWord = isNotAWord;
|
||||||
mIsPossiblyOffensive = isPossiblyOffensive;
|
mIsPossiblyOffensive = isPossiblyOffensive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
|
public PtNode(final int[] chars, final ArrayList<WeightedString> bigrams,
|
||||||
final ArrayList<WeightedString> bigrams, final ProbabilityInfo probabilityInfo,
|
final ProbabilityInfo probabilityInfo, final boolean isNotAWord,
|
||||||
final boolean isNotAWord, final boolean isPossiblyOffensive,
|
final boolean isPossiblyOffensive, final PtNodeArray children) {
|
||||||
final PtNodeArray children) {
|
|
||||||
mChars = chars;
|
mChars = chars;
|
||||||
mProbabilityInfo = probabilityInfo;
|
mProbabilityInfo = probabilityInfo;
|
||||||
mShortcutTargets = shortcutTargets;
|
|
||||||
mBigrams = bigrams;
|
mBigrams = bigrams;
|
||||||
mChildren = children;
|
mChildren = children;
|
||||||
mIsNotAWord = isNotAWord;
|
mIsNotAWord = isNotAWord;
|
||||||
|
@ -153,14 +149,6 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
return mIsPossiblyOffensive;
|
return mIsPossiblyOffensive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<WeightedString> getShortcutTargets() {
|
|
||||||
// We don't want write permission to escape outside the package, so we return a copy
|
|
||||||
if (null == mShortcutTargets) return null;
|
|
||||||
final ArrayList<WeightedString> copyOfShortcutTargets =
|
|
||||||
new ArrayList<>(mShortcutTargets);
|
|
||||||
return copyOfShortcutTargets;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<WeightedString> getBigrams() {
|
public ArrayList<WeightedString> getBigrams() {
|
||||||
// We don't want write permission to escape outside the package, so we return a copy
|
// We don't want write permission to escape outside the package, so we return a copy
|
||||||
if (null == mBigrams) return null;
|
if (null == mBigrams) return null;
|
||||||
|
@ -190,24 +178,6 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the shortcut target for the given word. Returns null if the word is not in the
|
|
||||||
* shortcut list.
|
|
||||||
*/
|
|
||||||
public WeightedString getShortcut(final String word) {
|
|
||||||
// TODO: Don't do a linear search
|
|
||||||
if (mShortcutTargets != null) {
|
|
||||||
final int size = mShortcutTargets.size();
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
WeightedString shortcut = mShortcutTargets.get(i);
|
|
||||||
if (shortcut.mWord.equals(word)) {
|
|
||||||
return shortcut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the bigram for the given word.
|
* Gets the bigram for the given word.
|
||||||
* Returns null if the word is not in the bigrams list.
|
* Returns null if the word is not in the bigrams list.
|
||||||
|
@ -232,27 +202,9 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
* updated if they are higher than the existing ones.
|
* updated if they are higher than the existing ones.
|
||||||
*/
|
*/
|
||||||
void update(final ProbabilityInfo probabilityInfo,
|
void update(final ProbabilityInfo probabilityInfo,
|
||||||
final ArrayList<WeightedString> shortcutTargets,
|
|
||||||
final ArrayList<WeightedString> bigrams,
|
final ArrayList<WeightedString> bigrams,
|
||||||
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
||||||
mProbabilityInfo = ProbabilityInfo.max(mProbabilityInfo, probabilityInfo);
|
mProbabilityInfo = ProbabilityInfo.max(mProbabilityInfo, probabilityInfo);
|
||||||
if (shortcutTargets != null) {
|
|
||||||
if (mShortcutTargets == null) {
|
|
||||||
mShortcutTargets = shortcutTargets;
|
|
||||||
} else {
|
|
||||||
final int size = shortcutTargets.size();
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
final WeightedString shortcut = shortcutTargets.get(i);
|
|
||||||
final WeightedString existingShortcut = getShortcut(shortcut.mWord);
|
|
||||||
if (existingShortcut == null) {
|
|
||||||
mShortcutTargets.add(shortcut);
|
|
||||||
} else {
|
|
||||||
existingShortcut.mProbabilityInfo = ProbabilityInfo.max(
|
|
||||||
existingShortcut.mProbabilityInfo, shortcut.mProbabilityInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (bigrams != null) {
|
if (bigrams != null) {
|
||||||
if (mBigrams == null) {
|
if (mBigrams == null) {
|
||||||
mBigrams = bigrams;
|
mBigrams = bigrams;
|
||||||
|
@ -312,19 +264,16 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
* Helper method to add a word as a string.
|
* Helper method to add a word as a string.
|
||||||
*
|
*
|
||||||
* This method adds a word to the dictionary with the given frequency. Optional
|
* This method adds a word to the dictionary with the given frequency. Optional
|
||||||
* lists of bigrams and shortcuts can be passed here. For each word inside,
|
* lists of bigrams can be passed here. For each word inside,
|
||||||
* they will be added to the dictionary as necessary.
|
* they will be added to the dictionary as necessary.
|
||||||
*
|
* @param word the word to add.
|
||||||
* @param word the word to add.
|
|
||||||
* @param probabilityInfo probability information of the word.
|
* @param probabilityInfo probability information of the word.
|
||||||
* @param shortcutTargets a list of shortcut targets for this word, or null.
|
|
||||||
* @param isNotAWord true if this should not be considered a word (e.g. shortcut only)
|
* @param isNotAWord true if this should not be considered a word (e.g. shortcut only)
|
||||||
* @param isPossiblyOffensive true if this word is possibly offensive
|
* @param isPossiblyOffensive true if this word is possibly offensive
|
||||||
*/
|
*/
|
||||||
public void add(final String word, final ProbabilityInfo probabilityInfo,
|
public void add(final String word, final ProbabilityInfo probabilityInfo,
|
||||||
final ArrayList<WeightedString> shortcutTargets, final boolean isNotAWord,
|
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
||||||
final boolean isPossiblyOffensive) {
|
add(getCodePoints(word), probabilityInfo, isNotAWord, isPossiblyOffensive);
|
||||||
add(getCodePoints(word), probabilityInfo, shortcutTargets, isNotAWord, isPossiblyOffensive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,7 +307,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
if (ptNode0 != null) {
|
if (ptNode0 != null) {
|
||||||
final PtNode ptNode1 = findWordInTree(mRootNodeArray, word1);
|
final PtNode ptNode1 = findWordInTree(mRootNodeArray, word1);
|
||||||
if (ptNode1 == null) {
|
if (ptNode1 == null) {
|
||||||
add(getCodePoints(word1), new ProbabilityInfo(0), null, false /* isNotAWord */,
|
add(getCodePoints(word1), new ProbabilityInfo(0), false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
// The PtNode for the first word may have moved by the above insertion,
|
// The PtNode for the first word may have moved by the above insertion,
|
||||||
// if word1 and word2 share a common stem that happens not to have been
|
// if word1 and word2 share a common stem that happens not to have been
|
||||||
|
@ -376,15 +325,12 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
*
|
*
|
||||||
* The shortcuts, if any, have to be in the dictionary already. If they aren't,
|
* The shortcuts, if any, have to be in the dictionary already. If they aren't,
|
||||||
* an exception is thrown.
|
* an exception is thrown.
|
||||||
*
|
* @param word the word, as an int array.
|
||||||
* @param word the word, as an int array.
|
|
||||||
* @param probabilityInfo the probability information of the word.
|
* @param probabilityInfo the probability information of the word.
|
||||||
* @param shortcutTargets an optional list of shortcut targets for this word (null if none).
|
|
||||||
* @param isNotAWord true if this is not a word for spellcheking purposes (shortcut only or so)
|
* @param isNotAWord true if this is not a word for spellcheking purposes (shortcut only or so)
|
||||||
* @param isPossiblyOffensive true if this word is possibly offensive
|
* @param isPossiblyOffensive true if this word is possibly offensive
|
||||||
*/
|
*/
|
||||||
private void add(final int[] word, final ProbabilityInfo probabilityInfo,
|
private void add(final int[] word, final ProbabilityInfo probabilityInfo,
|
||||||
final ArrayList<WeightedString> shortcutTargets,
|
|
||||||
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
final boolean isNotAWord, final boolean isPossiblyOffensive) {
|
||||||
assert(probabilityInfo.mProbability <= FormatSpec.MAX_TERMINAL_FREQUENCY);
|
assert(probabilityInfo.mProbability <= FormatSpec.MAX_TERMINAL_FREQUENCY);
|
||||||
if (word.length >= DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH) {
|
if (word.length >= DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH) {
|
||||||
|
@ -414,7 +360,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
// No node at this point to accept the word. Create one.
|
// No node at this point to accept the word. Create one.
|
||||||
final int insertionIndex = findInsertionIndex(currentNodeArray, word[charIndex]);
|
final int insertionIndex = findInsertionIndex(currentNodeArray, word[charIndex]);
|
||||||
final PtNode newPtNode = new PtNode(Arrays.copyOfRange(word, charIndex, word.length),
|
final PtNode newPtNode = new PtNode(Arrays.copyOfRange(word, charIndex, word.length),
|
||||||
shortcutTargets, null /* bigrams */, probabilityInfo, isNotAWord,
|
null /* bigrams */, probabilityInfo, isNotAWord,
|
||||||
isPossiblyOffensive);
|
isPossiblyOffensive);
|
||||||
currentNodeArray.mData.add(insertionIndex, newPtNode);
|
currentNodeArray.mData.add(insertionIndex, newPtNode);
|
||||||
if (DBG) checkStack(currentNodeArray);
|
if (DBG) checkStack(currentNodeArray);
|
||||||
|
@ -425,14 +371,14 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
// The new word is a prefix of an existing word, but the node on which it
|
// The new word is a prefix of an existing word, but the node on which it
|
||||||
// should end already exists as is. Since the old PtNode was not a terminal,
|
// should end already exists as is. Since the old PtNode was not a terminal,
|
||||||
// make it one by filling in its frequency and other attributes
|
// make it one by filling in its frequency and other attributes
|
||||||
currentPtNode.update(probabilityInfo, shortcutTargets, null, isNotAWord,
|
currentPtNode.update(probabilityInfo, null, isNotAWord,
|
||||||
isPossiblyOffensive);
|
isPossiblyOffensive);
|
||||||
} else {
|
} else {
|
||||||
// The new word matches the full old word and extends past it.
|
// The new word matches the full old word and extends past it.
|
||||||
// We only have to create a new node and add it to the end of this.
|
// We only have to create a new node and add it to the end of this.
|
||||||
final PtNode newNode = new PtNode(
|
final PtNode newNode = new PtNode(
|
||||||
Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length),
|
Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length),
|
||||||
shortcutTargets, null /* bigrams */, probabilityInfo,
|
null /* bigrams */, probabilityInfo,
|
||||||
isNotAWord, isPossiblyOffensive);
|
isNotAWord, isPossiblyOffensive);
|
||||||
currentPtNode.mChildren = new PtNodeArray();
|
currentPtNode.mChildren = new PtNodeArray();
|
||||||
currentPtNode.mChildren.mData.add(newNode);
|
currentPtNode.mChildren.mData.add(newNode);
|
||||||
|
@ -441,7 +387,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
if (0 == differentCharIndex) {
|
if (0 == differentCharIndex) {
|
||||||
// Exact same word. Update the frequency if higher. This will also add the
|
// Exact same word. Update the frequency if higher. This will also add the
|
||||||
// new shortcuts to the existing shortcut list if it already exists.
|
// new shortcuts to the existing shortcut list if it already exists.
|
||||||
currentPtNode.update(probabilityInfo, shortcutTargets, null,
|
currentPtNode.update(probabilityInfo, null,
|
||||||
currentPtNode.mIsNotAWord && isNotAWord,
|
currentPtNode.mIsNotAWord && isNotAWord,
|
||||||
currentPtNode.mIsPossiblyOffensive || isPossiblyOffensive);
|
currentPtNode.mIsPossiblyOffensive || isPossiblyOffensive);
|
||||||
} else {
|
} else {
|
||||||
|
@ -450,7 +396,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
PtNodeArray newChildren = new PtNodeArray();
|
PtNodeArray newChildren = new PtNodeArray();
|
||||||
final PtNode newOldWord = new PtNode(
|
final PtNode newOldWord = new PtNode(
|
||||||
Arrays.copyOfRange(currentPtNode.mChars, differentCharIndex,
|
Arrays.copyOfRange(currentPtNode.mChars, differentCharIndex,
|
||||||
currentPtNode.mChars.length), currentPtNode.mShortcutTargets,
|
currentPtNode.mChars.length),
|
||||||
currentPtNode.mBigrams, currentPtNode.mProbabilityInfo,
|
currentPtNode.mBigrams, currentPtNode.mProbabilityInfo,
|
||||||
currentPtNode.mIsNotAWord, currentPtNode.mIsPossiblyOffensive,
|
currentPtNode.mIsNotAWord, currentPtNode.mIsPossiblyOffensive,
|
||||||
currentPtNode.mChildren);
|
currentPtNode.mChildren);
|
||||||
|
@ -460,17 +406,17 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
if (charIndex + differentCharIndex >= word.length) {
|
if (charIndex + differentCharIndex >= word.length) {
|
||||||
newParent = new PtNode(
|
newParent = new PtNode(
|
||||||
Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
|
Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
|
||||||
shortcutTargets, null /* bigrams */, probabilityInfo,
|
null /* bigrams */, probabilityInfo,
|
||||||
isNotAWord, isPossiblyOffensive, newChildren);
|
isNotAWord, isPossiblyOffensive, newChildren);
|
||||||
} else {
|
} else {
|
||||||
newParent = new PtNode(
|
newParent = new PtNode(
|
||||||
Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
|
Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
|
||||||
null /* shortcutTargets */, null /* bigrams */,
|
null /* bigrams */, null /* probabilityInfo */,
|
||||||
null /* probabilityInfo */, false /* isNotAWord */,
|
false /* isNotAWord */, false /* isPossiblyOffensive */,
|
||||||
false /* isPossiblyOffensive */, newChildren);
|
newChildren);
|
||||||
final PtNode newWord = new PtNode(Arrays.copyOfRange(word,
|
final PtNode newWord = new PtNode(Arrays.copyOfRange(word,
|
||||||
charIndex + differentCharIndex, word.length),
|
charIndex + differentCharIndex, word.length),
|
||||||
shortcutTargets, null /* bigrams */, probabilityInfo,
|
null /* bigrams */, probabilityInfo,
|
||||||
isNotAWord, isPossiblyOffensive);
|
isNotAWord, isPossiblyOffensive);
|
||||||
final int addIndex = word[charIndex + differentCharIndex]
|
final int addIndex = word[charIndex + differentCharIndex]
|
||||||
> currentPtNode.mChars[differentCharIndex] ? 1 : 0;
|
> currentPtNode.mChars[differentCharIndex] ? 1 : 0;
|
||||||
|
@ -532,7 +478,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
private static int findInsertionIndex(final PtNodeArray nodeArray, int character) {
|
private static int findInsertionIndex(final PtNodeArray nodeArray, int character) {
|
||||||
final ArrayList<PtNode> data = nodeArray.mData;
|
final ArrayList<PtNode> data = nodeArray.mData;
|
||||||
final PtNode reference = new PtNode(new int[] { character },
|
final PtNode reference = new PtNode(new int[] { character },
|
||||||
null /* shortcutTargets */, null /* bigrams */, null /* probabilityInfo */,
|
null /* bigrams */, null /* probabilityInfo */,
|
||||||
false /* isNotAWord */, false /* isPossiblyOffensive */);
|
false /* isNotAWord */, false /* isPossiblyOffensive */);
|
||||||
int result = Collections.binarySearch(data, reference, PTNODE_COMPARATOR);
|
int result = Collections.binarySearch(data, reference, PTNODE_COMPARATOR);
|
||||||
return result >= 0 ? result : -result - 1;
|
return result >= 0 ? result : -result - 1;
|
||||||
|
@ -669,8 +615,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
|
||||||
}
|
}
|
||||||
if (currentPtNode.isTerminal()) {
|
if (currentPtNode.isTerminal()) {
|
||||||
return new WordProperty(mCurrentString.toString(),
|
return new WordProperty(mCurrentString.toString(),
|
||||||
currentPtNode.mProbabilityInfo,
|
currentPtNode.mProbabilityInfo, currentPtNode.mBigrams,
|
||||||
currentPtNode.mShortcutTargets, currentPtNode.mBigrams,
|
|
||||||
currentPtNode.mIsNotAWord, currentPtNode.mIsPossiblyOffensive);
|
currentPtNode.mIsNotAWord, currentPtNode.mIsPossiblyOffensive);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -285,7 +285,7 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
|
||||||
// Insert unigrams into the fusion dictionary.
|
// Insert unigrams into the fusion dictionary.
|
||||||
for (final WordProperty wordProperty : wordProperties) {
|
for (final WordProperty wordProperty : wordProperties) {
|
||||||
fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo,
|
fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo,
|
||||||
wordProperty.mShortcutTargets, wordProperty.mIsNotAWord,
|
wordProperty.mIsNotAWord,
|
||||||
wordProperty.mIsPossiblyOffensive);
|
wordProperty.mIsPossiblyOffensive);
|
||||||
}
|
}
|
||||||
// Insert bigrams into the fusion dictionary.
|
// Insert bigrams into the fusion dictionary.
|
||||||
|
|
|
@ -239,37 +239,6 @@ public class Ver2DictEncoder implements DictEncoder {
|
||||||
childrenPos);
|
childrenPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a shortcut attributes list to mBuffer.
|
|
||||||
*
|
|
||||||
* @param shortcuts the shortcut attributes list.
|
|
||||||
*/
|
|
||||||
private void writeShortcuts(final ArrayList<WeightedString> shortcuts,
|
|
||||||
final HashMap<Integer, Integer> codePointToOneByteCodeMap) {
|
|
||||||
if (null == shortcuts || shortcuts.isEmpty()) return;
|
|
||||||
|
|
||||||
final int indexOfShortcutByteSize = mPosition;
|
|
||||||
mPosition += FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE;
|
|
||||||
final Iterator<WeightedString> shortcutIterator = shortcuts.iterator();
|
|
||||||
while (shortcutIterator.hasNext()) {
|
|
||||||
final WeightedString target = shortcutIterator.next();
|
|
||||||
final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags(
|
|
||||||
shortcutIterator.hasNext(),
|
|
||||||
target.getProbability());
|
|
||||||
mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, shortcutFlags,
|
|
||||||
FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
|
|
||||||
final int shortcutShift = CharEncoding.writeString(mBuffer, mPosition, target.mWord,
|
|
||||||
codePointToOneByteCodeMap);
|
|
||||||
mPosition += shortcutShift;
|
|
||||||
}
|
|
||||||
final int shortcutByteSize = mPosition - indexOfShortcutByteSize;
|
|
||||||
if (shortcutByteSize > FormatSpec.MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE) {
|
|
||||||
throw new RuntimeException("Shortcut list too large");
|
|
||||||
}
|
|
||||||
BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, indexOfShortcutByteSize, shortcutByteSize,
|
|
||||||
FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a bigram attributes list to mBuffer.
|
* Write a bigram attributes list to mBuffer.
|
||||||
*
|
*
|
||||||
|
@ -305,8 +274,6 @@ public class Ver2DictEncoder implements DictEncoder {
|
||||||
writeCharacters(ptNode.mChars, ptNode.hasSeveralChars(), codePointToOneByteCodeMap);
|
writeCharacters(ptNode.mChars, ptNode.hasSeveralChars(), codePointToOneByteCodeMap);
|
||||||
writeFrequency(ptNode.getProbability());
|
writeFrequency(ptNode.getProbability());
|
||||||
writeChildrenPosition(ptNode, codePointToOneByteCodeMap);
|
writeChildrenPosition(ptNode, codePointToOneByteCodeMap);
|
||||||
// TODO: Use codePointToOneByteCodeMap for shortcuts.
|
|
||||||
writeShortcuts(ptNode.mShortcutTargets, null /* codePointToOneByteCodeMap */);
|
|
||||||
writeBigrams(ptNode.mBigrams, dict);
|
writeBigrams(ptNode.mBigrams, dict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin.makedict;
|
package com.android.inputmethod.latin.makedict;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
@ -49,7 +47,7 @@ public class Ver2DictEncoderTests extends AndroidTestCase {
|
||||||
new FormatSpec.FormatOptions(FormatSpec.VERSION2);
|
new FormatSpec.FormatOptions(FormatSpec.VERSION2);
|
||||||
final FusionDictionary sourcedict = new FusionDictionary(new PtNodeArray(),
|
final FusionDictionary sourcedict = new FusionDictionary(new PtNodeArray(),
|
||||||
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
|
||||||
addUnigrams(sourcedict, words, null /* shortcutMap */);
|
addUnigrams(sourcedict, words);
|
||||||
final CodePointTable codePointTable = Ver2DictEncoder.makeCodePointTable(sourcedict);
|
final CodePointTable codePointTable = Ver2DictEncoder.makeCodePointTable(sourcedict);
|
||||||
|
|
||||||
// Check if mCodePointOccurrenceArray is correct
|
// Check if mCodePointOccurrenceArray is correct
|
||||||
|
@ -73,17 +71,10 @@ public class Ver2DictEncoderTests extends AndroidTestCase {
|
||||||
/**
|
/**
|
||||||
* Adds unigrams to the dictionary.
|
* Adds unigrams to the dictionary.
|
||||||
*/
|
*/
|
||||||
private static void addUnigrams(final FusionDictionary dict, final List<String> words,
|
private static void addUnigrams(final FusionDictionary dict, final List<String> words) {
|
||||||
final HashMap<String, List<String>> shortcutMap) {
|
|
||||||
for (final String word : words) {
|
for (final String word : words) {
|
||||||
final ArrayList<WeightedString> shortcuts = new ArrayList<>();
|
|
||||||
if (shortcutMap != null && shortcutMap.containsKey(word)) {
|
|
||||||
for (final String shortcut : shortcutMap.get(word)) {
|
|
||||||
shortcuts.add(new WeightedString(shortcut, UNIGRAM_FREQ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ),
|
dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ),
|
||||||
(shortcutMap == null) ? null : shortcuts, false /* isNotAWord */,
|
false /* isNotAWord */,
|
||||||
false /* isPossiblyOffensive */);
|
false /* isPossiblyOffensive */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class Ver4DictDecoder extends AbstractDictDecoder {
|
||||||
// Insert unigrams into the fusion dictionary.
|
// Insert unigrams into the fusion dictionary.
|
||||||
for (final WordProperty wordProperty : wordProperties) {
|
for (final WordProperty wordProperty : wordProperties) {
|
||||||
fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo,
|
fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo,
|
||||||
wordProperty.mShortcutTargets, wordProperty.mIsNotAWord,
|
wordProperty.mIsNotAWord,
|
||||||
wordProperty.mIsPossiblyOffensive);
|
wordProperty.mIsPossiblyOffensive);
|
||||||
}
|
}
|
||||||
// Insert bigrams into the fusion dictionary.
|
// Insert bigrams into the fusion dictionary.
|
||||||
|
|
|
@ -74,26 +74,10 @@ public class Ver4DictEncoder implements DictEncoder {
|
||||||
throw new IOException("Cannot create dictionary file");
|
throw new IOException("Cannot create dictionary file");
|
||||||
}
|
}
|
||||||
for (final WordProperty wordProperty : dict) {
|
for (final WordProperty wordProperty : dict) {
|
||||||
// TODO: switch to addMultipleDictionaryEntries when they support shortcuts
|
if (!binaryDict.addUnigramEntry(wordProperty.mWord, wordProperty.getProbability(),
|
||||||
if (null == wordProperty.mShortcutTargets || wordProperty.mShortcutTargets.isEmpty()) {
|
wordProperty.mIsBeginningOfSentence, wordProperty.mIsNotAWord,
|
||||||
if (!binaryDict.addUnigramEntry(wordProperty.mWord, wordProperty.getProbability(),
|
wordProperty.mIsPossiblyOffensive, 0 /* timestamp */)) {
|
||||||
null /* shortcutTarget */, 0 /* shortcutProbability */,
|
MakedictLog.e("Cannot add unigram entry for " + wordProperty.mWord);
|
||||||
wordProperty.mIsBeginningOfSentence, wordProperty.mIsNotAWord,
|
|
||||||
wordProperty.mIsPossiblyOffensive, 0 /* timestamp */)) {
|
|
||||||
MakedictLog.e("Cannot add unigram entry for " + wordProperty.mWord);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) {
|
|
||||||
if (!binaryDict.addUnigramEntry(wordProperty.mWord,
|
|
||||||
wordProperty.getProbability(),
|
|
||||||
shortcutTarget.mWord, shortcutTarget.getProbability(),
|
|
||||||
wordProperty.mIsBeginningOfSentence, wordProperty.mIsNotAWord,
|
|
||||||
wordProperty.mIsPossiblyOffensive, 0 /* timestamp */)) {
|
|
||||||
MakedictLog.e("Cannot add unigram entry for " + wordProperty.mWord
|
|
||||||
+ ", shortcutTarget: " + shortcutTarget.mWord);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) {
|
if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) {
|
||||||
if (!binaryDict.flushWithGC()) {
|
if (!binaryDict.flushWithGC()) {
|
||||||
|
|
Loading…
Reference in New Issue