Remove shortcut support from LatinIME.

Note this change does not affect the native decoder interface.

Change-Id: I73b7dc008a5acaf75a31a36a2d332b5afabd82d0
This commit is contained in:
Dan Zivkovic 2015-02-10 14:54:38 -08:00
parent 2979fad213
commit 12d80ebead
36 changed files with 176 additions and 967 deletions

View file

@ -16,11 +16,20 @@
package com.android.inputmethod.latin.common;
import android.os.Build;
import com.android.inputmethod.annotations.UsedForTesting;
import javax.annotation.Nonnull;
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 {
/**
* The alpha value for fully opaque.

View file

@ -43,26 +43,6 @@
android:layout_marginStart="8dip"
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
android:id="@+id/user_dictionary_add_locale_label"
style="?android:attr/textAppearanceSmall"

View file

@ -35,6 +35,7 @@ import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.compat.SettingsSecureCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.utils.InputTypeUtils;
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
// announce events.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (Constants.JELLY_BEAN_OR_HIGHER) {
event.setEventType(AccessibilityEventCompat.TYPE_ANNOUNCEMENT);
} else {
event.setEventType(AccessibilityEvent.TYPE_VIEW_FOCUSED);

View file

@ -38,7 +38,7 @@ public final class InputMethodSubtypeCompatUtils {
int.class, int.class, String.class, String.class, String.class, boolean.class,
boolean.class, int.class);
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) {
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,
String mode, String extraValue, boolean isAuxiliary,
boolean overridesImplicitlyEnabledSubtype, int id) {
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (CONSTRUCTOR_INPUT_METHOD_SUBTYPE == null || !Constants.JELLY_BEAN_MR1_OR_HIGHER) {
return new InputMethodSubtype(nameId, iconId, locale, mode, extraValue, isAuxiliary,
overridesImplicitlyEnabledSubtype);
}

View file

@ -17,7 +17,8 @@
package com.android.inputmethod.compat;
import android.app.Notification;
import android.os.Build;
import com.android.inputmethod.latin.common.Constants;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -73,7 +74,7 @@ public class NotificationCompatUtils {
@SuppressWarnings("deprecation")
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
return (Notification) CompatUtils.invoke(builder, null, METHOD_build);
}

View file

@ -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);
}
}

View file

@ -40,13 +40,11 @@ import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.utils.CapsModeUtils;
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.ResourceUtils;
import com.android.inputmethod.latin.utils.ScriptUtils;
public final class KeyboardSwitcher implements KeyboardState.SwitchActions,
NetworkConnectivityUtils.NetworkStateChangeListener {
public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
private InputView mCurrentInputView;
@ -412,15 +410,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions,
return mCurrentInputView;
}
// {@link NetworkConnectivityUtils.NetworkStateChangeListener#onNetworkStateChanged(boolean)}.
@Override
public void onNetworkStateChanged() {
if (mKeyboardView == null) {
return;
}
mKeyboardView.updateShortcutKey(mRichImm.isShortcutImeReady());
}
public int getKeyboardShiftMode() {
final Keyboard keyboard = getKeyboard();
if (keyboard == null) {

View file

@ -694,25 +694,25 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
}
@Override
public boolean onTouchEvent(final MotionEvent me) {
public boolean onTouchEvent(final MotionEvent event) {
if (getKeyboard() == null) {
return false;
}
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.
mTimerHandler.cancelKeyRepeatTimers();
}
// Non distinct multitouch screen support
mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector);
mNonDistinctMultitouchHelper.processMotionEvent(event, mKeyDetector);
return true;
}
return processMotionEvent(me);
return processMotionEvent(event);
}
public boolean processMotionEvent(final MotionEvent me) {
final int index = me.getActionIndex();
final int id = me.getPointerId(index);
public boolean processMotionEvent(final MotionEvent event) {
final int index = event.getActionIndex();
final int id = event.getPointerId(index);
final PointerTracker tracker = PointerTracker.getPointerTracker(id);
// 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.
@ -720,7 +720,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
&& PointerTracker.getActivePointerTrackerCount() == 1) {
return true;
}
tracker.processMotionEvent(me, mKeyDetector);
tracker.processMotionEvent(event, mKeyDetector);
return true;
}

View file

@ -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_POSSIBLY_OFFENSIVE_INDEX = 1;
private static final int FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX = 2;
private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3;
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;
// 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_POSSIBLY_OFFENSIVE_INDEX],
outFlags[FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX],
outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX],
outFlags[FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX], outProbabilityInfo,
outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
outNgramTargets, outNgramProbabilityInfo, outShortcutTargets,
outShortcutProbabilities);
outNgramTargets, outNgramProbabilityInfo);
}
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.
public boolean addUnigramEntry(final String word, final int probability,
final String shortcutTarget, final int shortcutProbability,
final boolean isBeginningOfSentence, final boolean isNotAWord,
final boolean isPossiblyOffensive, final int timestamp) {
public boolean addUnigramEntry(
final String word, final int probability, final boolean isBeginningOfSentence,
final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
if (word == null || (word.isEmpty() && !isBeginningOfSentence)) {
return false;
}
final int[] codePoints = StringUtils.toCodePointArray(word);
final int[] shortcutTargetCodePoints = (shortcutTarget != null) ?
StringUtils.toCodePointArray(shortcutTarget) : null;
if (!addUnigramEntryNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints,
shortcutProbability, isBeginningOfSentence, isNotAWord, isPossiblyOffensive,
timestamp)) {
if (!addUnigramEntryNative(mNativeDict, codePoints, probability,
null /* shortcutTargetCodePoints */, 0 /* shortcutProbability */,
isBeginningOfSentence, isNotAWord, isPossiblyOffensive, timestamp)) {
return false;
}
mHasUpdated = true;

View file

