aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java13
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java23
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java16
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFactory.java2
-rw-r--r--java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java18
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java2
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java13
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java56
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java61
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java33
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java27
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java85
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java89
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java53
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java41
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java18
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java24
-rw-r--r--java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java5
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/SuggestionResults.java15
20 files changed, 228 insertions, 372 deletions
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index addc8f209..9ea1950f5 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -20,7 +20,8 @@ import android.content.Context;
import android.util.Pair;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.keyboard.KeyboardLayout;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.common.ComposedData;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.utils.SuggestionResults;
@@ -147,18 +148,18 @@ public interface DictionaryFacilitator {
throws InterruptedException;
void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
- @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
+ @Nonnull final NgramContext ngramContext, final long timeStampInSeconds,
final boolean blockPotentiallyOffensive);
void unlearnFromUserHistory(final String word,
- @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
+ @Nonnull final NgramContext ngramContext, final long timeStampInSeconds,
final int eventType);
// TODO: Revise the way to fusion suggestion results.
- SuggestionResults getSuggestionResults(final WordComposer composer,
- final NgramContext ngramContext, final long proximityInfoHandle,
+ SuggestionResults getSuggestionResults(final ComposedData composedData,
+ final NgramContext ngramContext, @Nonnull final Keyboard keyboard,
final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId,
- final int inputStyle, final KeyboardLayout keyboardLayout);
+ final int inputStyle);
boolean isValidSpellingWord(final String word);
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
index 1e0885420..763cfa26d 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java
@@ -22,9 +22,10 @@ import android.util.Log;
import android.util.Pair;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.keyboard.KeyboardLayout;
+import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.NgramContext.WordInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.common.ComposedData;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
@@ -579,7 +580,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
}
public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
- @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
+ @Nonnull final NgramContext ngramContext, final long timeStampInSeconds,
final boolean blockPotentiallyOffensive) {
final DictionaryGroup dictionaryGroup = getDictionaryGroupForMostProbableLanguage();
final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
@@ -588,7 +589,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
final String currentWord = words[i];
final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false;
addWordToUserHistory(dictionaryGroup, ngramContextForCurrentWord, currentWord,
- wasCurrentWordAutoCapitalized, timeStampInSeconds, blockPotentiallyOffensive);
+ wasCurrentWordAutoCapitalized, (int) timeStampInSeconds, blockPotentiallyOffensive);
ngramContextForCurrentWord =
ngramContextForCurrentWord.getNextNgramContext(new WordInfo(currentWord));
}
@@ -656,7 +657,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
@Override
public void unlearnFromUserHistory(final String word,
- @Nonnull final NgramContext ngramContext, final int timeStampInSeconds,
+ @Nonnull final NgramContext ngramContext, final long timeStampInSeconds,
final int eventType) {
// TODO: Decide whether or not to remove the word on EVENT_BACKSPACE.
if (eventType != Constants.EVENT_BACKSPACE) {
@@ -666,24 +667,26 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
// TODO: Revise the way to fusion suggestion results.
@Override
- public SuggestionResults getSuggestionResults(WordComposer composer,
- NgramContext ngramContext, long proximityInfoHandle,
+ public SuggestionResults getSuggestionResults(ComposedData composedData,
+ NgramContext ngramContext, @Nonnull final Keyboard keyboard,
SettingsValuesForSuggestion settingsValuesForSuggestion, int sessionId,
- int inputStyle, KeyboardLayout keyboardLayout) {
+ int inputStyle) {
+ long proximityInfoHandle = keyboard.getProximityInfo().getNativeProximityInfo();
final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
final SuggestionResults suggestionResults = new SuggestionResults(
- SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext());
+ SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext(),
+ false /* firstSuggestionExceedsConfidenceThreshold */);
final float[] weightOfLangModelVsSpatialModel =
new float[] { Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL };
for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
for (final String dictType : DICTIONARY_TYPES_FOR_SUGGESTIONS) {
final Dictionary dictionary = dictionaryGroup.getDict(dictType);
if (null == dictionary) continue;
- final float weightForLocale = composer.isBatchMode()
+ final float weightForLocale = composedData.mIsBatchMode
? dictionaryGroup.mWeightForGesturingInLocale
: dictionaryGroup.mWeightForTypingInLocale;
final ArrayList<SuggestedWordInfo> dictionarySuggestions =
- dictionary.getSuggestions(composer.getComposedDataSnapshot(), ngramContext,
+ dictionary.getSuggestions(composedData, ngramContext,
proximityInfoHandle, settingsValuesForSuggestion, sessionId,
weightForLocale, weightOfLangModelVsSpatialModel);
if (null == dictionarySuggestions) continue;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
index b813af4c2..2a1ae3684 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
@@ -41,7 +41,8 @@ public class DictionaryFacilitatorLruCache {
public DictionaryFacilitatorLruCache(final Context context, final String dictionaryNamePrefix) {
mContext = context;
mDictionaryNamePrefix = dictionaryNamePrefix;
- mDictionaryFacilitator = DictionaryFacilitatorProvider.getDictionaryFacilitator();
+ mDictionaryFacilitator = DictionaryFacilitatorProvider.getDictionaryFacilitator(
+ true /* isNeededForSpellChecking */);
}
private static void waitForLoadingMainDictionary(
@@ -64,11 +65,14 @@ public class DictionaryFacilitatorLruCache {
}
private void resetDictionariesForLocaleLocked() {
- // Note: Given that personalized dictionaries are not used here; we can pass null account.
- mDictionaryFacilitator.resetDictionaries(mContext, new Locale[]{mLocale},
- mUseContactsDictionary, false /* usePersonalizedDicts */,
- false /* forceReloadMainDictionary */, null /* account */,
- mDictionaryNamePrefix, null /* listener */);
+ // Nothing to do if the locale is null. This would be the case before any get() calls.
+ if (mLocale != null) {
+ // Note: Given that personalized dictionaries are not used here; we can pass null account.
+ mDictionaryFacilitator.resetDictionaries(mContext, new Locale[]{mLocale},
+ mUseContactsDictionary, false /* usePersonalizedDicts */,
+ false /* forceReloadMainDictionary */, null /* account */,
+ mDictionaryNamePrefix, null /* listener */);
+ }
}
public void setUseContactsDictionary(final boolean useContactsDictionary) {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 781ab06c5..49608d830 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -80,7 +80,7 @@ public final class DictionaryFactory {
* @param context The context to contact the dictionary provider, if possible.
* @param f A file address to the dictionary to kill.
*/
- private static void killDictionary(final Context context, final AssetFileAddress f) {
+ public static void killDictionary(final Context context, final AssetFileAddress f) {
if (f.pointsToPhysicalFile()) {
f.deleteUnderlyingFile();
// Warn the dictionary provider if the dictionary came from there.
diff --git a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
index 8116a4983..9b271116d 100644
--- a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
+++ b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import android.util.Log;
import android.view.KeyEvent;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
@@ -25,10 +26,18 @@ import com.android.inputmethod.latin.settings.Settings;
* A class for detecting Emoji-Alt physical key.
*/
final class EmojiAltPhysicalKeyDetector {
+ private static final String TAG = "EmojiAltPhysicalKeyDetector";
+
+ private final RichInputConnection mRichInputConnection;
+
// True if the Alt key has been used as a modifier. In this case the Alt key up isn't
// recognized as an emoji key.
private boolean mAltHasBeenUsedAsAModifier;
+ public EmojiAltPhysicalKeyDetector(final RichInputConnection richInputConnection) {
+ mRichInputConnection = richInputConnection;
+ }
+
/**
* Record a down key event.
* @param keyEvent a down key event.
@@ -62,9 +71,14 @@ final class EmojiAltPhysicalKeyDetector {
if (!Settings.getInstance().getCurrent().mEnableEmojiAltPhysicalKey) {
return;
}
- if (!mAltHasBeenUsedAsAModifier) {
- onEmojiAltKeyDetected();
+ if (mAltHasBeenUsedAsAModifier) {
+ return;
+ }
+ if (!mRichInputConnection.isConnected()) {
+ Log.w(TAG, "onKeyUp() : No connection to text view");
+ return;
}
+ onEmojiAltKeyDetected();
}
private static void onEmojiAltKeyDetected() {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 064d79b3c..b0fb91bec 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -259,7 +259,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/**
* Check whether GC is needed and run GC if required.
*/
- protected void runGCIfRequired(final boolean mindsBlockByGC) {
+ public void runGCIfRequired(final boolean mindsBlockByGC) {
asyncExecuteTaskWithWriteLock(new Runnable() {
@Override
public void run() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 550efa59f..76d4a4a8d 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -73,7 +73,6 @@ import com.android.inputmethod.latin.common.InputPointers;
import com.android.inputmethod.latin.define.DebugFlags;
import com.android.inputmethod.latin.define.ProductionFlags;
import com.android.inputmethod.latin.inputlogic.InputLogic;
-import com.android.inputmethod.latin.personalization.DictionaryDecayBroadcastReciever;
import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.settings.SettingsActivity;
@@ -127,7 +126,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Settings mSettings;
private final DictionaryFacilitator mDictionaryFacilitator =
- DictionaryFacilitatorProvider.getDictionaryFacilitator();
+ DictionaryFacilitatorProvider.getDictionaryFacilitator(
+ false /* isNeededForSpellChecking */);
final InputLogic mInputLogic = new InputLogic(this /* LatinIME */,
this /* SuggestionStripViewAccessor */, mDictionaryFacilitator);
// We expect to have only one decoder in almost all cases, hence the default capacity of 1.
@@ -143,7 +143,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
private final EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector =
- new EmojiAltPhysicalKeyDetector();
+ new EmojiAltPhysicalKeyDetector(mInputLogic.mConnection);
private StatsUtilsManager mStatsUtilsManager;
// Working variable for {@link #startShowingInputView()} and
// {@link #onEvaluateInputViewShown()}.
@@ -584,7 +584,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
dictDumpFilter.addAction(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION);
registerReceiver(mDictionaryDumpBroadcastReceiver, dictDumpFilter);
- DictionaryDecayBroadcastReciever.setUpIntervalAlarmForDictionaryDecaying(this);
StatsUtils.onCreate(mSettings.getCurrent(), mRichImm);
}
@@ -704,7 +703,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
unregisterReceiver(mDictionaryPackInstallReceiver);
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
mStatsUtilsManager.onDestroy(this /* context */);
- DictionaryDecayBroadcastReciever.cancelIntervalAlarmForDictionaryDecaying(this);
super.onDestroy();
}
@@ -1514,9 +1512,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
callback.onGetSuggestedWords(SuggestedWords.getEmptyInstance());
return;
}
- mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard.getProximityInfo(),
- mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback,
- keyboard.getKeyboardLayout());
+ mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard,
+ mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 0210d7e18..08e8fe346 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -101,12 +101,17 @@ public final class RichInputConnection implements PrivateCommandPerformer {
private final InputMethodService mParent;
InputConnection mIC;
int mNestLevel;
+
public RichInputConnection(final InputMethodService parent) {
mParent = parent;
mIC = null;
mNestLevel = 0;
}
+ public boolean isConnected() {
+ return mIC != null;
+ }
+
private void checkConsistencyForDebug() {
final ExtractedTextRequest r = new ExtractedTextRequest();
r.hintMaxChars = 0;
@@ -142,7 +147,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public void beginBatchEdit() {
if (++mNestLevel == 1) {
mIC = mParent.getCurrentInputConnection();
- if (null != mIC) {
+ if (isConnected()) {
mIC.beginBatchEdit();
}
} else {
@@ -157,7 +162,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public void endBatchEdit() {
if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
- if (--mNestLevel == 0 && null != mIC) {
+ if (--mNestLevel == 0 && isConnected()) {
mIC.endBatchEdit();
}
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -189,7 +194,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
Log.d(TAG, "Will try to retrieve text later.");
return false;
}
- if (null != mIC && shouldFinishComposition) {
+ if (isConnected() && shouldFinishComposition) {
mIC.finishComposingText();
}
return true;
@@ -205,8 +210,9 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mIC = mParent.getCurrentInputConnection();
// Call upon the inputconnection directly since our own method is using the cache, and
// we want to refresh it.
- final CharSequence textBeforeCursor = null == mIC ? null :
- mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
+ final CharSequence textBeforeCursor = isConnected()
+ ? mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE, 0)
+ : null;
if (null == textBeforeCursor) {
// For some reason the app thinks we are not connected to it. This looks like a
// framework bug... Fall back to ground state and return false.
@@ -235,7 +241,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
// it works, but it's wrong and should be fixed.
mCommittedTextBeforeComposingText.append(mComposingText);
mComposingText.setLength(0);
- if (null != mIC) {
+ if (isConnected()) {
mIC.finishComposingText();
}
}
@@ -256,7 +262,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mExpectedSelStart += text.length() - mComposingText.length();
mExpectedSelEnd = mExpectedSelStart;
mComposingText.setLength(0);
- if (null != mIC) {
+ if (isConnected()) {
mTempObjectForCommitText.clear();
mTempObjectForCommitText.append(text);
final CharacterStyle[] spans = mTempObjectForCommitText.getSpans(
@@ -283,7 +289,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
}
public CharSequence getSelectedText(final int flags) {
- return (null == mIC) ? null : mIC.getSelectedText(flags);
+ return isConnected() ? mIC.getSelectedText(flags) : null;
}
public boolean canDeleteCharacters() {
@@ -308,7 +314,9 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public int getCursorCapsMode(final int inputType,
final SpacingAndPunctuations spacingAndPunctuations, final boolean hasSpaceBefore) {
mIC = mParent.getCurrentInputConnection();
- if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF;
+ if (!isConnected()) {
+ return Constants.TextUtils.CAP_MODE_OFF;
+ }
if (!TextUtils.isEmpty(mComposingText)) {
if (hasSpaceBefore) {
// If we have some composing text and a space before, then we should have
@@ -368,12 +376,12 @@ public final class RichInputConnection implements PrivateCommandPerformer {
return s;
}
mIC = mParent.getCurrentInputConnection();
- return (null == mIC) ? null : mIC.getTextBeforeCursor(n, flags);
+ return isConnected() ? mIC.getTextBeforeCursor(n, flags) : null;
}
public CharSequence getTextAfterCursor(final int n, final int flags) {
mIC = mParent.getCurrentInputConnection();
- return (null == mIC) ? null : mIC.getTextAfterCursor(n, flags);
+ return isConnected() ? mIC.getTextAfterCursor(n, flags) : null;
}
public void deleteSurroundingText(final int beforeLength, final int afterLength) {
@@ -400,7 +408,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mExpectedSelEnd -= mExpectedSelStart;
mExpectedSelStart = 0;
}
- if (null != mIC) {
+ if (isConnected()) {
mIC.deleteSurroundingText(beforeLength, afterLength);
}
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -408,7 +416,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public void performEditorAction(final int actionId) {
mIC = mParent.getCurrentInputConnection();
- if (null != mIC) {
+ if (isConnected()) {
mIC.performEditorAction(actionId);
}
}
@@ -460,7 +468,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
break;
}
}
- if (null != mIC) {
+ if (isConnected()) {
mIC.sendKeyEvent(keyEvent);
}
}
@@ -483,7 +491,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mCommittedTextBeforeComposingText.append(
textBeforeCursor.subSequence(0, indexOfStartOfComposingText));
}
- if (null != mIC) {
+ if (isConnected()) {
mIC.setComposingRegion(start, end);
}
}
@@ -497,7 +505,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mComposingText.append(text);
// TODO: support values of newCursorPosition != 1. At this time, this is never called with
// newCursorPosition != 1.
- if (null != mIC) {
+ if (isConnected()) {
mIC.setComposingText(text, newCursorPosition);
}
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -522,7 +530,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
}
mExpectedSelStart = start;
mExpectedSelEnd = end;
- if (null != mIC) {
+ if (isConnected()) {
final boolean isIcValid = mIC.setSelection(start, end);
if (!isIcValid) {
return false;
@@ -536,7 +544,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
// This has no effect on the text field and does not change its content. It only makes
// TextView flash the text for a second based on indices contained in the argument.
- if (null != mIC) {
+ if (isConnected()) {
mIC.commitCorrection(correctionInfo);
}
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -552,7 +560,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mExpectedSelStart += text.length() - mComposingText.length();
mExpectedSelEnd = mExpectedSelStart;
mComposingText.setLength(0);
- if (null != mIC) {
+ if (isConnected()) {
mIC.commitCompletion(completionInfo);
}
if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
@@ -563,7 +571,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public NgramContext getNgramContextFromNthPreviousWord(
final SpacingAndPunctuations spacingAndPunctuations, final int n) {
mIC = mParent.getCurrentInputConnection();
- if (null == mIC) {
+ if (!isConnected()) {
return NgramContext.EMPTY_PREV_WORDS_INFO;
}
final CharSequence prev = getTextBeforeCursor(LOOKBACK_CHARACTER_NUM, 0);
@@ -608,7 +616,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public TextRange getWordRangeAtCursor(final SpacingAndPunctuations spacingAndPunctuations,
final int scriptId) {
mIC = mParent.getCurrentInputConnection();
- if (mIC == null) {
+ if (!isConnected()) {
return null;
}
final CharSequence before = mIC.getTextBeforeCursor(Constants.EDITOR_CONTENTS_CACHE_SIZE,
@@ -824,7 +832,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
mIC = mParent.getCurrentInputConnection();
final CharSequence textBeforeCursor = getTextBeforeCursor(
Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
- final CharSequence selectedText = null == mIC ? null : mIC.getSelectedText(0 /* flags */);
+ final CharSequence selectedText = isConnected() ? mIC.getSelectedText(0 /* flags */) : null;
if (null == textBeforeCursor ||
(!TextUtils.isEmpty(selectedText) && mExpectedSelEnd == mExpectedSelStart)) {
// If textBeforeCursor is null, we have no idea what kind of text field we have or if
@@ -863,7 +871,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
@Override
public boolean performPrivateCommand(final String action, final Bundle data) {
mIC = mParent.getCurrentInputConnection();
- if (mIC == null) {
+ if (!isConnected()) {
return false;
}
return mIC.performPrivateCommand(action, data);
@@ -923,7 +931,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
public boolean requestCursorUpdates(final boolean enableMonitor,
final boolean requestImmediateCallback) {
mIC = mParent.getCurrentInputConnection();
- if (mIC == null) {
+ if (!isConnected()) {
return false;
}
return InputConnectionCompatUtils.requestCursorUpdates(
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index ddb2b5358..f4680fc88 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -18,8 +18,9 @@ package com.android.inputmethod.latin;
import android.text.TextUtils;
-import com.android.inputmethod.keyboard.KeyboardLayout;
-import com.android.inputmethod.keyboard.ProximityInfo;
+import static com.android.inputmethod.latin.define.DecoderSpecificConstants.SHOULD_AUTO_CORRECT_USING_NON_WHITE_LISTED_SUGGESTION;
+
+import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.StringUtils;
@@ -95,19 +96,17 @@ public final class Suggest {
}
public void getSuggestedWords(final WordComposer wordComposer,
- final NgramContext ngramContext, final ProximityInfo proximityInfo,
+ final NgramContext ngramContext, final Keyboard keyboard,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
final boolean isCorrectionEnabled, final int inputStyle, final int sequenceNumber,
- final OnGetSuggestedWordsCallback callback,
- final KeyboardLayout keyboardLayout) {
+ final OnGetSuggestedWordsCallback callback) {
if (wordComposer.isBatchMode()) {
- getSuggestedWordsForBatchInput(wordComposer, ngramContext, proximityInfo,
- settingsValuesForSuggestion, inputStyle, sequenceNumber, callback,
- keyboardLayout);
+ getSuggestedWordsForBatchInput(wordComposer, ngramContext, keyboard,
+ settingsValuesForSuggestion, inputStyle, sequenceNumber, callback);
} else {
- getSuggestedWordsForNonBatchInput(wordComposer, ngramContext, proximityInfo,
+ getSuggestedWordsForNonBatchInput(wordComposer, ngramContext, keyboard,
settingsValuesForSuggestion, inputStyle, isCorrectionEnabled,
- sequenceNumber, callback, keyboardLayout);
+ sequenceNumber, callback);
}
}
@@ -163,11 +162,10 @@ public final class Suggest {
// Retrieves suggestions for non-batch input (typing, recorrection, predictions...)
// and calls the callback function with the suggestions.
private void getSuggestedWordsForNonBatchInput(final WordComposer wordComposer,
- final NgramContext ngramContext, final ProximityInfo proximityInfo,
+ final NgramContext ngramContext, final Keyboard keyboard,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
final int inputStyleIfNotPrediction, final boolean isCorrectionEnabled,
- final int sequenceNumber, final OnGetSuggestedWordsCallback callback,
- final KeyboardLayout keyboardLayout) {
+ final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
final String typedWordString = wordComposer.getTypedWord();
final int trailingSingleQuotesCount =
StringUtils.getTrailingSingleQuotesCount(typedWordString);
@@ -176,9 +174,8 @@ public final class Suggest {
: typedWordString;
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
- wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(),
- settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction,
- keyboardLayout);
+ wordComposer.getComposedDataSnapshot(), ngramContext, keyboard,
+ settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction);
final Locale mostProbableLocale = mDictionaryFacilitator.getMostProbableLocale();
final ArrayList<SuggestedWordInfo> suggestionsContainer =
getTransformedSuggestedWordInfoList(wordComposer, suggestionResults,
@@ -213,7 +210,8 @@ public final class Suggest {
}
}
- SuggestedWordInfo.removeDups(typedWordString, suggestionsContainer);
+ final int firstOcurrenceOfTypedWordInSuggestions =
+ SuggestedWordInfo.removeDups(typedWordString, suggestionsContainer);
final SuggestedWordInfo whitelistedWordInfo =
getWhitelistedWordInfoOrNull(suggestionsContainer);
@@ -236,10 +234,11 @@ public final class Suggest {
}
final boolean resultsArePredictions = !wordComposer.isComposingWord();
- // We allow auto-correction if we have a whitelisted word, or if the word had more than
- // one char and was not suggested.
- final boolean allowsToBeAutoCorrected = (null != whitelistedWord)
- || (consideredWord.length() > 1 && (null == sourceDictionaryOfRemovedWord));
+ // We allow auto-correction if whitelisting is not required or the word is whitelisted,
+ // or if the word had more than one char and was not suggested.
+ final boolean allowsToBeAutoCorrected =
+ (SHOULD_AUTO_CORRECT_USING_NON_WHITE_LISTED_SUGGESTION || whitelistedWord != null)
+ || (consideredWord.length() > 1 && (sourceDictionaryOfRemovedWord == null));
final boolean hasAutoCorrection;
// If correction is not enabled, we never auto-correct. This is for example for when
@@ -275,7 +274,8 @@ public final class Suggest {
hasAutoCorrection = false;
} else {
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
- if (suggestionResults.mAutocorrectRecommendation) {
+ if (suggestionResults.mFirstSuggestionExceedsConfidenceThreshold
+ && firstOcurrenceOfTypedWordInSuggestions != 0) {
hasAutoCorrection = true;
} else if (!AutoCorrectionUtils.suggestionExceedsThreshold(
firstSuggestion, consideredWord, mAutoCorrectionThreshold)) {
@@ -316,12 +316,12 @@ public final class Suggest {
} else {
inputStyle = inputStyleIfNotPrediction;
}
+
+ final boolean isTypedWordValid = firstOcurrenceOfTypedWordInSuggestions > -1
+ || (!resultsArePredictions && !allowsToBeAutoCorrected);
callback.onGetSuggestedWords(new SuggestedWords(suggestionsList,
suggestionResults.mRawSuggestions, typedWordInfo,
- // TODO: this first argument is lying. If this is a whitelisted word which is an
- // actual word, it says typedWordValid = false, which looks wrong. We should either
- // rename the attribute or change the value.
- !resultsArePredictions && !allowsToBeAutoCorrected /* typedWordValid */,
+ isTypedWordValid,
hasAutoCorrection /* willAutoCorrect */,
false /* isObsoleteSuggestions */, inputStyle, sequenceNumber));
}
@@ -343,14 +343,13 @@ public final class Suggest {
// Retrieves suggestions for the batch input
// and calls the callback function with the suggestions.
private void getSuggestedWordsForBatchInput(final WordComposer wordComposer,
- final NgramContext ngramContext, final ProximityInfo proximityInfo,
+ final NgramContext ngramContext, final Keyboard keyboard,
final SettingsValuesForSuggestion settingsValuesForSuggestion,
final int inputStyle, final int sequenceNumber,
- final OnGetSuggestedWordsCallback callback,
- final KeyboardLayout keyboardLayout) {
+ final OnGetSuggestedWordsCallback callback) {
final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults(
- wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(),
- settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle, keyboardLayout);
+ wordComposer.getComposedDataSnapshot(), ngramContext, keyboard,
+ settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle);
// For transforming words that don't come from a dictionary, because it's our best bet
final Locale defaultLocale = mDictionaryFacilitator.getMostProbableLocale();
final ArrayList<SuggestedWordInfo> suggestionsContainer =
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 913b63a61..3816c0870 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -17,6 +17,7 @@
package com.android.inputmethod.latin;
import android.text.TextUtils;
+import android.util.Log;
import android.view.inputmethod.CompletionInfo;
import com.android.inputmethod.annotations.UsedForTesting;
@@ -375,31 +376,45 @@ public class SuggestedWords {
return mWord + " (" + mDebugString + ")";
}
- // This will always remove the higher index if a duplicate is found.
- public static void removeDups(@Nullable final String typedWord,
- @Nonnull ArrayList<SuggestedWordInfo> candidates) {
+ /**
+ * This will always remove the higher index if a duplicate is found.
+ *
+ * @return position of typed word in the candidate list
+ */
+ public static int removeDups(
+ @Nullable final String typedWord,
+ @Nonnull final ArrayList<SuggestedWordInfo> candidates) {
if (candidates.isEmpty()) {
- return;
+ return -1;
}
+ int firstOccurrenceOfWord = -1;
if (!TextUtils.isEmpty(typedWord)) {
- removeSuggestedWordInfoFromList(typedWord, candidates, -1 /* startIndexExclusive */);
+ firstOccurrenceOfWord = removeSuggestedWordInfoFromList(
+ typedWord, candidates, -1 /* startIndexExclusive */);
}
for (int i = 0; i < candidates.size(); ++i) {
- removeSuggestedWordInfoFromList(candidates.get(i).mWord, candidates,
- i /* startIndexExclusive */);
+ removeSuggestedWordInfoFromList(
+ candidates.get(i).mWord, candidates, i /* startIndexExclusive */);
}
+ return firstOccurrenceOfWord;
}
- private static void removeSuggestedWordInfoFromList(
- @Nonnull final String word, @Nonnull final ArrayList<SuggestedWordInfo> candidates,
+ private static int removeSuggestedWordInfoFromList(
+ @Nonnull final String word,
+ @Nonnull final ArrayList<SuggestedWordInfo> candidates,
final int startIndexExclusive) {
+ int firstOccurrenceOfWord = -1;
for (int i = startIndexExclusive + 1; i < candidates.size(); ++i) {
final SuggestedWordInfo previous = candidates.get(i);
if (word.equals(previous.mWord)) {
+ if (firstOccurrenceOfWord == -1) {
+ firstOccurrenceOfWord = i;
+ }
candidates.remove(i);
--i;
}
}
+ return firstOccurrenceOfWord;
}
}
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 56be23f5b..7907aaa16 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -32,9 +32,8 @@ import android.view.inputmethod.EditorInfo;
import com.android.inputmethod.compat.SuggestionSpanUtils;
import com.android.inputmethod.event.Event;
import com.android.inputmethod.event.InputTransaction;
-import com.android.inputmethod.keyboard.KeyboardLayout;
+import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
-import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.DictionaryFacilitator;
import com.android.inputmethod.latin.LastComposedWord;
@@ -1094,8 +1093,8 @@ public final class InputLogic {
int totalDeletedLength = 1;
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
// If this is an accelerated (i.e., double) deletion, then we need to
- // consider unlearning here too because we may have just entered the
- // previous word, and the next deletion will currupt it.
+ // consider unlearning here because we may have already reached
+ // the previous word, and will lose it after next deletion.
hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted(
inputTransaction.mSettingsValues, currentKeyboardScriptId);
sendDownUpKeyEvent(KeyEvent.KEYCODE_DEL);
@@ -1121,8 +1120,8 @@ public final class InputLogic {
int totalDeletedLength = lengthToDelete;
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
// If this is an accelerated (i.e., double) deletion, then we need to
- // consider unlearning here too because we may have just entered the
- // previous word, and the next deletion will currupt it.
+ // consider unlearning here because we may have already reached
+ // the previous word, and will lose it after next deletion.
hasUnlearnedWordBeingDeleted |= unlearnWordBeingDeleted(
inputTransaction.mSettingsValues, currentKeyboardScriptId);
final int codePointBeforeCursorToDeleteAgain =
@@ -1166,6 +1165,11 @@ public final class InputLogic {
final TextRange range = mConnection.getWordRangeAtCursor(
settingsValues.mSpacingAndPunctuations,
currentKeyboardScriptId);
+ if (range == null) {
+ // TODO(zivkovic): Check for bad connection before getting this far.
+ // Happens if we don't have an input connection at all.
+ return false;
+ }
final String wordBeingDeleted = range.mWord.toString();
if (!wordBeingDeleted.isEmpty()) {
unlearnWord(wordBeingDeleted, settingsValues,
@@ -1179,7 +1183,7 @@ public final class InputLogic {
void unlearnWord(final String word, final SettingsValues settingsValues, final int eventType) {
final NgramContext ngramContext = mConnection.getNgramContextFromNthPreviousWord(
settingsValues.mSpacingAndPunctuations, 2);
- final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds(
+ final long timeStampInSeconds = TimeUnit.MILLISECONDS.toSeconds(
System.currentTimeMillis());
mDictionaryFacilitator.unlearnFromUserHistory(
word, ngramContext, timeStampInSeconds, eventType);
@@ -2160,9 +2164,8 @@ public final class InputLogic {
}
public void getSuggestedWords(final SettingsValues settingsValues,
- final ProximityInfo proximityInfo, final int keyboardShiftMode, final int inputStyle,
- final int sequenceNumber, final OnGetSuggestedWordsCallback callback,
- final KeyboardLayout keyboardLayout) {
+ final Keyboard keyboard, final int keyboardShiftMode, final int inputStyle,
+ final int sequenceNumber, final OnGetSuggestedWordsCallback callback) {
mWordComposer.adviseCapitalizedModeBeforeFetchingSuggestions(
getActualCapsMode(settingsValues, keyboardShiftMode));
mSuggest.getSuggestedWords(mWordComposer,
@@ -2172,11 +2175,11 @@ public final class InputLogic {
// a word, it's whatever is *before* the half-committed word in the buffer,
// hence 2; if we aren't, we should just skip whitespace if any, so 1.
mWordComposer.isComposingWord() ? 2 : 1),
- proximityInfo,
+ keyboard,
new SettingsValuesForSuggestion(settingsValues.mBlockPotentiallyOffensive,
settingsValues.mPhraseGestureEnabled),
settingsValues.mAutoCorrectionEnabledPerUserSettings,
- inputStyle, sequenceNumber, callback, keyboardLayout);
+ inputStyle, sequenceNumber, callback);
}
/**
diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
deleted file mode 100644
index 78b51d9f4..000000000
--- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java
+++ /dev/null
@@ -1,85 +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.latin.personalization;
-
-import android.content.Context;
-
-import com.android.inputmethod.latin.Dictionary;
-import com.android.inputmethod.latin.ExpandableBinaryDictionary;
-import com.android.inputmethod.latin.makedict.DictionaryHeader;
-
-import java.io.File;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * This class is a base class of a dictionary that supports decaying for the personalized language
- * model.
- */
-public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableBinaryDictionary {
- private static final boolean DBG_DUMP_ON_CLOSE = false;
-
- /** Any pair being typed or picked */
- public static final int FREQUENCY_FOR_TYPED = 2;
-
- public static final int FREQUENCY_FOR_WORDS_IN_DICTS = FREQUENCY_FOR_TYPED;
- public static final int FREQUENCY_FOR_WORDS_NOT_IN_DICTS = Dictionary.NOT_A_PROBABILITY;
-
- protected DecayingExpandableBinaryDictionaryBase(final Context context,
- final String dictName, final Locale locale, final String dictionaryType,
- final File dictFile) {
- super(context, dictName, locale, dictionaryType, dictFile);
- if (mLocale != null && mLocale.toString().length() > 1) {
- reloadDictionaryIfRequired();
- }
- }
-
- @Override
- public void close() {
- if (DBG_DUMP_ON_CLOSE) {
- dumpAllWordsForDebug();
- }
- // Flush pending writes.
- asyncFlushBinaryDictionary();
- super.close();
- }
-
- @Override
- protected Map<String, String> getHeaderAttributeMap() {
- final Map<String, String> attributeMap = super.getHeaderAttributeMap();
- attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY,
- DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
- attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY,
- DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
- return attributeMap;
- }
-
- @Override
- protected void loadInitialContentsLocked() {
- // No initial contents.
- }
-
- /* package */ void runGCIfRequired() {
- runGCIfRequired(false /* mindsBlockByGC */);
- }
-
- @Override
- public boolean isValidWord(final String word) {
- // Strings out of this dictionary should not be considered existing words.
- return false;
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java
deleted file mode 100644
index 0c5e5d010..000000000
--- a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java
+++ /dev/null
@@ -1,89 +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.latin.personalization;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * Broadcast receiver for periodically updating decaying dictionaries.
- */
-public class DictionaryDecayBroadcastReciever extends BroadcastReceiver {
- /**
- * The root domain for the personalization.
- */
- private static final String PERSONALIZATION_DOMAIN =
- "com.android.inputmethod.latin.personalization";
-
- /**
- * The action of the intent to tell the time to decay dictionaries.
- */
- private static final String DICTIONARY_DECAY_INTENT_ACTION =
- PERSONALIZATION_DOMAIN + ".DICT_DECAY";
-
- /**
- * Interval to update for decaying dictionaries.
- */
- static final long DICTIONARY_DECAY_INTERVAL_IN_MILLIS = TimeUnit.MINUTES.toMillis(60);
-
- private static PendingIntent getPendingIntentForDictionaryDecay(final Context context) {
- final Intent updateIntent = new Intent(DICTIONARY_DECAY_INTENT_ACTION);
- updateIntent.setClass(context, DictionaryDecayBroadcastReciever.class);
- return PendingIntent.getBroadcast(context, 0 /* requestCode */,
- updateIntent, PendingIntent.FLAG_CANCEL_CURRENT);
- }
-
- /**
- * Set up interval alarm for dynamic dictionaries.
- */
- public static void setUpIntervalAlarmForDictionaryDecaying(final Context context) {
- final AlarmManager alarmManager =
- (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
- if (null == alarmManager) {
- return;
- }
- final long alarmTriggerTimeInMillis =
- System.currentTimeMillis() + DICTIONARY_DECAY_INTERVAL_IN_MILLIS;
- alarmManager.setInexactRepeating(AlarmManager.RTC, alarmTriggerTimeInMillis,
- DICTIONARY_DECAY_INTERVAL_IN_MILLIS, getPendingIntentForDictionaryDecay(context));
- }
-
- /**
- * Cancel interval alarm that has been set up.
- */
- public static void cancelIntervalAlarmForDictionaryDecaying(final Context context) {
- final AlarmManager alarmManager =
- (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
- if (null == alarmManager) {
- return;
- }
- alarmManager.cancel(getPendingIntentForDictionaryDecay(context));
- }
-
- @Override
- public void onReceive(final Context context, final Intent intent) {
- final String action = intent.getAction();
- if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) {
- PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries();
- }
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
index 1c1cb4f95..298e46c0a 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -26,7 +26,6 @@ import java.io.FilenameFilter;
import java.lang.ref.SoftReference;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -68,60 +67,28 @@ public class PersonalizationHelper {
}
}
- private static int sCurrentTimestampForTesting = 0;
- public static void currentTimeChangedForTesting(final int currentTimestamp) {
- if (TimeUnit.MILLISECONDS.toSeconds(
- DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL_IN_MILLIS)
- < currentTimestamp - sCurrentTimestampForTesting) {
- runGCOnAllOpenedUserHistoryDictionaries();
- }
- }
-
- public static void runGCOnAllOpenedUserHistoryDictionaries() {
- runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache);
- }
-
- private static <T extends DecayingExpandableBinaryDictionaryBase>
- void runGCOnAllDictionariesIfRequired(
- final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) {
- for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry
- : dictionaryMap.entrySet()) {
- final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get();
- if (dict != null) {
- dict.runGCIfRequired();
- } else {
- dictionaryMap.remove(entry.getKey());
- }
- }
- }
-
public static void removeAllUserHistoryDictionaries(final Context context) {
- removeAllDictionaries(context, sLangUserHistoryDictCache,
- UserHistoryDictionary.NAME);
- }
-
- private static <T extends DecayingExpandableBinaryDictionaryBase> void removeAllDictionaries(
- final Context context, final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap,
- final String dictNamePrefix) {
- synchronized (dictionaryMap) {
- for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry
- : dictionaryMap.entrySet()) {
+ synchronized (sLangUserHistoryDictCache) {
+ for (final ConcurrentHashMap.Entry<String, SoftReference<UserHistoryDictionary>> entry
+ : sLangUserHistoryDictCache.entrySet()) {
if (entry.getValue() != null) {
- final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get();
+ final UserHistoryDictionary dict = entry.getValue().get();
if (dict != null) {
dict.clear();
}
}
}
- dictionaryMap.clear();
+ sLangUserHistoryDictCache.clear();
final File filesDir = context.getFilesDir();
if (filesDir == null) {
Log.e(TAG, "context.getFilesDir() returned null.");
return;
}
- if (!FileUtils.deleteFilteredFiles(filesDir, new DictFilter(dictNamePrefix))) {
- Log.e(TAG, "Cannot remove all existing dictionary files. filesDir: "
- + filesDir.getAbsolutePath() + ", dictNamePrefix: " + dictNamePrefix);
+ final boolean filesDeleted = FileUtils.deleteFilteredFiles(
+ filesDir, new DictFilter(UserHistoryDictionary.NAME));
+ if (!filesDeleted) {
+ Log.e(TAG, "Cannot remove dictionary files. filesDir: " + filesDir.getAbsolutePath()
+ + ", dictNamePrefix: " + UserHistoryDictionary.NAME);
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
index b6286b203..54ee68d65 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -25,9 +25,11 @@ import com.android.inputmethod.latin.ExpandableBinaryDictionary;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.define.DecoderSpecificConstants;
import com.android.inputmethod.latin.define.ProductionFlags;
+import com.android.inputmethod.latin.makedict.DictionaryHeader;
import java.io.File;
import java.util.Locale;
+import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -37,17 +39,16 @@ import javax.annotation.Nullable;
* auto-correction cancellation or manual picks. This allows the keyboard to adapt to the
* typist over time.
*/
-public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase {
+public class UserHistoryDictionary extends ExpandableBinaryDictionary {
static final String NAME = UserHistoryDictionary.class.getSimpleName();
// TODO: Make this constructor private
UserHistoryDictionary(final Context context, final Locale locale,
@Nullable final String account) {
- super(context,
- getUserHistoryDictName(NAME, locale, null /* dictFile */, account),
- locale,
- Dictionary.TYPE_USER_HISTORY,
- null /* dictFile */);
+ super(context, getUserHistoryDictName(NAME, locale, null /* dictFile */, account), locale, Dictionary.TYPE_USER_HISTORY, null);
+ if (mLocale != null && mLocale.toString().length() > 1) {
+ reloadDictionaryIfRequired();
+ }
}
/**
@@ -103,4 +104,32 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas
userHistoryDictionary.updateEntriesForWord(ngramContext, word,
isValid, 1 /* count */, timestamp);
}
+
+ @Override
+ public void close() {
+ // Flush pending writes.
+ asyncFlushBinaryDictionary();
+ super.close();
+ }
+
+ @Override
+ protected Map<String, String> getHeaderAttributeMap() {
+ final Map<String, String> attributeMap = super.getHeaderAttributeMap();
+ attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY,
+ DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
+ attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY,
+ DictionaryHeader.ATTRIBUTE_VALUE_TRUE);
+ return attributeMap;
+ }
+
+ @Override
+ protected void loadInitialContentsLocked() {
+ // No initial contents.
+ }
+
+ @Override
+ public boolean isValidWord(final String word) {
+ // Strings out of this dictionary should not be considered existing words.
+ return false;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index d35d1f2f5..f04f093f0 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -28,26 +28,26 @@ import android.util.Log;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.keyboard.KeyboardLayout;
import com.android.inputmethod.keyboard.KeyboardLayoutSet;
-import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.DictionaryFacilitator;
import com.android.inputmethod.latin.DictionaryFacilitatorLruCache;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodSubtype;
import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.common.ComposedData;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
import com.android.inputmethod.latin.utils.ScriptUtils;
import com.android.inputmethod.latin.utils.SuggestionResults;
-import com.android.inputmethod.latin.WordComposer;
import java.util.Locale;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
+import javax.annotation.Nonnull;
+
/**
* Service for spell checking, using LatinIME's dictionaries and mechanisms.
*/
@@ -191,18 +191,18 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
}
}
- public SuggestionResults getSuggestionResults(final Locale locale, final WordComposer composer,
- final NgramContext ngramContext, final ProximityInfo proximityInfo,
- final KeyboardLayout keyboardLayout) {
+ public SuggestionResults getSuggestionResults(final Locale locale,
+ final ComposedData composedData, final NgramContext ngramContext,
+ @Nonnull final Keyboard keyboard) {
Integer sessionId = null;
mSemaphore.acquireUninterruptibly();
try {
sessionId = mSessionIdPool.poll();
DictionaryFacilitator dictionaryFacilitatorForLocale =
mDictionaryFacilitatorCache.get(locale);
- return dictionaryFacilitatorForLocale.getSuggestionResults(composer, ngramContext,
- proximityInfo.getNativeProximityInfo(), mSettingsValuesForSuggestion,
- sessionId, SuggestedWords.INPUT_STYLE_TYPING, keyboardLayout);
+ return dictionaryFacilitatorForLocale.getSuggestionResults(composedData, ngramContext,
+ keyboard, mSettingsValuesForSuggestion,
+ sessionId, SuggestedWords.INPUT_STYLE_TYPING);
} finally {
if (sessionId != null) {
mSessionIdPool.add(sessionId);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 0b5e12f03..5c1915c6c 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -29,13 +29,10 @@ import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardLayout;
-import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.NgramContext;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.WordComposer;
import com.android.inputmethod.latin.common.Constants;
-import com.android.inputmethod.latin.common.CoordinateUtils;
import com.android.inputmethod.latin.common.LocaleUtils;
import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
@@ -268,25 +265,20 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
false /* reportAsTypo */);
}
final Keyboard keyboard = mService.getKeyboardForLocale(mLocale);
+ if (null == keyboard) {
+ Log.d(TAG, "No keyboard for locale: " + mLocale);
+ // If there is no keyboard for this locale, don't do any spell-checking.
+ return AndroidSpellCheckerService.getNotInDictEmptySuggestions(
+ false /* reportAsTypo */);
+ }
final WordComposer composer = new WordComposer();
final int[] codePoints = StringUtils.toCodePointArray(text);
final int[] coordinates;
- final ProximityInfo proximityInfo;
- final KeyboardLayout keyboardLayout;
- if (null == keyboard) {
- coordinates = CoordinateUtils.newCoordinateArray(codePoints.length,
- Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- proximityInfo = null;
- keyboardLayout = null;
- } else {
- coordinates = keyboard.getCoordinates(codePoints);
- proximityInfo = keyboard.getProximityInfo();
- keyboardLayout = keyboard.getKeyboardLayout();
- }
+ coordinates = keyboard.getCoordinates(codePoints);
composer.setComposingWord(codePoints, coordinates);
// TODO: Don't gather suggestions if the limit is <= 0 unless necessary
final SuggestionResults suggestionResults = mService.getSuggestionResults(
- mLocale, composer, ngramContext, proximityInfo, keyboardLayout);
+ mLocale, composer.getComposedDataSnapshot(), ngramContext, keyboard);
final Result result = getResult(capitalizeType, mLocale, suggestionsLimit,
mService.getRecommendedThreshold(), text, suggestionResults);
isInDict = isInDictForAnyCapitalization(text, capitalizeType);
diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
index 23ffde2a2..892b967c4 100644
--- a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
@@ -21,7 +21,6 @@ import com.android.inputmethod.latin.BinaryDictionary;
import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.makedict.DictionaryHeader;
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
-import com.android.inputmethod.latin.personalization.PersonalizationHelper;
import java.io.File;
import java.io.IOException;
@@ -123,8 +122,6 @@ public final class BinaryDictionaryUtils {
*/
@UsedForTesting
public static int setCurrentTimeForTest(final int currentTime) {
- final int currentNativeTimestamp = setCurrentTimeForTestNative(currentTime);
- PersonalizationHelper.currentTimeChangedForTesting(currentNativeTimestamp);
- return currentNativeTimestamp;
+ return setCurrentTimeForTestNative(currentTime);
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 6734ca8c5..293623cae 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -359,8 +359,11 @@ public class DictionaryInfoUtils {
* @param fileAddress the asset dictionary file address.
* @return information of the specified dictionary.
*/
+ @Nullable
private static DictionaryInfo createDictionaryInfoFromFileAddress(
final AssetFileAddress fileAddress) {
+ // TODO: Read the header and update the version number for the new dictionaries.
+ // This will make sure that the dictionary version is updated in the database.
final DictionaryHeader header = getDictionaryFileHeaderOrNull(
new File(fileAddress.mFilename), fileAddress.mOffset, fileAddress.mLength);
if (header == null) {
@@ -436,7 +439,8 @@ public class DictionaryInfoUtils {
// Protect against cases of a less-specific dictionary being found, like an
// en dictionary being used for an en_US locale. In this case, the en dictionary
// should be used for en_US but discounted for listing purposes.
- if (!dictionaryInfo.mLocale.equals(locale)) {
+ // TODO: Remove dictionaryInfo == null when the static LMs have the headers.
+ if (dictionaryInfo == null || !dictionaryInfo.mLocale.equals(locale)) {
continue;
}
addOrUpdateDictInfo(dictList, dictionaryInfo);
diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
index 10e3994b6..981355115 100644
--- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
+++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java
@@ -33,21 +33,18 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
// TODO: Instead of a boolean , we may want to include the context of this suggestion results,
// such as {@link NgramContext}.
public final boolean mIsBeginningOfSentence;
- public final boolean mAutocorrectRecommendation;
+ public final boolean mFirstSuggestionExceedsConfidenceThreshold;
private final int mCapacity;
- public SuggestionResults(final int capacity, final boolean isBeginningOfSentence) {
- this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence, false);
- }
-
public SuggestionResults(final int capacity, final boolean isBeginningOfSentence,
- final boolean autocorrectRecommendation) {
+ final boolean firstSuggestionExceedsConfidenceThreshold) {
this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence,
- autocorrectRecommendation);
+ firstSuggestionExceedsConfidenceThreshold);
}
private SuggestionResults(final Comparator<SuggestedWordInfo> comparator, final int capacity,
- final boolean isBeginningOfSentence, final boolean autocorrectRecommendation) {
+ final boolean isBeginningOfSentence,
+ final boolean firstSuggestionExceedsConfidenceThreshold) {
super(comparator);
mCapacity = capacity;
if (ProductionFlags.INCLUDE_RAW_SUGGESTIONS) {
@@ -56,7 +53,7 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> {
mRawSuggestions = null;
}
mIsBeginningOfSentence = isBeginningOfSentence;
- mAutocorrectRecommendation = autocorrectRecommendation;
+ mFirstSuggestionExceedsConfidenceThreshold = firstSuggestionExceedsConfidenceThreshold;
}
@Override