@ -139,8 +139,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
Log.d(TAG, "loadAccountVocabulary: " + word);
}
runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS, null /* shortcut */,
0 /* shortcutFreq */, false /* isNotAWord */, false /* isPossiblyOffensive */,
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS,
false /* isNotAWord */, false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
}
}
@ -239,8 +239,7 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
Log.d(TAG, "addName " + name + ", " + word + ", " + ngramContext);
}
runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS,
null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */,
addUnigramLocked(word, FREQUENCY_FOR_CONTACTS, false /* isNotAWord */,
false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
if (!ngramContext.isValid() && mUseFirstLastBigrams) {

View file

@ -297,21 +297,18 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* Adds unigram information of a word to the dictionary. May overwrite an existing entry.
*/
public void addUnigramEntry(final String word, final int frequency,
final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
final boolean isPossiblyOffensive, final int timestamp) {
final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
updateDictionaryWithWriteLock(new Runnable() {
@Override
public void run() {
addUnigramLocked(word, frequency, shortcutTarget, shortcutFreq,
isNotAWord, isPossiblyOffensive, timestamp);
addUnigramLocked(word, frequency, isNotAWord, isPossiblyOffensive, timestamp);
}
});
}
protected void addUnigramLocked(final String word, final int frequency,
final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
final boolean isPossiblyOffensive, final int timestamp) {
if (!mBinaryDictionary.addUnigramEntry(word, frequency, shortcutTarget, shortcutFreq,
final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
if (!mBinaryDictionary.addUnigramEntry(word, frequency,
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive, timestamp)) {
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.
*/
@ -408,20 +380,29 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
isValidWord, count, timestamp)) {
if (DEBUG) {
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 void onFinished();
}
/**
* 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(
@Nonnull final ArrayList<WordInputEventForPersonalization> inputEvents,
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
* exists.
@ -551,6 +527,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
Thread.sleep(15000);
Log.w(TAG, "End stress in loading");
} catch (InterruptedException e) {
Log.w("Interrupted while loading: " + mDictName, e);
}
}
final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;

View file

@ -87,7 +87,6 @@ import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.JniUtils;
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.StatsUtilsManager;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@ -565,8 +564,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
loadSettings();
resetDictionaryFacilitatorIfNecessary();
NetworkConnectivityUtils.onCreate(this /* context */, mKeyboardSwitcher /* listener */);
// Register to receive ringer mode change.
final IntentFilter filter = new IntentFilter();
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
@ -703,7 +700,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onDestroy() {
mDictionaryFacilitator.closeDictionaries();
mSettings.onDestroy();
NetworkConnectivityUtils.onDestroy(this /* context */);
unregisterReceiver(mRingerModeChangeReceiver);
unregisterReceiver(mDictionaryPackInstallReceiver);
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
@ -717,7 +713,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
unregisterReceiver(mDictionaryPackInstallReceiver);
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
unregisterReceiver(mRingerModeChangeReceiver);
NetworkConnectivityUtils.onDestroy(this /* context */);
mInputLogic.recycle();
}

View file

@ -899,7 +899,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
* On platforms on which this method is not present, this is a no-op.
*/
public void maybeMoveTheCursorAroundAndRestoreToWorkaroundABug() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
if (!Constants.JELLY_BEAN_OR_HIGHER) {
if (mExpectedSelStart > 0) {
mIC.setSelection(mExpectedSelStart - 1, mExpectedSelStart - 1);
} else {

View file

@ -17,7 +17,6 @@
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.ExtraValue.REQ_NETWORK_CONNECTIVITY;
import android.content.Context;
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.utils.AdditionalSubtypeUtils;
import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
import com.android.inputmethod.latin.utils.NetworkConnectivityUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.Collections;
@ -288,24 +286,20 @@ public class RichInputMethodManager {
}
public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
return checkIfSubtypeBelongsToImeAndEnabled(getInputMethodInfoOfThisIme(), subtype);
return checkIfSubtypeBelongsToList(subtype,
getEnabledInputMethodSubtypeList(
getInputMethodInfoOfThisIme(),
true /* allowsImplicitlySelectedSubtypes */));
}
public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
final InputMethodSubtype subtype) {
final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(
subtype, getMyEnabledInputMethodSubtypeList(
false /* allowsImplicitlySelectedSubtypes */));
final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(subtype,
getMyEnabledInputMethodSubtypeList(false /* allowsImplicitlySelectedSubtypes */));
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,
final List<InputMethodSubtype> subtypes) {
return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
@ -564,16 +558,6 @@ public class RichInputMethodManager {
}.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() {
if (mShortcutInputMethodInfo == null) {
return false;
@ -581,9 +565,6 @@ public class RichInputMethodManager {
if (mShortcutSubtype == null) {
return true;
}
if (mShortcutSubtype.containsExtraValueKey(REQ_NETWORK_CONNECTIVITY)) {
return NetworkConnectivityUtils.isNetworkConnected();
}
return true;
}
}

View file

@ -22,7 +22,6 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Build;
import android.provider.UserDictionary.Words;
import android.text.TextUtils;
import android.util.Log;
@ -47,19 +46,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
private static final String USER_DICTIONARY_ALL_LANGUAGES = "";
private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
// Shortcut frequency is 0~15, with 15 = whitelist. We don't want user dictionary entries
// to auto-correct, so we set this to the highest frequency that won't, i.e. 14.
private static final int USER_DICT_SHORTCUT_FREQUENCY = 14;
private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] {
Words.WORD,
Words.SHORTCUT,
Words.FREQUENCY,
};
private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] {
Words.WORD,
Words.FREQUENCY,
};
private static final String[] PROJECTION_QUERY = new String[] {Words.WORD, Words.FREQUENCY};
private static final String NAME = "userunigram";
@ -171,20 +159,7 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
requestArguments = localeElements;
}
final String requestString = request.toString();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
try {
addWordsFromProjectionLocked(PROJECTION_QUERY_WITH_SHORTCUT, requestString,
requestArguments);
} catch (IllegalArgumentException e) {
// This may happen on some non-compliant devices where the declared API is JB+ but
// the SHORTCUT column is not present for some reason.
addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
requestArguments);
}
} else {
addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
requestArguments);
}
addWordsFromProjectionLocked(PROJECTION_QUERY, requestString, requestArguments);
}
private void addWordsFromProjectionLocked(final String[] query, String request,
@ -219,31 +194,20 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
}
private void addWordsLocked(final Cursor cursor) {
final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
if (cursor == null) return;
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
final int indexShortcut = hasShortcutColumn ? cursor.getColumnIndex(Words.SHORTCUT) : 0;
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
while (!cursor.isAfterLast()) {
final String word = cursor.getString(indexWord);
final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null;
final int frequency = cursor.getInt(indexFrequency);
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
// Safeguard against adding really long words.
if (word.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(word, adjustedFrequency, null /* shortcutTarget */,
0 /* shortcutFreq */, false /* isNotAWord */,
addUnigramLocked(word, adjustedFrequency, false /* isNotAWord */,
false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
if (null != shortcut && shortcut.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true /* mindsBlockByGC */);
addUnigramLocked(shortcut, adjustedFrequency, word,
USER_DICT_SHORTCUT_FREQUENCY, true /* isNotAWord */,
false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
}
}
cursor.moveToNext();
}

View file

@ -37,13 +37,11 @@ import javax.annotation.Nullable;
public final class WordProperty implements Comparable<WordProperty> {
public final String mWord;
public final ProbabilityInfo mProbabilityInfo;
public final ArrayList<WeightedString> mShortcutTargets;
public final ArrayList<NgramProperty> mNgrams;
// TODO: Support mIsBeginningOfSentence.
public final boolean mIsBeginningOfSentence;
public final boolean mIsNotAWord;
public final boolean mIsPossiblyOffensive;
public final boolean mHasShortcuts;
public final boolean mHasNgrams;
private int mHashCode = 0;
@ -51,12 +49,10 @@ public final class WordProperty implements Comparable<WordProperty> {
// TODO: Support n-gram.
@UsedForTesting
public WordProperty(final String word, final ProbabilityInfo probabilityInfo,
final ArrayList<WeightedString> shortcutTargets,
@Nullable final ArrayList<WeightedString> bigrams,
final boolean isNotAWord, final boolean isPossiblyOffensive) {
mWord = word;
mProbabilityInfo = probabilityInfo;
mShortcutTargets = shortcutTargets;
if (null == bigrams) {
mNgrams = null;
} else {
@ -70,7 +66,6 @@ public final class WordProperty implements Comparable<WordProperty> {
mIsNotAWord = isNotAWord;
mIsPossiblyOffensive = isPossiblyOffensive;
mHasNgrams = bigrams != null && !bigrams.isEmpty();
mHasShortcuts = shortcutTargets != null && !shortcutTargets.isEmpty();
}
private static ProbabilityInfo createProbabilityInfoFromArray(final int[] probabilityInfo) {
@ -84,21 +79,17 @@ public final class WordProperty implements Comparable<WordProperty> {
// Construct word property using information from native code.
// This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY.
public WordProperty(final int[] codePoints, final boolean isNotAWord,
final boolean isPossiblyOffensive, final boolean hasBigram, final boolean hasShortcuts,
final boolean isPossiblyOffensive, final boolean hasBigram,
final boolean isBeginningOfSentence, final int[] probabilityInfo,
final ArrayList<int[][]> ngramPrevWordsArray,
final ArrayList<boolean[]> ngramPrevWordIsBeginningOfSentenceArray,
final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo,
final ArrayList<int[]> shortcutTargets,
final ArrayList<Integer> shortcutProbabilities) {
final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo) {
mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo);
mShortcutTargets = new ArrayList<>();
final ArrayList<NgramProperty> ngrams = new ArrayList<>();
mIsBeginningOfSentence = isBeginningOfSentence;
mIsNotAWord = isNotAWord;
mIsPossiblyOffensive = isPossiblyOffensive;
mHasShortcuts = hasShortcuts;
mHasNgrams = hasBigram;
final int relatedNgramCount = ngramTargets.size();
@ -121,14 +112,6 @@ public final class WordProperty implements Comparable<WordProperty> {
ngrams.add(new NgramProperty(ngramTarget, ngramContext));
}
mNgrams = ngrams.isEmpty() ? null : ngrams;
final int shortcutTargetCount = shortcutTargets.size();
for (int i = 0; i < shortcutTargetCount; i++) {
final String shortcutTargetString =
StringUtils.getStringFromNullTerminatedCodePointArray(shortcutTargets.get(i));
mShortcutTargets.add(
new WeightedString(shortcutTargetString, shortcutProbabilities.get(i)));
}
}
// TODO: Remove
@ -154,7 +137,6 @@ public final class WordProperty implements Comparable<WordProperty> {
return Arrays.hashCode(new Object[] {
word.mWord,
word.mProbabilityInfo,
word.mShortcutTargets,
word.mNgrams,
word.mIsNotAWord,
word.mIsPossiblyOffensive
@ -185,10 +167,10 @@ public final class WordProperty implements Comparable<WordProperty> {
if (o == this) return true;
if (!(o instanceof WordProperty)) return false;
WordProperty w = (WordProperty)o;
return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord)
&& mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams)
return mProbabilityInfo.equals(w.mProbabilityInfo)
&& mWord.equals(w.mWord) && equals(mNgrams, w.mNgrams)
&& 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.

View file

@ -25,6 +25,7 @@ import android.preference.Preference;
import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.common.Constants;
/**
* "Preferences" settings sub screen.
@ -72,11 +73,9 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
final Preference voiceInputKeyOption = findPreference(Settings.PREF_VOICE_INPUT_KEY);
if (voiceInputKeyOption != null) {
RichInputMethodManager.getInstance().refreshSubtypeCaches();
final boolean isShortcutImeEnabled = RichInputMethodManager.getInstance()
.isShortcutImeEnabled();
voiceInputKeyOption.setEnabled(isShortcutImeEnabled);
voiceInputKeyOption.setSummary(
isShortcutImeEnabled ? null : getText(R.string.voice_input_disabled_summary));
voiceInputKeyOption.setEnabled(Constants.JELLY_BEAN_OR_HIGHER);
voiceInputKeyOption.setSummary(Constants.JELLY_BEAN_OR_HIGHER
? null : getText(R.string.voice_input_disabled_summary));
}
}

View file

@ -28,6 +28,7 @@ import com.android.inputmethod.compat.AppWorkaroundsUtils;
import com.android.inputmethod.latin.InputAttributes;
import com.android.inputmethod.latin.R;
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.ResourceUtils;
import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
@ -136,7 +137,7 @@ public class SettingsValues {
DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, true);
mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res)
&& mInputAttributes.mShouldShowVoiceInputKey
&& RichInputMethodManager.getInstance().isShortcutImeEnabled();
&& Constants.JELLY_BEAN_OR_HIGHER;
final String autoCorrectionThresholdRawValue = prefs.getString(
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
res.getString(R.string.auto_correction_threshold_mode_index_modest));

View file

@ -26,7 +26,6 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import com.android.inputmethod.compat.UserDictionaryCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.common.LocaleUtils;
@ -47,10 +46,7 @@ import javax.annotation.Nullable;
public class UserDictionaryAddWordContents {
public static final String EXTRA_MODE = "mode";
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_ORIGINAL_WORD = "originalWord";
public static final String EXTRA_ORIGINAL_SHORTCUT = "originalShortcut";
public static final int MODE_EDIT = 0;
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 EditText mWordEditText;
private final EditText mShortcutEditText;
private String mLocale;
private final String mOldWord;
private final String mOldShortcut;
private String mSavedWord;
private String mSavedShortcut;
/* package */ UserDictionaryAddWordContents(final View view, final Bundle args) {
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);
if (null != word) {
mWordEditText.setText(word);
@ -84,17 +72,6 @@ public class UserDictionaryAddWordContents {
// it's too long to be edited.
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
mOldWord = args.getString(EXTRA_WORD);
updateLocale(args.getString(EXTRA_LOCALE));
@ -103,10 +80,8 @@ public class UserDictionaryAddWordContents {
/* package */ UserDictionaryAddWordContents(final View view,
final UserDictionaryAddWordContents oldInstanceToBeEdited) {
mWordEditText = (EditText)view.findViewById(R.id.user_dictionary_add_word_text);
mShortcutEditText = (EditText)view.findViewById(R.id.user_dictionary_add_shortcut);
mMode = MODE_EDIT;
mOldWord = oldInstanceToBeEdited.mSavedWord;
mOldShortcut = oldInstanceToBeEdited.mSavedShortcut;
updateLocale(mLocale);
}
@ -118,13 +93,6 @@ public class UserDictionaryAddWordContents {
/* package */ void saveStateIntoBundle(final Bundle outState) {
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);
}
@ -132,7 +100,7 @@ public class UserDictionaryAddWordContents {
if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) {
// Mode edit: remove the old entry.
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.
}
@ -143,50 +111,31 @@ public class UserDictionaryAddWordContents {
final ContentResolver resolver = context.getContentResolver();
if (MODE_EDIT == mMode && !TextUtils.isEmpty(mOldWord)) {
// Mode edit: remove the old entry.
UserDictionarySettings.deleteWord(mOldWord, mOldShortcut, resolver);
UserDictionarySettings.deleteWord(mOldWord, resolver);
}
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 the word is somehow empty, don't insert it.
return CODE_CANCEL;
}
mSavedWord = newWord;
mSavedShortcut = newShortcut;
// If there is no shortcut, and the word already exists in the database, then we
// 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)) {
// If the word already exists in the database, then we should not insert.
if (hasWord(newWord, context)) {
return CODE_ALREADY_PRESENT;
}
// Disallow duplicates. If the same word with no shortcut is defined, remove it; if
// the same word with the same shortcut is defined, remove it; but we don't mind if
// 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);
}
// Disallow duplicates. If the same word is defined, remove it.
UserDictionarySettings.deleteWord(newWord, resolver);
// 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'.
UserDictionaryCompatUtils.addWord(context, newWord.toString(),
FREQUENCY_FOR_USER_DICTIONARY_ADDS, newShortcut, TextUtils.isEmpty(mLocale) ?
null : LocaleUtils.constructLocaleFromString(mLocale));
final Locale locale = TextUtils.isEmpty(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;
}

View file

@ -31,6 +31,7 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.LocaleUtils;
import java.util.List;
@ -74,7 +75,7 @@ public class UserDictionaryList extends PreferenceFragment {
} finally {
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
// is different from the system locale
localeSet.add("");

View file

@ -48,42 +48,18 @@ import java.util.Locale;
public class UserDictionarySettings extends ListFragment {
public static final boolean IS_SHORTCUT_API_SUPPORTED =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
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[] QUERY_PROJECTION = {
UserDictionary.Words._ID, UserDictionary.Words.WORD
};
private static final String[] ADAPTER_FROM_SHORTCUT_SUPPORTED = {
UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT
private static final String[] ADAPTER_FROM = {
UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT
};
private static final String[] ADAPTER_FROM = IS_SHORTCUT_API_SUPPORTED ?
ADAPTER_FROM_SHORTCUT_SUPPORTED : ADAPTER_FROM_SHORTCUT_UNSUPPORTED;
private static final int[] ADAPTER_TO_SHORTCUT_UNSUPPORTED = {
private static final int[] ADAPTER_TO = {
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)
// or the word equals our current locale
private static final String QUERY_SELECTION =
@ -91,13 +67,7 @@ public class UserDictionarySettings extends ListFragment {
private static final String QUERY_SELECTION_ALL_LOCALES =
UserDictionary.Words.LOCALE + " is null";
private static final String DELETE_SELECTION_WITH_SHORTCUT = 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 String DELETE_SELECTION = UserDictionary.Words.WORD + "=?";
private static final int OPTIONS_MENU_ADD = Menu.FIRST;
@ -192,20 +162,18 @@ public class UserDictionarySettings extends ListFragment {
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
final String word = getWord(position);
final String shortcut = getShortcut(position);
if (word != null) {
showAddOrEditDialog(word, shortcut);
showAddOrEditDialog(word);
}
}
@Override
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;
if (!TextUtils.isEmpty(mLocale) && !mLocale.equals(systemLocale.toString())) {
// 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
// with the shortcut API.
// for an entry.
return;
}
}
@ -219,7 +187,7 @@ public class UserDictionarySettings extends ListFragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == OPTIONS_MENU_ADD) {
showAddOrEditDialog(null, null);
showAddOrEditDialog(null);
return true;
}
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.
* @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();
args.putInt(UserDictionaryAddWordContents.EXTRA_MODE, null == editingWord
? UserDictionaryAddWordContents.MODE_INSERT
: UserDictionaryAddWordContents.MODE_EDIT);
args.putString(UserDictionaryAddWordContents.EXTRA_WORD, editingWord);
args.putString(UserDictionaryAddWordContents.EXTRA_SHORTCUT, editingShortcut);
args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale);
android.preference.PreferenceActivity pa =
(android.preference.PreferenceActivity)getActivity();
getActivity();
}
private String getWord(final int position) {
@ -252,31 +217,8 @@ public class UserDictionarySettings extends ListFragment {
mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD));
}
private String getShortcut(final int position) {
if (!IS_SHORTCUT_API_SUPPORTED) return null;
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 });
}
public static void deleteWord(final String word, final ContentResolver resolver) {
resolver.delete(UserDictionary.Words.CONTENT_URI, DELETE_SELECTION, new String[] { word });
}
private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer {
@ -286,22 +228,7 @@ public class UserDictionarySettings extends ListFragment {
@Override
public boolean setViewValue(final View v, final Cursor c, final int columnIndex) {
if (!IS_SHORTCUT_API_SUPPORTED) {
// 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;
}
// just let SimpleCursorAdapter set the view values
return false;
}
};

View file

@ -19,7 +19,6 @@ package com.android.inputmethod.latin.utils;
import com.android.inputmethod.latin.makedict.DictionaryHeader;
import com.android.inputmethod.latin.makedict.NgramProperty;
import com.android.inputmethod.latin.makedict.ProbabilityInfo;
import com.android.inputmethod.latin.makedict.WeightedString;
import com.android.inputmethod.latin.makedict.WordProperty;
import java.util.HashMap;
@ -29,7 +28,6 @@ public class CombinedFormatUtils {
public static final String BIGRAM_TAG = "bigram";
public static final String NGRAM_TAG = "ngram";
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 HISTORICAL_INFO_TAG = "historicalInfo";
public static final String HISTORICAL_INFO_SEPARATOR = ":";
@ -71,14 +69,6 @@ public class CombinedFormatUtils {
builder.append("," + POSSIBLY_OFFENSIVE_TAG + "=" + TRUE_VALUE);
}
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) {
for (final NgramProperty ngramProperty : wordProperty.mNgrams) {
builder.append(" " + NGRAM_TAG + "=" + ngramProperty.mTargetWord.mWord);

View file

@ -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();
}
}

View file

@ -17,19 +17,20 @@
package com.android.inputmethod.compat;
import android.graphics.Typeface;
import android.os.Build;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.StyleSpan;
import com.android.inputmethod.latin.common.Constants;
import java.util.Locale;
@SmallTest
public class LocaleSpanCompatUtilsTests extends AndroidTestCase {
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.
return;
}

View file

@ -16,15 +16,14 @@
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
* its glyph.
*/
class DevanagariLetterConstants {
private static final boolean NEEDS_DOTTED_CIRCLE =
Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN;
private static final boolean NEEDS_DOTTED_CIRCLE = !Constants.JELLY_BEAN_OR_HIGHER;
// U+25CC: "" DOTTED CIRCLE
private static final String DOTTED_CIRCLE = NEEDS_DOTTED_CIRCLE ? "\u25CC" : "";

View file

@ -700,8 +700,7 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
binaryDictionary.addUnigramEntry("", DUMMY_PROBABILITY, "" /* shortcutTarget */,
Dictionary.NOT_A_PROBABILITY /* shortcutProbability */,
binaryDictionary.addUnigramEntry("", DUMMY_PROBABILITY,
true /* isBeginningOfSentence */, true /* isNotAWord */,
false /* isPossiblyOffensive */, mCurrentTime);
final NgramContext beginningOfSentenceContext = NgramContext.BEGINNING_OF_SENTENCE;

View file

@ -182,8 +182,7 @@ public class BinaryDictionaryTests extends AndroidTestCase {
addUnigramWord(binaryDictionary, validLongWord, probability);
addUnigramWord(binaryDictionary, invalidLongWord, probability);
// Too long short cut.
binaryDictionary.addUnigramEntry("a", probability, invalidLongWord,
10 /* shortcutProbability */, false /* isBeginningOfSentence */,
binaryDictionary.addUnigramEntry("a", probability, false /* isBeginningOfSentence */,
false /* isNotAWord */, false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
addUnigramWord(binaryDictionary, "abc", probability);
@ -201,8 +200,7 @@ public class BinaryDictionaryTests extends AndroidTestCase {
private static void addUnigramWord(final BinaryDictionary binaryDictionary, final String word,
final int probability) {
binaryDictionary.addUnigramEntry(word, probability, "" /* shortcutTarget */,
Dictionary.NOT_A_PROBABILITY /* shortcutProbability */,
binaryDictionary.addUnigramEntry(word, probability,
false /* isBeginningOfSentence */, false /* isNotAWord */,
false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP /* timestamp */);
@ -884,7 +882,6 @@ public class BinaryDictionaryTests extends AndroidTestCase {
final boolean isPossiblyOffensive = random.nextBoolean();
// TODO: Add tests for historical info.
binaryDictionary.addUnigramEntry(word, unigramProbability,
null /* shortcutTarget */, Dictionary.NOT_A_PROBABILITY,
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
if (binaryDictionary.needsToRunGC(false /* mindsBlockByGC */)) {
@ -899,9 +896,7 @@ public class BinaryDictionaryTests extends AndroidTestCase {
assertEquals(isNotAWord, wordProperty.mIsNotAWord);
assertEquals(isPossiblyOffensive, wordProperty.mIsPossiblyOffensive);
assertEquals(false, wordProperty.mHasNgrams);
assertEquals(false, wordProperty.mHasShortcuts);
assertEquals(unigramProbability, wordProperty.mProbabilityInfo.mProbability);
assertTrue(wordProperty.mShortcutTargets.isEmpty());
}
for (int i = 0; i < BIGRAM_COUNT; i++) {
@ -1035,137 +1030,10 @@ public class BinaryDictionaryTests extends AndroidTestCase {
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() {
final BinaryDictionary binaryDictionary =
getEmptyBinaryDictionary(FormatSpec.VERSION403);
binaryDictionary.addUnigramEntry("ddd", 100, null, Dictionary.NOT_A_PROBABILITY,
false, true, true, 0);
binaryDictionary.addUnigramEntry("ddd", 100, false, true, true, 0);
WordProperty wordProperty = binaryDictionary.getWordProperty("ddd", false);
assertEquals(true, wordProperty.mIsPossiblyOffensive);
}
@ -1184,11 +1052,11 @@ public class BinaryDictionaryTests extends AndroidTestCase {
final int bigramProbability = 150;
addBigramWords(binaryDictionary, "aaa", "bbb", bigramProbability);
final int shortcutProbability = 10;
binaryDictionary.addUnigramEntry("ccc", unigramProbability, "xxx", shortcutProbability,
binaryDictionary.addUnigramEntry("ccc", unigramProbability,
false /* isBeginningOfSentence */, false /* isNotAWord */,
false /* isPossiblyOffensive */, 0 /* timestamp */);
binaryDictionary.addUnigramEntry("ddd", unigramProbability, null /* shortcutTarget */,
Dictionary.NOT_A_PROBABILITY, false /* isBeginningOfSentence */,
binaryDictionary.addUnigramEntry("ddd", unigramProbability,
false /* isBeginningOfSentence */,
true /* isNotAWord */, true /* isPossiblyOffensive */, 0 /* timestamp */);
binaryDictionary.addNgramEntry(NgramContext.BEGINNING_OF_SENTENCE,
"aaa", bigramProbability, 0 /* timestamp */);
@ -1207,8 +1075,6 @@ public class BinaryDictionaryTests extends AndroidTestCase {
assertTrue(isValidBigram(binaryDictionary, "aaa", "bbb"));
WordProperty wordProperty = binaryDictionary.getWordProperty("ccc",
false /* isBeginningOfSentence */);
assertEquals(1, wordProperty.mShortcutTargets.size());
assertEquals("xxx", wordProperty.mShortcutTargets.get(0).mWord);
wordProperty = binaryDictionary.getWordProperty("ddd",
false /* isBeginningOfSentence */);
assertTrue(wordProperty.mIsPossiblyOffensive);

View file

@ -35,19 +35,19 @@ public class FusionDictionaryTests extends AndroidTestCase {
FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
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 */);
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
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 */);
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa"));
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 */);
dict.add("bacde", new ProbabilityInfo(10), null, false /* isNotAWord */,
dict.add("bacde", new ProbabilityInfo(10), false /* isNotAWord */,
false /* isPossiblyOffensive */);
assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "ba"));
assertNotNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "babcd"));

View file

@ -57,15 +57,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
private static final int UNIGRAM_FREQ = 10;
private static final int BIGRAM_FREQ = 50;
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> sWordsWithVariousCodePoints = new ArrayList<>();
private static final SparseArray<List<Integer>> sEmptyBigrams = new SparseArray<>();
private static final SparseArray<List<Integer>> sStarBigrams = new SparseArray<>();
private static final SparseArray<List<Integer>> sChainBigrams = new SparseArray<>();
private static final HashMap<String, List<String>> sShortcuts = new HashMap<>();
final Random mRandom;
@ -95,16 +92,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
for (int i = 1; i < maxBigrams; ++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
@ -142,17 +129,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
* Adds unigrams to the dictionary.
*/
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) {
final String word = words.get(i);
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),
(shortcutMap == null) ? null : shortcuts, false /* isNotAWord */,
dict.add(word, new ProbabilityInfo(UNIGRAM_FREQ), false /* isNotAWord */,
false /* isPossiblyOffensive */);
}
}
@ -200,8 +181,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
private static void checkDictionary(final FusionDictionary dict, final List<String> words,
final SparseArray<List<Integer>> bigrams,
final HashMap<String, List<String>> shortcutMap) {
final SparseArray<List<Integer>> bigrams) {
assertNotNull(dict);
// check unigram
@ -219,19 +199,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
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,
@ -244,8 +211,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
// Tests for readDictionaryBinary and writeDictionaryBinary
private static long timeReadingAndCheckDict(final File file, final List<String> words,
final SparseArray<List<Integer>> bigrams,
final HashMap<String, List<String>> shortcutMap, final int bufferType) {
final SparseArray<List<Integer>> bigrams, final int bufferType) {
long now, diff = -1;
FusionDictionary dict = null;
@ -261,13 +227,13 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
Log.e(TAG, "Unsupported format", e);
}
checkDictionary(dict, words, bigrams, shortcutMap);
checkDictionary(dict, words, bigrams);
return diff;
}
// Tests for readDictionaryBinary and writeDictionaryBinary
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 String message) {
@ -278,12 +244,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(words.size(), dict, words, shortcuts);
addUnigrams(words.size(), dict, words);
addBigrams(dict, words, bigrams);
checkDictionary(dict, words, bigrams, shortcuts);
checkDictionary(dict, words, bigrams);
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
+ " : " + outputOptions(bufferType, formatOptions);
@ -291,20 +257,20 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
private void runReadAndWriteTests(final List<String> results, final int bufferType,
final FormatSpec.FormatOptions formatOptions) {
results.add(runReadAndWrite(sWords, sEmptyBigrams, null /* shortcuts */, bufferType,
results.add(runReadAndWrite(sWords, sEmptyBigrams, bufferType,
formatOptions, "unigram"));
results.add(runReadAndWrite(sWords, sChainBigrams, null /* shortcuts */, bufferType,
results.add(runReadAndWrite(sWords, sChainBigrams, bufferType,
formatOptions, "chain"));
results.add(runReadAndWrite(sWords, sStarBigrams, null /* shortcuts */, bufferType,
results.add(runReadAndWrite(sWords, sStarBigrams, bufferType,
formatOptions, "star"));
results.add(runReadAndWrite(sWords, sEmptyBigrams, sShortcuts, bufferType, formatOptions,
results.add(runReadAndWrite(sWords, sEmptyBigrams, bufferType, formatOptions,
"unigram with shortcuts"));
results.add(runReadAndWrite(sWords, sChainBigrams, sShortcuts, bufferType, formatOptions,
results.add(runReadAndWrite(sWords, sChainBigrams, bufferType, formatOptions,
"chain with shortcuts"));
results.add(runReadAndWrite(sWords, sStarBigrams, sShortcuts, bufferType, formatOptions,
results.add(runReadAndWrite(sWords, sStarBigrams, bufferType, formatOptions,
"star with shortcuts"));
results.add(runReadAndWrite(sWordsWithVariousCodePoints, sEmptyBigrams,
null /* shortcuts */, bufferType, formatOptions,
bufferType, formatOptions,
"unigram with various code points"));
}
@ -326,7 +292,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
FormatSpec.MINIMUM_SUPPORTED_STATIC_VERSION);
final FusionDictionary sourcedict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(words.size(), sourcedict, words, null /* shortcutMap */);
addUnigrams(words.size(), sourcedict, words);
dictEncoder.writeDictionary(sourcedict, formatOptions);
// Read the dictionary
@ -472,7 +438,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
// making the dictionary from lists of words.
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(words.size(), dict, words, null /* shortcutMap */);
addUnigrams(words.size(), dict, words);
addBigrams(dict, words, bigrams);
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.
long wordMap = timeAndCheckReadUnigramsAndBigramsBinary(file, words, bigrams, bufferType,
!formatOptions.mHasTimestamp /* checkProbability */);
long fullReading = timeReadingAndCheckDict(file, words, bigrams, null /* shortcutMap */,
long fullReading = timeReadingAndCheckDict(file, words, bigrams,
bufferType);
return "readDictionaryBinary=" + fullReading + ", readUnigramsAndBigramsBinary=" + wordMap
@ -567,7 +533,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */);
addUnigrams(sWords.size(), dict, sWords);
addBigrams(dict, words, bigrams);
timeWritingDictToFile(file, dict, formatOptions);
@ -636,12 +602,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
public void testVer2DictGetWordProperty() {
final FormatOptions formatOptions = BinaryDictUtils.STATIC_OPTIONS;
final ArrayList<String> words = sWords;
final HashMap<String, List<String>> shortcuts = sShortcuts;
final String dictName = "testGetWordProperty";
final String dictVersion = Long.toString(System.currentTimeMillis());
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(words.size(), dict, words, shortcuts);
addUnigrams(words.size(), dict, words);
addBigrams(dict, words, sEmptyBigrams);
final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions,
getContext().getCacheDir());
@ -655,30 +620,18 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
false /* isBeginningOfSentence */);
assertEquals(word, wordProperty.mWord);
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() {
final FormatOptions formatOptions = BinaryDictUtils.STATIC_OPTIONS;
final ArrayList<String> words = sWords;
final HashMap<String, List<String>> shortcuts = sShortcuts;
final SparseArray<List<Integer>> bigrams = sEmptyBigrams;
final String dictName = "testGetWordProperty";
final String dictVersion = Long.toString(System.currentTimeMillis());
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(words.size(), dict, words, shortcuts);
addUnigrams(words.size(), dict, words);
addBigrams(dict, words, bigrams);
final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions,
getContext().getCacheDir());
@ -708,17 +661,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
final String word0 = wordProperty.mWord;
assertEquals(UNIGRAM_FREQ, wordProperty.mProbabilityInfo.mProbability);
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) {
for (final WeightedString bigramTarget : wordProperty.getBigrams()) {
final String word1 = bigramTarget.mWord;

View file

@ -16,9 +16,7 @@
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.DictBuffer;
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
@ -91,38 +89,6 @@ public class BinaryDictEncoderUtils {
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.
*
@ -137,8 +103,6 @@ public class BinaryDictEncoderUtils {
size += FormatSpec.PTNODE_FREQUENCY_SIZE;
}
size += FormatSpec.PTNODE_MAX_ADDRESS_SIZE; // For children address
// TODO: Use codePointToOneByteCodeMap for shortcuts.
size += getShortcutListSize(ptNode.mShortcutTargets, null /* codePointToOneByteCodeMap */);
if (null != ptNode.mBigrams) {
size += (FormatSpec.PTNODE_ATTRIBUTE_FLAGS_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
// 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 + size, ptNode.mChildren));
}
// TODO: Use codePointToOneByteCodeMap for shortcuts.
nodeSize += getShortcutListSize(ptNode.mShortcutTargets,
null /* codePointToOneByteCodeMap */);
if (null != ptNode.mBigrams) {
for (WeightedString bigram : ptNode.mBigrams) {
final int offset = getOffsetToTargetPtNodeDuringUpdate(ptNodeArray,
@ -568,14 +508,13 @@ public class BinaryDictEncoderUtils {
* @param hasMultipleChars whether the PtNode has multiple chars.
* @param isTerminal whether the PtNode is terminal.
* @param childrenAddressSize the size of a children address.
* @param hasShortcuts whether the PtNode has shortcuts.
* @param hasBigrams whether the PtNode has bigrams.
* @param isNotAWord whether the PtNode is not a word.
* @param isPossiblyOffensive whether the PtNode is a possibly offensive entry.
* @return the flags
*/
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) {
byte flags = 0;
if (hasMultipleChars) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS;
@ -596,7 +535,6 @@ public class BinaryDictEncoderUtils {
default:
throw new RuntimeException("Node with a strange address");
}
if (hasShortcuts) flags |= FormatSpec.FLAG_HAS_SHORTCUT_TARGETS;
if (hasBigrams) flags |= FormatSpec.FLAG_HAS_BIGRAMS;
if (isNotAWord) flags |= FormatSpec.FLAG_IS_NOT_A_WORD;
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) {
return (byte) makePtNodeFlags(node.mChars.length > 1, node.isTerminal(),
getByteSize(childrenOffset),
node.mShortcutTargets != null && !node.mShortcutTargets.isEmpty(),
node.mBigrams != null && !node.mBigrams.isEmpty(),
node.mIsNotAWord, node.mIsPossiblyOffensive);
}
@ -621,7 +558,7 @@ public class BinaryDictEncoderUtils {
* @param word the second bigram, for debugging purposes
* @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) {
int bigramFlags = (more ? FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT : 0)
+ (offset < 0 ? FormatSpec.FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE : 0);
@ -690,19 +627,7 @@ public class BinaryDictEncoderUtils {
return discretizedFrequency > 0 ? discretizedFrequency : 0;
}
/**
* 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,
/* package */ static int getChildrenPosition(final PtNode ptNode,
final HashMap<Integer, Integer> codePointToOneByteCodeMap) {
int positionOfChildrenPosField = ptNode.mCachedAddressAfterUpdate
+ getNodeHeaderSize(ptNode, codePointToOneByteCodeMap);

View file

@ -82,7 +82,6 @@ public final class FusionDictionary implements Iterable<WordProperty> {
public static final class PtNode {
private static final int NOT_A_TERMINAL = -1;
final int mChars[];
ArrayList<WeightedString> mShortcutTargets;
ArrayList<WeightedString> mBigrams;
// null == mProbabilityInfo indicates this is not a terminal.
ProbabilityInfo mProbabilityInfo;
@ -100,26 +99,23 @@ public final class FusionDictionary implements Iterable<WordProperty> {
int mCachedAddressBeforeUpdate; // The address of this PtNode (before update)
int mCachedAddressAfterUpdate; // The address of this PtNode (after update)
public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
final ArrayList<WeightedString> bigrams, final ProbabilityInfo probabilityInfo,
final boolean isNotAWord, final boolean isPossiblyOffensive) {
public PtNode(final int[] chars, final ArrayList<WeightedString> bigrams,
final ProbabilityInfo probabilityInfo, final boolean isNotAWord,
final boolean isPossiblyOffensive) {
mChars = chars;
mProbabilityInfo = probabilityInfo;
mTerminalId = probabilityInfo == null ? NOT_A_TERMINAL : probabilityInfo.mProbability;
mShortcutTargets = shortcutTargets;
mBigrams = bigrams;
mChildren = null;
mIsNotAWord = isNotAWord;
mIsPossiblyOffensive = isPossiblyOffensive;
}
public PtNode(final int[] chars, final ArrayList<WeightedString> shortcutTargets,
final ArrayList<WeightedString> bigrams, final ProbabilityInfo probabilityInfo,
final boolean isNotAWord, final boolean isPossiblyOffensive,
final PtNodeArray children) {
public PtNode(final int[] chars, final ArrayList<WeightedString> bigrams,
final ProbabilityInfo probabilityInfo, final boolean isNotAWord,
final boolean isPossiblyOffensive, final PtNodeArray children) {
mChars = chars;
mProbabilityInfo = probabilityInfo;
mShortcutTargets = shortcutTargets;
mBigrams = bigrams;
mChildren = children;
mIsNotAWord = isNotAWord;
@ -153,14 +149,6 @@ public final class FusionDictionary implements Iterable<WordProperty> {
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() {
// We don't want write permission to escape outside the package, so we return a copy
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.
* 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.
*/
void update(final ProbabilityInfo probabilityInfo,
final ArrayList<WeightedString> shortcutTargets,
final ArrayList<WeightedString> bigrams,
final boolean isNotAWord, final boolean isPossiblyOffensive) {
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 (mBigrams == null) {
mBigrams = bigrams;
@ -312,19 +264,16 @@ public final class FusionDictionary implements Iterable<WordProperty> {
* Helper method to add a word as a string.
*
* 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.
*
* @param word the word to add.
* @param word the word to add.
* @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 isPossiblyOffensive true if this word is possibly offensive
*/
public void add(final String word, final ProbabilityInfo probabilityInfo,
final ArrayList<WeightedString> shortcutTargets, final boolean isNotAWord,
final boolean isPossiblyOffensive) {
add(getCodePoints(word), probabilityInfo, shortcutTargets, isNotAWord, isPossiblyOffensive);
final boolean isNotAWord, final boolean isPossiblyOffensive) {
add(getCodePoints(word), probabilityInfo, isNotAWord, isPossiblyOffensive);
}
/**
@ -358,7 +307,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
if (ptNode0 != null) {
final PtNode ptNode1 = findWordInTree(mRootNodeArray, word1);
if (ptNode1 == null) {
add(getCodePoints(word1), new ProbabilityInfo(0), null, false /* isNotAWord */,
add(getCodePoints(word1), new ProbabilityInfo(0), false /* isNotAWord */,
false /* isPossiblyOffensive */);
// 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
@ -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,
* 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 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 isPossiblyOffensive true if this word is possibly offensive
*/
private void add(final int[] word, final ProbabilityInfo probabilityInfo,
final ArrayList<WeightedString> shortcutTargets,
final boolean isNotAWord, final boolean isPossiblyOffensive) {
assert(probabilityInfo.mProbability <= FormatSpec.MAX_TERMINAL_FREQUENCY);
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.
final int insertionIndex = findInsertionIndex(currentNodeArray, word[charIndex]);
final PtNode newPtNode = new PtNode(Arrays.copyOfRange(word, charIndex, word.length),
shortcutTargets, null /* bigrams */, probabilityInfo, isNotAWord,
null /* bigrams */, probabilityInfo, isNotAWord,
isPossiblyOffensive);
currentNodeArray.mData.add(insertionIndex, newPtNode);
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
// 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
currentPtNode.update(probabilityInfo, shortcutTargets, null, isNotAWord,
currentPtNode.update(probabilityInfo, null, isNotAWord,
isPossiblyOffensive);
} else {
// 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.
final PtNode newNode = new PtNode(
Arrays.copyOfRange(word, charIndex + differentCharIndex, word.length),
shortcutTargets, null /* bigrams */, probabilityInfo,
null /* bigrams */, probabilityInfo,
isNotAWord, isPossiblyOffensive);
currentPtNode.mChildren = new PtNodeArray();
currentPtNode.mChildren.mData.add(newNode);
@ -441,7 +387,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
if (0 == differentCharIndex) {
// Exact same word. Update the frequency if higher. This will also add the
// new shortcuts to the existing shortcut list if it already exists.
currentPtNode.update(probabilityInfo, shortcutTargets, null,
currentPtNode.update(probabilityInfo, null,
currentPtNode.mIsNotAWord && isNotAWord,
currentPtNode.mIsPossiblyOffensive || isPossiblyOffensive);
} else {
@ -450,7 +396,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
PtNodeArray newChildren = new PtNodeArray();
final PtNode newOldWord = new PtNode(
Arrays.copyOfRange(currentPtNode.mChars, differentCharIndex,
currentPtNode.mChars.length), currentPtNode.mShortcutTargets,
currentPtNode.mChars.length),
currentPtNode.mBigrams, currentPtNode.mProbabilityInfo,
currentPtNode.mIsNotAWord, currentPtNode.mIsPossiblyOffensive,
currentPtNode.mChildren);
@ -460,17 +406,17 @@ public final class FusionDictionary implements Iterable<WordProperty> {
if (charIndex + differentCharIndex >= word.length) {
newParent = new PtNode(
Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
shortcutTargets, null /* bigrams */, probabilityInfo,
null /* bigrams */, probabilityInfo,
isNotAWord, isPossiblyOffensive, newChildren);
} else {
newParent = new PtNode(
Arrays.copyOfRange(currentPtNode.mChars, 0, differentCharIndex),
null /* shortcutTargets */, null /* bigrams */,
null /* probabilityInfo */, false /* isNotAWord */,
false /* isPossiblyOffensive */, newChildren);
null /* bigrams */, null /* probabilityInfo */,
false /* isNotAWord */, false /* isPossiblyOffensive */,
newChildren);
final PtNode newWord = new PtNode(Arrays.copyOfRange(word,
charIndex + differentCharIndex, word.length),
shortcutTargets, null /* bigrams */, probabilityInfo,
null /* bigrams */, probabilityInfo,
isNotAWord, isPossiblyOffensive);
final int addIndex = word[charIndex + differentCharIndex]
> 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) {
final ArrayList<PtNode> data = nodeArray.mData;
final PtNode reference = new PtNode(new int[] { character },
null /* shortcutTargets */, null /* bigrams */, null /* probabilityInfo */,
null /* bigrams */, null /* probabilityInfo */,
false /* isNotAWord */, false /* isPossiblyOffensive */);
int result = Collections.binarySearch(data, reference, PTNODE_COMPARATOR);
return result >= 0 ? result : -result - 1;
@ -669,8 +615,7 @@ public final class FusionDictionary implements Iterable<WordProperty> {
}
if (currentPtNode.isTerminal()) {
return new WordProperty(mCurrentString.toString(),
currentPtNode.mProbabilityInfo,
currentPtNode.mShortcutTargets, currentPtNode.mBigrams,
currentPtNode.mProbabilityInfo, currentPtNode.mBigrams,
currentPtNode.mIsNotAWord, currentPtNode.mIsPossiblyOffensive);
}
} else {

View file

@ -285,7 +285,7 @@ public class Ver2DictDecoder extends AbstractDictDecoder {
// Insert unigrams into the fusion dictionary.
for (final WordProperty wordProperty : wordProperties) {
fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo,
wordProperty.mShortcutTargets, wordProperty.mIsNotAWord,
wordProperty.mIsNotAWord,
wordProperty.mIsPossiblyOffensive);
}
// Insert bigrams into the fusion dictionary.

View file

@ -239,37 +239,6 @@ public class Ver2DictEncoder implements DictEncoder {
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.
*
@ -305,8 +274,6 @@ public class Ver2DictEncoder implements DictEncoder {
writeCharacters(ptNode.mChars, ptNode.hasSeveralChars(), codePointToOneByteCodeMap);
writeFrequency(ptNode.getProbability());
writeChildrenPosition(ptNode, codePointToOneByteCodeMap);
// TODO: Use codePointToOneByteCodeMap for shortcuts.
writeShortcuts(ptNode.mShortcutTargets, null /* codePointToOneByteCodeMap */);
writeBigrams(ptNode.mBigrams, dict);
}
}

View file

@ -16,9 +16,7 @@
package com.android.inputmethod.latin.makedict;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
@ -49,7 +47,7 @@ public class Ver2DictEncoderTests extends AndroidTestCase {
new FormatSpec.FormatOptions(FormatSpec.VERSION2);
final FusionDictionary sourcedict = new FusionDictionary(new PtNodeArray(),
BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions));
addUnigrams(sourcedict, words, null /* shortcutMap */);
addUnigrams(sourcedict, words);
final CodePointTable codePointTable = Ver2DictEncoder.makeCodePointTable(sourcedict);
// Check if mCodePointOccurrenceArray is correct
@ -73,17 +71,10 @@ public class Ver2DictEncoderTests extends AndroidTestCase {
/**
* Adds unigrams to the dictionary.
*/
private static void addUnigrams(final FusionDictionary dict, final List<String> words,
final HashMap<String, List<String>> shortcutMap) {
private static void addUnigrams(final FusionDictionary dict, final List<String> 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),
(shortcutMap == null) ? null : shortcuts, false /* isNotAWord */,
false /* isNotAWord */,
false /* isPossiblyOffensive */);
}
}

View file

@ -84,7 +84,7 @@ public class Ver4DictDecoder extends AbstractDictDecoder {
// Insert unigrams into the fusion dictionary.
for (final WordProperty wordProperty : wordProperties) {
fusionDict.add(wordProperty.mWord, wordProperty.mProbabilityInfo,
wordProperty.mShortcutTargets, wordProperty.mIsNotAWord,
wordProperty.mIsNotAWord,
wordProperty.mIsPossiblyOffensive);
}
// Insert bigrams into the fusion dictionary.

View file

@ -74,26 +74,10 @@ public class Ver4DictEncoder implements DictEncoder {
throw new IOException("Cannot create dictionary file");
}
for (final WordProperty wordProperty : dict) {
// TODO: switch to addMultipleDictionaryEntries when they support shortcuts
if (null == wordProperty.mShortcutTargets || wordProperty.mShortcutTargets.isEmpty()) {
if (!binaryDict.addUnigramEntry(wordProperty.mWord, wordProperty.getProbability(),
null /* shortcutTarget */, 0 /* shortcutProbability */,
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.addUnigramEntry(wordProperty.mWord, wordProperty.getProbability(),
wordProperty.mIsBeginningOfSentence, wordProperty.mIsNotAWord,
wordProperty.mIsPossiblyOffensive, 0 /* timestamp */)) {
MakedictLog.e("Cannot add unigram entry for " + wordProperty.mWord);
}
if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) {
if (!binaryDict.flushWithGC()) {