aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java11
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java2
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java56
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java8
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryCollection.java5
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java148
-rw-r--r--java/src/com/android/inputmethod/latin/ResearchLogger.java516
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java19
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java71
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java57
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java17
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java2
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java3
13 files changed, 544 insertions, 371 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index ba08c593c..70e38fdb0 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -275,17 +275,6 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat
return false;
}
- @Override
- public AccessibilityNodeInfoCompat findAccessibilityFocus(int virtualViewId) {
- return createAccessibilityNodeInfo(mAccessibilityFocusedView);
- }
-
- @Override
- public AccessibilityNodeInfoCompat accessibilityFocusSearch(int direction, int virtualViewId) {
- // Focus search is not currently supported for IMEs.
- return null;
- }
-
/**
* Sends an accessibility event for the given {@link Key}.
*
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index b4fa86dd5..be7644fb5 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -159,7 +159,7 @@ public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel
@Override
public boolean dismissMoreKeysPanel() {
- if (mIsDismissing) return false;
+ if (mIsDismissing || mController == null) return false;
mIsDismissing = true;
final boolean dismissed = mController.dismissMoreKeysPanel();
mIsDismissing = false;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 14d61e228..8c218c6d3 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -428,23 +428,23 @@ public final class KeyboardTextsSet {
// U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
/* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
/* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
- // U+064F: "ُ" ARABIC DAMMA
- // U+064C: "ٌ" ARABIC DAMMATAN
- // U+0651: "ّ" ARABIC SHADDA
+ // U+0655: "ٕ" ARABIC HAMZA BELOW
+ // U+0654: "ٔ" ARABIC HAMZA ABOVE
// U+0652: "ْ" ARABIC SUKUN
- // U+0653: "ٓ" ARABIC MADDAH ABOVE
// U+064D: "ٍ" ARABIC KASRATAN
+ // U+064C: "ٌ" ARABIC DAMMATAN
// U+064B: "ً" ARABIC FATHATAN
+ // U+0651: "ّ" ARABIC SHADDA
+ // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+ // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+ // U+0653: "ٓ" ARABIC MADDAH ABOVE
// U+0650: "ِ" ARABIC KASRA
+ // U+064F: "ُ" ARABIC DAMMA
// U+064E: "َ" ARABIC FATHA
// U+0640: "ـ" ARABIC TATWEEL
- // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
- // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
- // U+0655: "ٕ" ARABIC HAMZA BELOW
- // U+0654: "ٔ" ARABIC HAMZA ABOVE
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
- /* 56 */ "!fixedColumnOrder!5,\u064F,\u064C,\u0651,\u0652,\u0653,\u064D,\u064B,\u0650,\u064E,\u0640\u0640\u0640|\u0640,\u0656,\u0670,\u0655,\u0654",
- /* 57 */ "\u064F",
+ /* 56 */ "!fixedColumnOrder!7,\u0655,\u0654,\u0652,\u064D,\u064C,\u064B,\u0651,\u0656,\u0670,\u0653,\u0650,\u064F,\u064E,\u0640\u0640\u0640|\u0640",
+ /* 57 */ "\u0651",
// U+0661: "١" ARABIC-INDIC DIGIT ONE
/* 58 */ "\u0661",
// U+0662: "٢" ARABIC-INDIC DIGIT TWO
@@ -993,7 +993,7 @@ public final class KeyboardTextsSet {
/* ~41 */
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_double_quote">&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;</string>
- /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 42 */ "!fixedColumnOrder!4,\u201C,\u201D,\",\'",
// TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
// <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
/* 43 */ "!fixedColumnOrder!4,\u201C,\u201D,\u00AB|\u00BB,\u00BB|\u00AB,\u2018,\u2019,\u201A,\u201B",
@@ -1031,25 +1031,25 @@ public final class KeyboardTextsSet {
// U+201D: "”" RIGHT DOUBLE QUOTATION MARK
// U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
// U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
- /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
- /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
- // U+0651: "ّ" ARABIC SHADDA
- // U+064F: "ُ" ARABIC DAMMA
- // U+0650: "ِ" ARABIC KASRA
- // U+064E: "َ" ARABIC FATHA
- // U+0653: "ٓ" ARABIC MADDAH ABOVE
+ /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
+ /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
// U+0655: "ٕ" ARABIC HAMZA BELOW
- // U+0654: "ٔ" ARABIC HAMZA ABOVE
- // U+064D: "ٍ" ARABIC KASRATAN
- // U+064B: "ً" ARABIC FATHATAN
// U+0652: "ْ" ARABIC SUKUN
- // U+0640: "ـ" ARABIC TATWEEL
+ // U+0651: "ّ" ARABIC SHADDA
// U+064C: "ٌ" ARABIC DAMMATAN
+ // U+064D: "ٍ" ARABIC KASRATAN
+ // U+064B: "ً" ARABIC FATHATAN
+ // U+0654: "ٔ" ARABIC HAMZA ABOVE
// U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
// U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+ // U+0653: "ٓ" ARABIC MADDAH ABOVE
+ // U+064F: "ُ" ARABIC DAMMA
+ // U+0650: "ِ" ARABIC KASRA
+ // U+064E: "َ" ARABIC FATHA
+ // U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
- /* 56 */ "!fixedColumnOrder!5,\u0651,\u064F,\u0650,\u064E,\u0653,\u0655,\u0654,\u064D,\u064B,\u0652,\u0640\u0640\u0640|\u0640,\u064C,\u0656,\u0670",
- /* 57 */ "\u0653",
+ /* 56 */ "!fixedColumnOrder!7,\u0655,\u0652,\u0651,\u064C,\u064D,\u064B,\u0654,\u0656,\u0670,\u0653,\u064F,\u0650,\u064E,\u0640\u0640\u0640|\u0640",
+ /* 57 */ "\u064B",
// U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
/* 58 */ "\u06F1",
// U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
@@ -1101,14 +1101,16 @@ public final class KeyboardTextsSet {
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
+ // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
/* 98 */ "\u060C",
/* 99 */ "!",
/* 100 */ "!,\\,",
/* 101 */ "\u061F",
/* 102 */ "\u061F,?",
- /* 103 */ null,
- /* 104 */ null,
- /* 105 */ "\u061F,\u061B,!,:,-,/,\',\"",
+ /* 103 */ "\u060C",
+ /* 104 */ "\u061F",
+ /* 105 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
};
/* Language fi: Finnish */
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 7cd9bc2a8..9c3d46e70 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -115,4 +115,12 @@ public abstract class Dictionary {
public void close() {
// empty base implementation
}
+
+ /**
+ * Subclasses may override to indicate that this Dictionary is not yet properly initialized.
+ */
+
+ public boolean isInitialized() {
+ return true;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index 1a05fcd86..26c2e637e 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -82,8 +82,9 @@ public class DictionaryCollection extends Dictionary {
return maxFreq;
}
- public boolean isEmpty() {
- return mDictionaries.isEmpty();
+ @Override
+ public boolean isInitialized() {
+ return !mDictionaries.isEmpty();
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8c244d686..8a5fc495e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -122,7 +122,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mSpaceState;
private SettingsValues mCurrentSettings;
- private InputAttributes mInputAttributes;
private View mExtractArea;
private View mKeyPreviewBackingView;
@@ -428,10 +427,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
// is not guaranteed. It may even be called at the same time on a different thread.
if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ final InputAttributes inputAttributes =
+ new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode());
final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() {
@Override
protected SettingsValues job(Resources res) {
- return new SettingsValues(mPrefs, mInputAttributes, LatinIME.this);
+ return new SettingsValues(mPrefs, inputAttributes, LatinIME.this);
}
};
mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale());
@@ -451,11 +452,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
oldContactsDictionary = null;
}
mSuggest = new Suggest(this, subtypeLocale);
- if (mCurrentSettings.isCorrectionOn()) {
+ if (mCurrentSettings.mCorrectionEnabled) {
mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold);
}
mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale);
+ if (ProductionFlag.IS_EXPERIMENTAL) {
+ ResearchLogger.getInstance().initSuggest(mSuggest);
+ }
mUserDictionary = new UserBinaryDictionary(this, localeStr);
mIsUserDictionaryAvailable = mUserDictionary.isEnabled();
@@ -671,7 +675,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
updateFullscreenMode();
mLastSelectionStart = editorInfo.initialSelStart;
mLastSelectionEnd = editorInfo.initialSelEnd;
- mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode());
mApplicationSpecifiedCompletions = null;
inputView.closing();
@@ -682,7 +685,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
loadSettings();
- if (mSuggest != null && mCurrentSettings.isCorrectionOn()) {
+ if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) {
mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold);
}
@@ -825,7 +828,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
@Override
public void onExtractedTextClicked() {
- if (isSuggestionsRequested()) return;
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return;
super.onExtractedTextClicked();
}
@@ -841,7 +844,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
@Override
public void onExtractedCursorMovement(int dx, int dy) {
- if (isSuggestionsRequested()) return;
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return;
super.onExtractedCursorMovement(dx, dy);
}
@@ -872,33 +875,32 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions);
}
- if (mInputAttributes.mApplicationSpecifiedCompletionOn) {
- mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
- if (applicationSpecifiedCompletions == null) {
- clearSuggestions();
- return;
- }
-
- final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
- SuggestedWords.getFromApplicationSpecifiedCompletions(
- applicationSpecifiedCompletions);
- final SuggestedWords suggestedWords = new SuggestedWords(
- applicationSuggestedWords,
- false /* typedWordValid */,
- false /* hasAutoCorrectionCandidate */,
- false /* allowsToBeAutoCorrected */,
- false /* isPunctuationSuggestions */,
- false /* isObsoleteSuggestions */,
- false /* isPrediction */);
- // When in fullscreen mode, show completions generated by the application
- final boolean isAutoCorrection = false;
- setSuggestions(suggestedWords, isAutoCorrection);
- setAutoCorrectionIndicator(isAutoCorrection);
- // TODO: is this the right thing to do? What should we auto-correct to in
- // this case? This says to keep whatever the user typed.
- mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
- setSuggestionStripShown(true);
+ if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return;
+ mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
+ if (applicationSpecifiedCompletions == null) {
+ clearSuggestions();
+ return;
}
+
+ final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
+ SuggestedWords.getFromApplicationSpecifiedCompletions(
+ applicationSpecifiedCompletions);
+ final SuggestedWords suggestedWords = new SuggestedWords(
+ applicationSuggestedWords,
+ false /* typedWordValid */,
+ false /* hasAutoCorrectionCandidate */,
+ false /* allowsToBeAutoCorrected */,
+ false /* isPunctuationSuggestions */,
+ false /* isObsoleteSuggestions */,
+ false /* isPrediction */);
+ // When in fullscreen mode, show completions generated by the application
+ final boolean isAutoCorrection = false;
+ setSuggestions(suggestedWords, isAutoCorrection);
+ setAutoCorrectionIndicator(isAutoCorrection);
+ // TODO: is this the right thing to do? What should we auto-correct to in
+ // this case? This says to keep whatever the user typed.
+ mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
+ setSuggestionStripShown(true);
}
private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) {
@@ -1000,8 +1002,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
// This will reset the whole input state to the starting state. It will clear
- // the composing word, reset the last composed word, tell the inputconnection
- // and the composingStateManager about it.
+ // the composing word, reset the last composed word, tell the inputconnection about it.
private void resetEntireInputState() {
resetComposingState(true /* alsoResetLastComposedWord */);
updateSuggestions();
@@ -1074,7 +1075,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
private boolean maybeDoubleSpace() {
- if (mCurrentSettings.mCorrectionMode == Suggest.CORRECTION_NONE) return false;
+ if (!mCurrentSettings.mCorrectionEnabled) return false;
if (!mHandler.isAcceptingDoubleSpaces()) return false;
final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0);
if (lastThree != null && lastThree.length() == 3
@@ -1277,8 +1278,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
break;
default:
- if (primaryCode == Keyboard.CODE_TAB
- && mInputAttributes.mEditorAction == EditorInfo.IME_ACTION_NEXT) {
+ if (primaryCode == Keyboard.CODE_TAB && mCurrentSettings.isEditorActionNext()) {
performEditorAction(EditorInfo.IME_ACTION_NEXT);
break;
}
@@ -1448,7 +1448,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
}
- if (isSuggestionsRequested()) {
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
restartSuggestionsOnWordBeforeCursorIfAtEndOfWord();
}
}
@@ -1493,7 +1493,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// thread here.
if (!isComposingWord && (isAlphabet(primaryCode)
|| mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode))
- && isSuggestionsRequested() &&
+ && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) &&
!mConnection.isCursorTouchingWord(mCurrentSettings)) {
// Reset entirely the composing state anyway, then start composing a new word unless
// the character is a single quote. The idea here is, single quote is not a
@@ -1556,8 +1556,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// not to auto correct, but accept the typed word. For instance,
// in Italian dov' should not be expanded to dove' because the elision
// requires the last vowel to be removed.
- final boolean shouldAutoCorrect = mCurrentSettings.isCorrectionOn();
- if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
+ if (mCurrentSettings.mCorrectionEnabled && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
commitCurrentAutoCorrection(primaryCode);
didAutoCorrect = true;
} else {
@@ -1575,7 +1574,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
sendKeyCodePoint(primaryCode);
if (Keyboard.CODE_SPACE == primaryCode) {
- if (isSuggestionsRequested()) {
+ if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) {
if (maybeDoubleSpace()) {
mSpaceState = SPACE_STATE_DOUBLE;
} else if (!isShowingPunctuationList()) {
@@ -1626,31 +1625,21 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
inputView.closing();
}
- public boolean isSuggestionsRequested() {
- // TODO: move this method to mSettingsValues
- return mInputAttributes.mIsSettingsSuggestionStripOn
- && (mCurrentSettings.isCorrectionOn() || isShowingSuggestionsStrip());
- }
-
public boolean isShowingPunctuationList() {
if (mSuggestionsView == null) return false;
return mCurrentSettings.mSuggestPuncList == mSuggestionsView.getSuggestions();
}
- public boolean isShowingSuggestionsStrip() {
- return mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation);
- }
-
public boolean isSuggestionsStripVisible() {
if (mSuggestionsView == null)
return false;
if (mSuggestionsView.isShowingAddToDictionaryHint())
return true;
- if (!isShowingSuggestionsStrip())
+ if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation))
return false;
- if (mInputAttributes.mApplicationSpecifiedCompletionOn)
+ if (mCurrentSettings.isApplicationSpecifiedCompletionsOn())
return true;
- return isSuggestionsRequested();
+ return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation);
}
public void switchToKeyboardView() {
@@ -1699,7 +1688,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void updateSuggestions() {
// Check if we have a suggestion engine attached.
- if ((mSuggest == null || !isSuggestionsRequested())) {
+ if ((mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation))) {
if (mWordComposer.isComposingWord()) {
Log.w(TAG, "Called updateSuggestions but suggestions were not requested!");
mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
@@ -1721,7 +1710,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// getSuggestedWords handles gracefully a null value of prevWord
final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer,
prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(),
- mCurrentSettings.mCorrectionMode);
+ mCurrentSettings.mCorrectionEnabled);
// Basically, we update the suggestion strip only when suggestion count > 1. However,
// there is an exception: We update the suggestion strip whenever typed word's length
@@ -1830,7 +1819,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- if (mInputAttributes.mApplicationSpecifiedCompletionOn
+ if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()
&& mApplicationSpecifiedCompletions != null
&& index >= 0 && index < mApplicationSpecifiedCompletions.length) {
if (mSuggestionsView != null) {
@@ -1873,8 +1862,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// - There is a dictionary and the word is not in it
// Please note that if mSuggest is null, it means that everything is off: suggestion
// and correction, so we shouldn't try to show the hint
- // We used to look at mCorrectionMode here, but showing the hint should have nothing
- // to do with the autocorrection setting.
final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
// If there is no dictionary the hint should be shown.
&& (!mSuggest.hasMainDictionary()
@@ -1906,14 +1893,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
*/
private void commitChosenWord(final CharSequence chosenWord, final int commitType,
final int separatorCode) {
- if (mCurrentSettings.mEnableSuggestionSpanInsertion) {
- final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
- mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
- this, chosenWord, suggestedWords, mIsMainDictionaryAvailable),
- 1);
- } else {
- mConnection.commitText(chosenWord, 1);
- }
+ final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
+ mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
+ this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1);
if (ProductionFlag.IS_EXPERIMENTAL) {
ResearchLogger.latinIME_commitText(chosenWord);
}
@@ -1928,7 +1910,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
public void updateBigramPredictions() {
- if (mSuggest == null || !isSuggestionsRequested())
+ if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation))
return;
if (!mCurrentSettings.mBigramPredictionEnabled) {
@@ -1937,7 +1919,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
final SuggestedWords suggestedWords;
- if (mCurrentSettings.mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
+ if (mCurrentSettings.mCorrectionEnabled) {
final CharSequence prevWord = mConnection.getThisWord(mCurrentSettings.mWordSeparators);
if (!TextUtils.isEmpty(prevWord)) {
suggestedWords = mSuggest.getBigramPredictions(prevWord);
@@ -1953,12 +1935,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// showSuggestions will retrieve the word near the cursor, we don't want that here)
showSuggestions(suggestedWords, "");
} else {
- if (!isShowingPunctuationList()) setPunctuationSuggestions();
+ clearSuggestions();
}
}
public void setPunctuationSuggestions() {
- setSuggestions(mCurrentSettings.mSuggestPuncList, false);
+ if (mCurrentSettings.mBigramPredictionEnabled) {
+ clearSuggestions();
+ } else {
+ setSuggestions(mCurrentSettings.mSuggestPuncList, false);
+ }
setAutoCorrectionIndicator(false);
setSuggestionStripShown(isSuggestionsStripVisible());
}
@@ -1966,10 +1952,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) {
if (TextUtils.isEmpty(suggestion)) return null;
- // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
- // adding words in situations where the user or application really didn't
- // want corrections enabled or learned.
- if (!mCurrentSettings.isCorrectionOn()) return null;
+ // If correction is not enabled, we don't add words to the user history dictionary.
+ // That's to avoid unintended additions in some sensitive fields, or fields that
+ // expect to receive non-words.
+ if (!mCurrentSettings.mCorrectionEnabled) return null;
final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary;
if (userHistoryDictionary != null) {
@@ -2224,13 +2210,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
p.println(" Keyboard mode = " + keyboardMode);
- p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn);
- p.println(" mCorrectionMode=" + mCurrentSettings.mCorrectionMode);
+ p.println(" mIsSuggestionsSuggestionsRequested = "
+ + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation));
+ p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled);
p.println(" isComposingWord=" + mWordComposer.isComposingWord());
- p.println(" isCorrectionOn=" + mCurrentSettings.isCorrectionOn());
p.println(" mSoundOn=" + mCurrentSettings.mSoundOn);
p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn);
p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn);
- p.println(" mInputAttributes=" + mInputAttributes.toString());
+ p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString());
}
}
diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java
index 46efa78f1..cf3cc7873 100644
--- a/java/src/com/android/inputmethod/latin/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java
@@ -51,7 +51,9 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
@@ -67,6 +69,7 @@ import java.util.UUID;
public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = ResearchLogger.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final boolean OUTPUT_ENTIRE_BUFFER = false; // true may disclose private info
/* package */ static boolean sIsLogging = false;
private static final int OUTPUT_FORMAT_VERSION = 1;
private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
@@ -94,11 +97,21 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static final int LOGGING_STATE_OFF = 0;
private static final int LOGGING_STATE_ON = 1;
private static final int LOGGING_STATE_STOPPING = 2;
+ private boolean mIsPasswordView = false;
+ // digits entered by the user are replaced with this codepoint.
+ /* package for test */ static final int DIGIT_REPLACEMENT_CODEPOINT =
+ Character.codePointAt("\uE000", 0); // U+E000 is in the "private-use area"
+ // U+E001 is in the "private-use area"
+ /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001";
// set when LatinIME should ignore an onUpdateSelection() callback that
// arises from operations in this class
private static boolean sLatinIMEExpectingUpdateSelection = false;
+ // used to check whether words are not unique
+ private Suggest mSuggest;
+ private Dictionary mDictionary;
+
private static class NullOutputStream extends OutputStream {
/** {@inheritDoc} */
@Override
@@ -313,130 +326,272 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
latinIME.showOptionDialog(builder.create());
}
+ public void initSuggest(Suggest suggest) {
+ mSuggest = suggest;
+ }
+
+ private void setIsPasswordView(boolean isPasswordView) {
+ mIsPasswordView = isPasswordView;
+ }
+
+ private boolean isAllowedToLog() {
+ return mLoggingState == LOGGING_STATE_ON && !mIsPasswordView;
+ }
+
private static final String CURRENT_TIME_KEY = "_ct";
private static final String UPTIME_KEY = "_ut";
private static final String EVENT_TYPE_KEY = "_ty";
private static final Object[] EVENTKEYS_NULLVALUES = {};
+ private LogUnit mCurrentLogUnit = new LogUnit();
+
/**
- * Write a description of the event out to the ResearchLog.
+ * Buffer a research log event, flagging it as privacy-sensitive.
*
- * Runs in the background to avoid blocking the UI thread.
+ * This event contains potentially private information. If the word that this event is a part
+ * of is determined to be privacy-sensitive, then this event should not be included in the
+ * output log. The system waits to output until the containing word is known.
*
* @param keys an array containing a descriptive name for the event, followed by the keys
* @param values an array of values, either a String or Number. length should be one
* less than the keys array
*/
- private synchronized void writeEvent(final String[] keys, final Object[] values) {
+ private synchronized void enqueuePotentiallyPrivateEvent(final String[] keys,
+ final Object[] values) {
assert values.length + 1 == keys.length;
- if (mLoggingState == LOGGING_STATE_ON) {
- mLoggingHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- mJsonWriter.beginObject();
- mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
- mJsonWriter.name(UPTIME_KEY).value(SystemClock.uptimeMillis());
- mJsonWriter.name(EVENT_TYPE_KEY).value(keys[0]);
- final int length = values.length;
- for (int i = 0; i < length; i++) {
- mJsonWriter.name(keys[i + 1]);
- Object value = values[i];
- if (value instanceof String) {
- mJsonWriter.value((String) value);
- } else if (value instanceof Number) {
- mJsonWriter.value((Number) value);
- } else if (value instanceof Boolean) {
- mJsonWriter.value((Boolean) value);
- } else if (value instanceof CompletionInfo[]) {
- CompletionInfo[] ci = (CompletionInfo[]) value;
- mJsonWriter.beginArray();
- for (int j = 0; j < ci.length; j++) {
- mJsonWriter.value(ci[j].toString());
- }
- mJsonWriter.endArray();
- } else if (value instanceof SharedPreferences) {
- SharedPreferences prefs = (SharedPreferences) value;
- mJsonWriter.beginObject();
- for (Map.Entry<String,?> entry : prefs.getAll().entrySet()) {
- mJsonWriter.name(entry.getKey());
- final Object innerValue = entry.getValue();
- if (innerValue == null) {
- mJsonWriter.nullValue();
- } else if (innerValue instanceof Boolean) {
- mJsonWriter.value((Boolean) innerValue);
- } else if (innerValue instanceof Number) {
- mJsonWriter.value((Number) innerValue);
- } else {
- mJsonWriter.value(innerValue.toString());
- }
- }
- mJsonWriter.endObject();
- } else if (value instanceof Key[]) {
- Key[] keys = (Key[]) value;
- mJsonWriter.beginArray();
- for (Key key : keys) {
- mJsonWriter.beginObject();
- mJsonWriter.name("code").value(key.mCode);
- mJsonWriter.name("altCode").value(key.mAltCode);
- mJsonWriter.name("x").value(key.mX);
- mJsonWriter.name("y").value(key.mY);
- mJsonWriter.name("w").value(key.mWidth);
- mJsonWriter.name("h").value(key.mHeight);
- mJsonWriter.endObject();
- }
- mJsonWriter.endArray();
- } else if (value instanceof SuggestedWords) {
- SuggestedWords words = (SuggestedWords) value;
- mJsonWriter.beginObject();
- mJsonWriter.name("typedWordValid").value(words.mTypedWordValid);
- mJsonWriter.name("hasAutoCorrectionCandidate")
- .value(words.mHasAutoCorrectionCandidate);
- mJsonWriter.name("isPunctuationSuggestions")
- .value(words.mIsPunctuationSuggestions);
- mJsonWriter.name("allowsToBeAutoCorrected")
- .value(words.mAllowsToBeAutoCorrected);
- mJsonWriter.name("isObsoleteSuggestions")
- .value(words.mIsObsoleteSuggestions);
- mJsonWriter.name("isPrediction")
- .value(words.mIsPrediction);
- mJsonWriter.name("words");
- mJsonWriter.beginArray();
- final int size = words.size();
- for (int j = 0; j < size; j++) {
- SuggestedWordInfo wordInfo = words.getWordInfo(j);
- mJsonWriter.value(wordInfo.toString());
- }
- mJsonWriter.endArray();
- mJsonWriter.endObject();
- } else if (value == null) {
- mJsonWriter.nullValue();
- } else {
- Log.w(TAG, "Unrecognized type to be logged: " +
- (value == null ? "<null>" : value.getClass().getName()));
- mJsonWriter.nullValue();
- }
+ mCurrentLogUnit.addLogAtom(keys, values, true);
+ }
+
+ /**
+ * Buffer a research log event, flaggint it as not privacy-sensitive.
+ *
+ * This event contains no potentially private information. Even if the word that this event
+ * is privacy-sensitive, this event can still safely be sent to the output log. The system
+ * waits until the containing word is known so that this event can be written in the proper
+ * temporal order with other events that may be privacy sensitive.
+ *
+ * @param keys an array containing a descriptive name for the event, followed by the keys
+ * @param values an array of values, either a String or Number. length should be one
+ * less than the keys array
+ */
+ private synchronized void enqueueEvent(final String[] keys, final Object[] values) {
+ assert values.length + 1 == keys.length;
+ mCurrentLogUnit.addLogAtom(keys, values, false);
+ }
+
+ /* package for test */ boolean isPrivacyThreat(String word) {
+ // currently: word not in dictionary or contains numbers.
+ if (TextUtils.isEmpty(word)) {
+ return false;
+ }
+ final int length = word.length();
+ boolean hasLetter = false;
+ for (int i = 0; i < length; i = word.offsetByCodePoints(i, 1)) {
+ final int codePoint = Character.codePointAt(word, i);
+ if (Character.isDigit(codePoint)) {
+ return true;
+ }
+ if (Character.isLetter(codePoint)) {
+ hasLetter = true;
+ break; // Word may contain digits, but will only be allowed if in the dictionary.
+ }
+ }
+ if (hasLetter) {
+ if (mDictionary == null && mSuggest != null && mSuggest.hasMainDictionary()) {
+ mDictionary = mSuggest.getMainDictionary();
+ }
+ if (mDictionary == null) {
+ // Can't access dictionary. Assume privacy threat.
+ return true;
+ }
+ return !(mDictionary.isValidWord(word));
+ }
+ // No letters, no numbers. Punctuation, space, or something else.
+ return false;
+ }
+
+ /**
+ * Write out enqueued LogEvents to the log, possibly dropping privacy sensitive events.
+ */
+ /* package for test */ synchronized void flushQueue(boolean removePotentiallyPrivateEvents) {
+ if (isAllowedToLog()) {
+ mCurrentLogUnit.setRemovePotentiallyPrivateEvents(removePotentiallyPrivateEvents);
+ mLoggingHandler.post(mCurrentLogUnit);
+ mCurrentLogUnit = new LogUnit();
+ }
+ }
+
+ private synchronized void outputEvent(final String[] keys, final Object[] values) {
+ try {
+ mJsonWriter.beginObject();
+ mJsonWriter.name(CURRENT_TIME_KEY).value(System.currentTimeMillis());
+ mJsonWriter.name(UPTIME_KEY).value(SystemClock.uptimeMillis());
+ mJsonWriter.name(EVENT_TYPE_KEY).value(keys[0]);
+ final int length = values.length;
+ for (int i = 0; i < length; i++) {
+ mJsonWriter.name(keys[i + 1]);
+ Object value = values[i];
+ if (value instanceof String) {
+ mJsonWriter.value((String) value);
+ } else if (value instanceof Number) {
+ mJsonWriter.value((Number) value);
+ } else if (value instanceof Boolean) {
+ mJsonWriter.value((Boolean) value);
+ } else if (value instanceof CompletionInfo[]) {
+ CompletionInfo[] ci = (CompletionInfo[]) value;
+ mJsonWriter.beginArray();
+ for (int j = 0; j < ci.length; j++) {
+ mJsonWriter.value(ci[j].toString());
+ }
+ mJsonWriter.endArray();
+ } else if (value instanceof SharedPreferences) {
+ SharedPreferences prefs = (SharedPreferences) value;
+ mJsonWriter.beginObject();
+ for (Map.Entry<String,?> entry : prefs.getAll().entrySet()) {
+ mJsonWriter.name(entry.getKey());
+ final Object innerValue = entry.getValue();
+ if (innerValue == null) {
+ mJsonWriter.nullValue();
+ } else if (innerValue instanceof Boolean) {
+ mJsonWriter.value((Boolean) innerValue);
+ } else if (innerValue instanceof Number) {
+ mJsonWriter.value((Number) innerValue);
+ } else {
+ mJsonWriter.value(innerValue.toString());
}
+ }
+ mJsonWriter.endObject();
+ } else if (value instanceof Key[]) {
+ Key[] keyboardKeys = (Key[]) value;
+ mJsonWriter.beginArray();
+ for (Key keyboardKey : keyboardKeys) {
+ mJsonWriter.beginObject();
+ mJsonWriter.name("code").value(keyboardKey.mCode);
+ mJsonWriter.name("altCode").value(keyboardKey.mAltCode);
+ mJsonWriter.name("x").value(keyboardKey.mX);
+ mJsonWriter.name("y").value(keyboardKey.mY);
+ mJsonWriter.name("w").value(keyboardKey.mWidth);
+ mJsonWriter.name("h").value(keyboardKey.mHeight);
mJsonWriter.endObject();
- } catch (IOException e) {
- e.printStackTrace();
- Log.w(TAG, "Error in JsonWriter; disabling logging");
- try {
- mJsonWriter.close();
- } catch (IllegalStateException e1) {
- // assume that this is just the json not being terminated properly.
- // ignore
- } catch (IOException e1) {
- e1.printStackTrace();
- } finally {
- mJsonWriter = NULL_JSON_WRITER;
- }
}
+ mJsonWriter.endArray();
+ } else if (value instanceof SuggestedWords) {
+ SuggestedWords words = (SuggestedWords) value;
+ mJsonWriter.beginObject();
+ mJsonWriter.name("typedWordValid").value(words.mTypedWordValid);
+ mJsonWriter.name("hasAutoCorrectionCandidate")
+ .value(words.mHasAutoCorrectionCandidate);
+ mJsonWriter.name("isPunctuationSuggestions")
+ .value(words.mIsPunctuationSuggestions);
+ mJsonWriter.name("allowsToBeAutoCorrected")
+ .value(words.mAllowsToBeAutoCorrected);
+ mJsonWriter.name("isObsoleteSuggestions")
+ .value(words.mIsObsoleteSuggestions);
+ mJsonWriter.name("isPrediction")
+ .value(words.mIsPrediction);
+ mJsonWriter.name("words");
+ mJsonWriter.beginArray();
+ final int size = words.size();
+ for (int j = 0; j < size; j++) {
+ SuggestedWordInfo wordInfo = words.getWordInfo(j);
+ mJsonWriter.value(wordInfo.toString());
+ }
+ mJsonWriter.endArray();
+ mJsonWriter.endObject();
+ } else if (value == null) {
+ mJsonWriter.nullValue();
+ } else {
+ Log.w(TAG, "Unrecognized type to be logged: " +
+ (value == null ? "<null>" : value.getClass().getName()));
+ mJsonWriter.nullValue();
}
- });
+ }
+ mJsonWriter.endObject();
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.w(TAG, "Error in JsonWriter; disabling logging");
+ try {
+ mJsonWriter.close();
+ } catch (IllegalStateException e1) {
+ // assume that this is just the json not being terminated properly.
+ // ignore
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ } finally {
+ mJsonWriter = NULL_JSON_WRITER;
+ }
}
}
+ private static class LogUnit implements Runnable {
+ private final List<String[]> mKeysList = new ArrayList<String[]>();
+ private final List<Object[]> mValuesList = new ArrayList<Object[]>();
+ private final List<Boolean> mIsPotentiallyPrivate = new ArrayList<Boolean>();
+ private boolean mRemovePotentiallyPrivateEvents = true;
+
+ private void addLogAtom(final String[] keys, final Object[] values,
+ final Boolean isPotentiallyPrivate) {
+ mKeysList.add(keys);
+ mValuesList.add(values);
+ mIsPotentiallyPrivate.add(isPotentiallyPrivate);
+ }
+
+ void setRemovePotentiallyPrivateEvents(boolean removePotentiallyPrivateEvents) {
+ mRemovePotentiallyPrivateEvents = removePotentiallyPrivateEvents;
+ }
+
+ @Override
+ public void run() {
+ final int numAtoms = mKeysList.size();
+ for (int atomIndex = 0; atomIndex < numAtoms; atomIndex++) {
+ if (mRemovePotentiallyPrivateEvents && mIsPotentiallyPrivate.get(atomIndex)) {
+ continue;
+ }
+ final String[] keys = mKeysList.get(atomIndex);
+ final Object[] values = mValuesList.get(atomIndex);
+ ResearchLogger.getInstance().outputEvent(keys, values);
+ }
+ }
+ }
+
+ private static int scrubDigitFromCodePoint(int codePoint) {
+ return Character.isDigit(codePoint) ? DIGIT_REPLACEMENT_CODEPOINT : codePoint;
+ }
+
+ /* package for test */ static String scrubDigitsFromString(String s) {
+ StringBuilder sb = null;
+ final int length = s.length();
+ for (int i = 0; i < length; i = s.offsetByCodePoints(i, 1)) {
+ final int codePoint = Character.codePointAt(s, i);
+ if (Character.isDigit(codePoint)) {
+ if (sb == null) {
+ sb = new StringBuilder(length);
+ sb.append(s.substring(0, i));
+ }
+ sb.appendCodePoint(DIGIT_REPLACEMENT_CODEPOINT);
+ } else {
+ if (sb != null) {
+ sb.appendCodePoint(codePoint);
+ }
+ }
+ }
+ if (sb == null) {
+ return s;
+ } else {
+ return sb.toString();
+ }
+ }
+
+ private String scrubWord(String word) {
+ if (mDictionary == null) {
+ return WORD_REPLACEMENT_STRING;
+ }
+ if (mDictionary.isValidWord(word)) {
+ return word;
+ }
+ return WORD_REPLACEMENT_STRING;
+ }
+
private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT = {
"LatinKeyboardViewProcessMotionEvent", "action", "eventTime", "id", "x", "y", "size",
"pressure"
@@ -460,7 +615,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
actionString, eventTime, id, x, y, size, pressure
};
- getInstance().writeEvent(EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_LATINKEYBOARDVIEW_PROCESSMOTIONEVENT, values);
}
}
@@ -469,9 +625,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
};
public static void latinIME_onCodeInput(final int code, final int x, final int y) {
final Object[] values = {
- Keyboard.printableCode(code), x, y
+ Keyboard.printableCode(scrubDigitFromCodePoint(code)), x, y
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONCODEINPUT, values);
}
private static final String[] EVENTKEYS_CORRECTION = {
@@ -480,9 +636,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void logCorrection(final String subgroup, final String before, final String after,
final int position) {
final Object[] values = {
- subgroup, before, after, position
+ subgroup, scrubDigitsFromString(before), scrubDigitsFromString(after), position
};
- getInstance().writeEvent(EVENTKEYS_CORRECTION, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_CORRECTION, values);
}
private static final String[] EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION = {
@@ -491,19 +647,25 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_commitCurrentAutoCorrection(final String typedWord,
final String autoCorrection) {
final Object[] values = {
- typedWord, autoCorrection
+ scrubDigitsFromString(typedWord), scrubDigitsFromString(autoCorrection)
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_LATINIME_COMMITCURRENTAUTOCORRECTION, values);
+ researchLogger.flushQueue(researchLogger.isPrivacyThreat(autoCorrection));
}
private static final String[] EVENTKEYS_LATINIME_COMMITTEXT = {
"LatinIMECommitText", "typedWord"
};
public static void latinIME_commitText(final CharSequence typedWord) {
+ final String scrubbedWord = scrubDigitsFromString(typedWord.toString());
final Object[] values = {
- typedWord.toString()
+ scrubbedWord
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_COMMITTEXT, values);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_COMMITTEXT, values);
+ researchLogger.flushQueue(researchLogger.isPrivacyThreat(scrubbedWord));
}
private static final String[] EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT = {
@@ -513,14 +675,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
length
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT, values);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_DELETESURROUNDINGTEXT, values);
}
private static final String[] EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD = {
"LatinIMEDoubleSpaceAutoPeriod"
};
public static void latinIME_doubleSpaceAutoPeriod() {
- getInstance().writeEvent(EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD, EVENTKEYS_NULLVALUES);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_DOUBLESPACEAUTOPERIOD, EVENTKEYS_NULLVALUES);
}
private static final String[] EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS = {
@@ -531,7 +693,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
applicationSpecifiedCompletions
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONDISPLAYCOMPLETIONS,
+ values);
}
/* package */ static boolean getAndClearLatinIMEExpectingUpdateSelection() {
@@ -552,27 +715,35 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
ic.setSelection(savedSelectionStart, savedSelectionEnd);
ic.endBatchEdit();
sLatinIMEExpectingUpdateSelection = true;
- Object[] values = new Object[2];
- if (TextUtils.isEmpty(charSequence)) {
- values[0] = false;
- values[1] = "";
- } else {
- if (charSequence.length() > MAX_INPUTVIEW_LENGTH_TO_CAPTURE) {
- int length = MAX_INPUTVIEW_LENGTH_TO_CAPTURE;
- // do not cut in the middle of a supplementary character
- final char c = charSequence.charAt(length - 1);
- if (Character.isHighSurrogate(c)) {
- length--;
- }
- final CharSequence truncatedCharSequence = charSequence.subSequence(0, length);
- values[0] = true;
- values[1] = truncatedCharSequence.toString();
- } else {
+ final Object[] values = new Object[2];
+ if (OUTPUT_ENTIRE_BUFFER) {
+ if (TextUtils.isEmpty(charSequence)) {
values[0] = false;
- values[1] = charSequence.toString();
+ values[1] = "";
+ } else {
+ if (charSequence.length() > MAX_INPUTVIEW_LENGTH_TO_CAPTURE) {
+ int length = MAX_INPUTVIEW_LENGTH_TO_CAPTURE;
+ // do not cut in the middle of a supplementary character
+ final char c = charSequence.charAt(length - 1);
+ if (Character.isHighSurrogate(c)) {
+ length--;
+ }
+ final CharSequence truncatedCharSequence = charSequence.subSequence(0,
+ length);
+ values[0] = true;
+ values[1] = truncatedCharSequence.toString();
+ } else {
+ values[0] = false;
+ values[1] = charSequence.toString();
+ }
}
+ } else {
+ values[0] = true;
+ values[1] = "";
}
- getInstance().writeEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONWINDOWHIDDEN, values);
+ researchLogger.flushQueue(true); // Play it safe. Remove privacy-sensitive events.
}
}
@@ -588,7 +759,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY,
Build.MODEL, prefs, OUTPUT_FORMAT_VERSION
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values);
}
}
@@ -622,12 +793,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
word = range.mWord;
}
}
+ final ResearchLogger researchLogger = getInstance();
+ final String scrubbedWord = researchLogger.scrubWord(word);
final Object[] values = {
lastSelectionStart, lastSelectionEnd, oldSelStart, oldSelEnd, newSelStart,
newSelEnd, composingSpanStart, composingSpanEnd, expectingUpdateSelection,
- expectingUpdateSelectionFromLogger, word
+ expectingUpdateSelectionFromLogger, scrubbedWord
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_ONUPDATESELECTION, values);
+ researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_ONUPDATESELECTION, values);
}
private static final String[] EVENTKEYS_LATINIME_PERFORMEDITORACTION = {
@@ -637,7 +810,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
imeActionNext
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_PERFORMEDITORACTION, values);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_PERFORMEDITORACTION, values);
}
private static final String[] EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION = {
@@ -648,7 +821,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
index, cs, x, y
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION, values);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION, values);
+ researchLogger.flushQueue(researchLogger.isPrivacyThreat(cs.toString()));
}
private static final String[] EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY = {
@@ -657,9 +833,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinIME_pickSuggestionManually(final String replacedWord,
final int index, CharSequence suggestion, int x, int y) {
final Object[] values = {
- replacedWord, index, suggestion, x, y
+ scrubDigitsFromString(replacedWord), index, suggestion == null ? null :
+ scrubDigitsFromString(suggestion.toString()), x, y
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY, values);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_PICKSUGGESTIONMANUALLY,
+ values);
+ researchLogger.flushQueue(researchLogger.isPrivacyThreat(suggestion.toString()));
}
private static final String[] EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION = {
@@ -670,14 +850,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
index, suggestion, x, y
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION, values);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_PUNCTUATIONSUGGESTION, values);
}
private static final String[] EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT = {
"LatinIMERevertDoubleSpaceWhileInBatchEdit"
};
public static void latinIME_revertDoubleSpaceWhileInBatchEdit() {
- getInstance().writeEvent(EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT,
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT,
EVENTKEYS_NULLVALUES);
}
@@ -685,7 +865,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
"LatinIMERevertSwapPunctuation"
};
public static void latinIME_revertSwapPunctuation() {
- getInstance().writeEvent(EVENTKEYS_LATINIME_REVERTSWAPPUNCTUATION, EVENTKEYS_NULLVALUES);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_REVERTSWAPPUNCTUATION, EVENTKEYS_NULLVALUES);
}
private static final String[] EVENTKEYS_LATINIME_SENDKEYCODEPOINT = {
@@ -693,16 +873,16 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
};
public static void latinIME_sendKeyCodePoint(final int code) {
final Object[] values = {
- code
+ Keyboard.printableCode(scrubDigitFromCodePoint(code))
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_SENDKEYCODEPOINT, values);
}
private static final String[] EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT = {
"LatinIMESwapSwapperAndSpaceWhileInBatchEdit"
};
public static void latinIME_swapSwapperAndSpaceWhileInBatchEdit() {
- getInstance().writeEvent(EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT,
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT,
EVENTKEYS_NULLVALUES);
}
@@ -710,14 +890,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
"LatinIMESwitchToKeyboardView"
};
public static void latinIME_switchToKeyboardView() {
- getInstance().writeEvent(EVENTKEYS_LATINIME_SWITCHTOKEYBOARDVIEW, EVENTKEYS_NULLVALUES);
+ getInstance().enqueueEvent(EVENTKEYS_LATINIME_SWITCHTOKEYBOARDVIEW, EVENTKEYS_NULLVALUES);
}
private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_ONLONGPRESS = {
"LatinKeyboardViewOnLongPress"
};
public static void latinKeyboardView_onLongPress() {
- getInstance().writeEvent(EVENTKEYS_LATINKEYBOARDVIEW_ONLONGPRESS, EVENTKEYS_NULLVALUES);
+ getInstance().enqueueEvent(EVENTKEYS_LATINKEYBOARDVIEW_ONLONGPRESS, EVENTKEYS_NULLVALUES);
}
private static final String[] EVENTKEYS_LATINKEYBOARDVIEW_SETKEYBOARD = {
@@ -729,6 +909,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
public static void latinKeyboardView_setKeyboard(final Keyboard keyboard) {
if (keyboard != null) {
final KeyboardId kid = keyboard.mId;
+ final boolean isPasswordView = kid.passwordInput();
final Object[] values = {
KeyboardId.elementIdToName(kid.mElementId),
kid.mLocale + ":" + kid.mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
@@ -739,7 +920,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
kid.navigateNext(),
kid.navigatePrevious(),
kid.mClobberSettingsKey,
- kid.passwordInput(),
+ isPasswordView,
kid.mShortcutKeyEnabled,
kid.mHasShortcutKey,
kid.mLanguageSwitchKeyEnabled,
@@ -748,7 +929,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
keyboard.mOccupiedHeight,
keyboard.mKeys
};
- getInstance().writeEvent(EVENTKEYS_LATINKEYBOARDVIEW_SETKEYBOARD, values);
+ getInstance().enqueueEvent(EVENTKEYS_LATINKEYBOARDVIEW_SETKEYBOARD, values);
+ getInstance().setIsPasswordView(isPasswordView);
}
}
@@ -759,14 +941,14 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
originallyTypedWord
};
- getInstance().writeEvent(EVENTKEYS_LATINIME_REVERTCOMMIT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_LATINIME_REVERTCOMMIT, values);
}
private static final String[] EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT = {
"PointerTrackerCallListenerOnCancelInput"
};
public static void pointerTracker_callListenerOnCancelInput() {
- getInstance().writeEvent(EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT,
+ getInstance().enqueueEvent(EVENTKEYS_POINTERTRACKER_CALLLISTENERONCANCELINPUT,
EVENTKEYS_NULLVALUES);
}
@@ -780,10 +962,12 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
if (key != null) {
CharSequence outputText = key.mOutputText;
final Object[] values = {
- Keyboard.printableCode(code), outputText, x, y, ignoreModifierKey, altersCode,
- key.isEnabled()
+ Keyboard.printableCode(scrubDigitFromCodePoint(code)), outputText == null ? null
+ : scrubDigitsFromString(outputText.toString()),
+ x, y, ignoreModifierKey, altersCode, key.isEnabled()
};
- getInstance().writeEvent(EVENTKEYS_POINTERTRACKER_CALLLISTENERONCODEINPUT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_POINTERTRACKER_CALLLISTENERONCODEINPUT, values);
}
}
@@ -795,10 +979,11 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final boolean withSliding, final boolean ignoreModifierKey) {
if (key != null) {
final Object[] values = {
- Keyboard.printableCode(primaryCode), withSliding, ignoreModifierKey,
- key.isEnabled()
+ Keyboard.printableCode(scrubDigitFromCodePoint(primaryCode)), withSliding,
+ ignoreModifierKey, key.isEnabled()
};
- getInstance().writeEvent(EVENTKEYS_POINTERTRACKER_CALLLISTENERONRELEASE, values);
+ getInstance().enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_POINTERTRACKER_CALLLISTENERONRELEASE, values);
}
}
@@ -809,7 +994,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
deltaT, distanceSquared
};
- getInstance().writeEvent(EVENTKEYS_POINTERTRACKER_ONDOWNEVENT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONDOWNEVENT, values);
}
private static final String[] EVENTKEYS_POINTERTRACKER_ONMOVEEVENT = {
@@ -820,7 +1005,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
x, y, lastX, lastY
};
- getInstance().writeEvent(EVENTKEYS_POINTERTRACKER_ONMOVEEVENT, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_POINTERTRACKER_ONMOVEEVENT, values);
}
private static final String[] EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT = {
@@ -831,8 +1016,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
me.toString()
};
- getInstance().writeEvent(EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT,
- values);
+ getInstance().enqueuePotentiallyPrivateEvent(
+ EVENTKEYS_SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT, values);
}
}
@@ -844,7 +1029,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final Object[] values = {
suggestedWords
};
- getInstance().writeEvent(EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS, values);
+ getInstance().enqueuePotentiallyPrivateEvent(EVENTKEYS_SUGGESTIONSVIEW_SETSUGGESTIONS,
+ values);
}
}
@@ -852,6 +1038,6 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
"UserTimestamp"
};
public void userTimestamp() {
- getInstance().writeEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES);
+ getInstance().enqueueEvent(EVENTKEYS_USER_TIMESTAMP, EVENTKEYS_NULLVALUES);
}
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index c9ff0a5a8..4c67b4957 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -69,9 +69,7 @@ public class Settings extends InputMethodSettingsFragment
public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY =
"pref_key_preview_popup_dismiss_delay";
public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict";
- public static final String PREF_BIGRAM_SUGGESTION = "next_word_suggestion";
public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction";
- public static final String PREF_KEY_ENABLE_SPAN_INSERT = "enable_span_insert";
public static final String PREF_VIBRATION_DURATION_SETTINGS =
"pref_vibration_duration_settings";
public static final String PREF_KEYPRESS_SOUND_VOLUME =
@@ -87,9 +85,7 @@ public class Settings extends InputMethodSettingsFragment
private ListPreference mShowCorrectionSuggestionsPreference;
private ListPreference mAutoCorrectionThresholdPreference;
private ListPreference mKeyPreviewPopupDismissDelay;
- // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
- private CheckBoxPreference mBigramSuggestion;
- // Prediction: use bigrams to predict the next word when there is no input for it yet
+ // Use bigrams to predict the next word when there is no input for it yet
private CheckBoxPreference mBigramPrediction;
private Preference mDebugSettingsPreference;
@@ -100,7 +96,6 @@ public class Settings extends InputMethodSettingsFragment
final String autoCorrectionOff = getResources().getString(
R.string.auto_correction_threshold_mode_index_off);
final String currentSetting = mAutoCorrectionThresholdPreference.getValue();
- mBigramSuggestion.setEnabled(!currentSetting.equals(autoCorrectionOff));
if (null != mBigramPrediction) {
mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff));
}
@@ -124,7 +119,6 @@ public class Settings extends InputMethodSettingsFragment
mAutoCorrectionThresholdPreference =
(ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD);
- mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTION);
mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS);
mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS);
if (mDebugSettingsPreference != null) {
@@ -150,9 +144,9 @@ public class Settings extends InputMethodSettingsFragment
}
if (!VibratorUtils.getInstance(context).hasVibrator()) {
- generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
final PreferenceGroup advancedSettings =
(PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS);
+ generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
advancedSettings.removePreference(findPreference(PREF_VIBRATION_DURATION_SETTINGS));
}
@@ -164,15 +158,6 @@ public class Settings extends InputMethodSettingsFragment
generalSettings.removePreference(findPreference(PREF_POPUP_ON));
}
- final boolean showBigramSuggestionsOption = res.getBoolean(
- R.bool.config_enable_next_word_suggestions_option);
- if (!showBigramSuggestionsOption) {
- textCorrectionGroup.removePreference(mBigramSuggestion);
- if (null != mBigramPrediction) {
- textCorrectionGroup.removePreference(mBigramPrediction);
- }
- }
-
final CheckBoxPreference includeOtherImesInLanguageSwitchList =
(CheckBoxPreference)findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST);
includeOtherImesInLanguageSwitchList.setEnabled(
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 6a79aa611..ef423f19b 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -76,24 +76,24 @@ public class SettingsValues {
@SuppressWarnings("unused") // TODO: Use this
private final String mKeyPreviewPopupDismissDelayRawValue;
public final boolean mUseContactsDict;
- // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
- public final boolean mBigramSuggestionEnabled;
- // Prediction: use bigrams to predict the next word when there is no input for it yet
+ // Use bigrams to predict the next word when there is no input for it yet
public final boolean mBigramPredictionEnabled;
- public final boolean mEnableSuggestionSpanInsertion;
@SuppressWarnings("unused") // TODO: Use this
private final int mVibrationDurationSettingsRawValue;
@SuppressWarnings("unused") // TODO: Use this
private final float mKeypressSoundVolumeRawValue;
private final InputMethodSubtype[] mAdditionalSubtypes;
+ // From the input box
+ private final InputAttributes mInputAttributes;
+
// Deduced settings
public final int mKeypressVibrationDuration;
public final float mFxVolume;
public final int mKeyPreviewPopupDismissDelay;
private final boolean mAutoCorrectEnabled;
public final float mAutoCorrectionThreshold;
- public final int mCorrectionMode;
+ public final boolean mCorrectionEnabled;
public final int mSuggestionVisibility;
private final boolean mVoiceKeyEnabled;
private final boolean mVoiceKeyOnMain;
@@ -125,6 +125,13 @@ public class SettingsValues {
mSymbolsExcludedFromWordSeparators, res);
mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
+ // Store the input attributes
+ if (null == inputAttributes) {
+ mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
+ } else {
+ mInputAttributes = inputAttributes;
+ }
+
// Get the settings preferences
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
mVibrateOn = isVibrateOn(context, prefs, res);
@@ -147,12 +154,7 @@ public class SettingsValues {
Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout)));
mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue);
- mBigramSuggestionEnabled = mAutoCorrectEnabled
- && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
- mBigramPredictionEnabled = mBigramSuggestionEnabled
- && isBigramPredictionEnabled(prefs, res);
- mEnableSuggestionSpanInsertion =
- prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
+ mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res);
mVibrationDurationSettingsRawValue =
prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1);
mKeypressSoundVolumeRawValue = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
@@ -167,18 +169,17 @@ public class SettingsValues {
mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
mAdditionalSubtypes = AdditionalSubtype.createAdditionalSubtypesArray(
getPrefAdditionalSubtypes(prefs, res));
- mCorrectionMode = createCorrectionMode(inputAttributes);
+ mCorrectionEnabled = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect;
mSuggestionVisibility = createSuggestionVisibility(res);
}
// Helper functions to create member values.
private static SuggestedWords createSuggestPuncList(final String[] puncs) {
- final ArrayList<SuggestedWords.SuggestedWordInfo> puncList =
- new ArrayList<SuggestedWords.SuggestedWordInfo>();
+ final ArrayList<SuggestedWordInfo> puncList = new ArrayList<SuggestedWordInfo>();
if (puncs != null) {
for (final String puncSpec : puncs) {
- puncList.add(new SuggestedWords.SuggestedWordInfo(
- KeySpecParser.getLabel(puncSpec), SuggestedWordInfo.MAX_SCORE));
+ puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
+ SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED));
}
}
return new SuggestedWords(puncList,
@@ -202,13 +203,6 @@ public class SettingsValues {
return wordSeparators;
}
- private int createCorrectionMode(final InputAttributes inputAttributes) {
- final boolean shouldAutoCorrect = mAutoCorrectEnabled
- && (null == inputAttributes || !inputAttributes.mInputTypeNoAutoCorrect);
- if (mBigramSuggestionEnabled && shouldAutoCorrect) return Suggest.CORRECTION_FULL_BIGRAM;
- return shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE;
- }
-
private int createSuggestionVisibility(final Resources res) {
final String suggestionVisiblityStr = mShowSuggestionsSetting;
for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
@@ -226,9 +220,18 @@ public class SettingsValues {
res.getBoolean(R.bool.config_default_vibration_enabled));
}
- public boolean isCorrectionOn() {
- return mCorrectionMode == Suggest.CORRECTION_FULL
- || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM;
+ public boolean isApplicationSpecifiedCompletionsOn() {
+ return mInputAttributes.mApplicationSpecifiedCompletionOn;
+ }
+
+ public boolean isEditorActionNext() {
+ return mInputAttributes.mEditorAction == EditorInfo.IME_ACTION_NEXT;
+ }
+
+ public boolean isSuggestionsRequested(final int displayOrientation) {
+ return mInputAttributes.mIsSettingsSuggestionStripOn
+ && (mCorrectionEnabled
+ || isSuggestionStripVisibleInOrientation(displayOrientation));
}
public boolean isSuggestionStripVisibleInOrientation(final int orientation) {
@@ -286,17 +289,6 @@ public class SettingsValues {
R.integer.config_key_preview_linger_timeout))));
}
- private static boolean isBigramSuggestionEnabled(final SharedPreferences sp,
- final Resources resources, final boolean autoCorrectEnabled) {
- final boolean showBigramSuggestionsOption = resources.getBoolean(
- R.bool.config_enable_next_word_suggestions_option);
- if (!showBigramSuggestionsOption) {
- return autoCorrectEnabled;
- }
- return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTION, resources.getBoolean(
- R.bool.config_default_next_word_suggestions));
- }
-
private static boolean isBigramPredictionEnabled(final SharedPreferences sp,
final Resources resources) {
return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean(
@@ -418,4 +410,9 @@ public class SettingsValues {
final String newStr = Utils.localeAndTimeHashMapToStr(map);
prefs.edit().putString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply();
}
+
+ // For debug.
+ public String getInputAttributesDebugString() {
+ return mInputAttributes.toString();
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 68b7b913f..892245402 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -39,9 +39,10 @@ public class Suggest implements Dictionary.WordCallback {
public static final int APPROX_MAX_WORD_LENGTH = 32;
+ // TODO: rename this to CORRECTION_OFF
public static final int CORRECTION_NONE = 0;
+ // TODO: rename this to CORRECTION_ON
public static final int CORRECTION_FULL = 1;
- public static final int CORRECTION_FULL_BIGRAM = 2;
// It seems the following values are only used for logging.
public static final int DIC_USER_TYPED = 0;
@@ -65,7 +66,7 @@ public class Suggest implements Dictionary.WordCallback {
private static final boolean DBG = LatinImeLogger.sDBG;
- private boolean mHasMainDictionary;
+ private Dictionary mMainDictionary;
private ContactsBinaryDictionary mContactsDict;
private WhitelistDictionary mWhiteListDictionary;
private final ConcurrentHashMap<String, Dictionary> mUnigramDictionaries =
@@ -73,7 +74,7 @@ public class Suggest implements Dictionary.WordCallback {
private final ConcurrentHashMap<String, Dictionary> mBigramDictionaries =
new ConcurrentHashMap<String, Dictionary>();
- private int mPrefMaxSuggestions = 18;
+ public static final int MAX_SUGGESTIONS = 18;
private static final int PREF_MAX_BIGRAMS = 60;
@@ -98,7 +99,7 @@ public class Suggest implements Dictionary.WordCallback {
final long startOffset, final long length, final Locale locale) {
final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
startOffset, length /* useFullEditDistance */, false, locale);
- mHasMainDictionary = null != mainDict;
+ mMainDictionary = mainDict;
addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, mainDict);
addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, mainDict);
initWhitelistAndAutocorrectAndPool(context, locale);
@@ -129,15 +130,15 @@ public class Suggest implements Dictionary.WordCallback {
}
public void resetMainDict(final Context context, final Locale locale) {
- mHasMainDictionary = false;
+ mMainDictionary = null;
new Thread("InitializeBinaryDictionary") {
@Override
public void run() {
final DictionaryCollection newMainDict =
DictionaryFactory.createMainDictionaryFromManager(context, locale);
- mHasMainDictionary = null != newMainDict && !newMainDict.isEmpty();
addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, newMainDict);
addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, newMainDict);
+ mMainDictionary = newMainDict;
}
}.start();
}
@@ -145,7 +146,11 @@ public class Suggest implements Dictionary.WordCallback {
// The main dictionary could have been loaded asynchronously. Don't cache the return value
// of this method.
public boolean hasMainDictionary() {
- return mHasMainDictionary;
+ return null != mMainDictionary && mMainDictionary.isInitialized();
+ }
+
+ public Dictionary getMainDictionary() {
+ return mMainDictionary;
}
public ContactsBinaryDictionary getContactsDictionary() {
@@ -217,7 +222,7 @@ public class Suggest implements Dictionary.WordCallback {
mIsFirstCharCapitalized = false;
mIsAllUpperCase = false;
mTrailingSingleQuotesCount = 0;
- mSuggestions = new ArrayList<SuggestedWordInfo>(mPrefMaxSuggestions);
+ mSuggestions = new ArrayList<SuggestedWordInfo>(MAX_SUGGESTIONS);
// Treating USER_TYPED as UNIGRAM suggestion for logging now.
LatinImeLogger.onAddSuggestedWord("", Suggest.DIC_USER_TYPED, Dictionary.UNIGRAM);
@@ -228,7 +233,7 @@ public class Suggest implements Dictionary.WordCallback {
getAllBigrams(prevWordForBigram, sEmptyWordComposer);
// Nothing entered: return all bigrams for the previous word
- int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions);
+ int insertCount = Math.min(mBigramSuggestions.size(), MAX_SUGGESTIONS);
for (int i = 0; i < insertCount; ++i) {
addBigramToSuggestions(mBigramSuggestions.get(i));
}
@@ -247,12 +252,12 @@ public class Suggest implements Dictionary.WordCallback {
// TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
public SuggestedWords getSuggestedWords(
final WordComposer wordComposer, CharSequence prevWordForBigram,
- final ProximityInfo proximityInfo, final int correctionMode) {
+ final ProximityInfo proximityInfo, final boolean isCorrectionEnabled) {
LatinImeLogger.onStartSuggestion(prevWordForBigram);
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
mIsAllUpperCase = wordComposer.isAllUpperCase();
mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
- mSuggestions = new ArrayList<SuggestedWordInfo>(mPrefMaxSuggestions);
+ mSuggestions = new ArrayList<SuggestedWordInfo>(MAX_SUGGESTIONS);
final String typedWord = wordComposer.getTypedWord();
final String consideredWord = mTrailingSingleQuotesCount > 0
@@ -262,7 +267,7 @@ public class Suggest implements Dictionary.WordCallback {
LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, Dictionary.UNIGRAM);
mConsideredWord = consideredWord;
- if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) {
+ if (wordComposer.size() <= 1 && isCorrectionEnabled) {
// At first character typed, search only the bigrams
mBigramSuggestions = new ArrayList<SuggestedWordInfo>(PREF_MAX_BIGRAMS);
@@ -270,7 +275,7 @@ public class Suggest implements Dictionary.WordCallback {
getAllBigrams(prevWordForBigram, wordComposer);
if (TextUtils.isEmpty(consideredWord)) {
// Nothing entered: return all bigrams for the previous word
- int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions);
+ int insertCount = Math.min(mBigramSuggestions.size(), MAX_SUGGESTIONS);
for (int i = 0; i < insertCount; ++i) {
addBigramToSuggestions(mBigramSuggestions.get(i));
}
@@ -289,7 +294,7 @@ public class Suggest implements Dictionary.WordCallback {
if (bigramSuggestionFirstChar == currentChar
|| bigramSuggestionFirstChar == currentCharUpper) {
addBigramToSuggestions(bigramSuggestion);
- if (++count > mPrefMaxSuggestions) break;
+ if (++count > MAX_SUGGESTIONS) break;
}
}
}
@@ -319,7 +324,7 @@ public class Suggest implements Dictionary.WordCallback {
mIsFirstCharCapitalized, mWhiteListDictionary.getWhitelistedWord(consideredWord));
final boolean hasAutoCorrection;
- if (CORRECTION_FULL == correctionMode || CORRECTION_FULL_BIGRAM == correctionMode) {
+ if (isCorrectionEnabled) {
final CharSequence autoCorrection =
AutoCorrection.computeAutoCorrectionWord(mUnigramDictionaries, wordComposer,
mSuggestions, consideredWord, mAutoCorrectionThreshold,
@@ -335,15 +340,16 @@ public class Suggest implements Dictionary.WordCallback {
for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) {
sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE);
}
- mSuggestions.add(0, new SuggestedWordInfo(
- sb.toString(), SuggestedWordInfo.MAX_SCORE));
+ mSuggestions.add(0, new SuggestedWordInfo(sb.toString(),
+ SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST));
} else {
- mSuggestions.add(0, new SuggestedWordInfo(
- whitelistedWord, SuggestedWordInfo.MAX_SCORE));
+ mSuggestions.add(0, new SuggestedWordInfo(whitelistedWord,
+ SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST));
}
}
- mSuggestions.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE));
+ mSuggestions.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
+ SuggestedWordInfo.KIND_TYPED));
SuggestedWordInfo.removeDups(mSuggestions);
final ArrayList<SuggestedWordInfo> suggestionsList;
@@ -365,10 +371,10 @@ public class Suggest implements Dictionary.WordCallback {
// language, and it will unexpectedly auto-correct. For example, if the user types in
// English with no dictionary and has a "Will" in their contact list, "will" would
// always auto-correct to "Will" which is unwanted. Hence, no main dict => no auto-correct.
- && mHasMainDictionary;
+ && hasMainDictionary();
boolean autoCorrectionAvailable = hasAutoCorrection;
- if (correctionMode == CORRECTION_FULL || correctionMode == CORRECTION_FULL_BIGRAM) {
+ if (isCorrectionEnabled) {
autoCorrectionAvailable |= !allowsToBeAutoCorrected;
}
// Don't auto-correct words with multiple capital letter
@@ -443,7 +449,7 @@ public class Suggest implements Dictionary.WordCallback {
prefMaxSuggestions = PREF_MAX_BIGRAMS;
} else {
suggestions = mSuggestions;
- prefMaxSuggestions = mPrefMaxSuggestions;
+ prefMaxSuggestions = MAX_SUGGESTIONS;
}
int pos = 0;
@@ -495,7 +501,8 @@ public class Suggest implements Dictionary.WordCallback {
for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) {
sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE);
}
- suggestions.add(pos, new SuggestedWordInfo(sb, score));
+ // TODO: figure out what type of suggestion this is
+ suggestions.add(pos, new SuggestedWordInfo(sb, score, SuggestedWordInfo.KIND_CORRECTION));
if (suggestions.size() > prefMaxSuggestions) {
suggestions.remove(prefMaxSuggestions);
} else {
@@ -511,7 +518,7 @@ public class Suggest implements Dictionary.WordCallback {
for (final Dictionary dictionary : dictionaries) {
dictionary.close();
}
- mHasMainDictionary = false;
+ mMainDictionary = null;
}
// TODO: Resolve the inconsistencies between the native auto correction algorithms and
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 497fd3bfa..1ed91fe71 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -91,7 +91,8 @@ public class SuggestedWords {
final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>();
for (CompletionInfo info : infos) {
if (null != info && info.getText() != null) {
- result.add(new SuggestedWordInfo(info.getText(), SuggestedWordInfo.MAX_SCORE));
+ result.add(new SuggestedWordInfo(info.getText(), SuggestedWordInfo.MAX_SCORE,
+ SuggestedWordInfo.KIND_APP_DEFINED));
}
}
return result;
@@ -103,7 +104,8 @@ public class SuggestedWords {
final CharSequence typedWord, final SuggestedWords previousSuggestions) {
final ArrayList<SuggestedWordInfo> suggestionsList = new ArrayList<SuggestedWordInfo>();
final HashSet<String> alreadySeen = new HashSet<String>();
- suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE));
+ suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
+ SuggestedWordInfo.KIND_TYPED));
alreadySeen.add(typedWord.toString());
final int previousSize = previousSuggestions.size();
for (int pos = 1; pos < previousSize; pos++) {
@@ -120,16 +122,25 @@ public class SuggestedWords {
public static class SuggestedWordInfo {
public static final int MAX_SCORE = Integer.MAX_VALUE;
+ public static final int KIND_TYPED = 0; // What user typed
+ public static final int KIND_CORRECTION = 1; // Simple correction/suggestion
+ public static final int KIND_COMPLETION = 2; // Completion (suggestion with appended chars)
+ public static final int KIND_WHITELIST = 3; // Whitelisted word
+ public static final int KIND_BLACKLIST = 4; // Blacklisted word
+ public static final int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation
+ public static final int KIND_APP_DEFINED = 6; // Suggested by the application
private final String mWordStr;
public final CharSequence mWord;
public final int mScore;
+ public final int mKind;
public final int mCodePointCount;
private String mDebugString = "";
- public SuggestedWordInfo(final CharSequence word, final int score) {
+ public SuggestedWordInfo(final CharSequence word, final int score, final int kind) {
mWordStr = word.toString();
mWord = word;
mScore = score;
+ mKind = kind;
mCodePointCount = mWordStr.codePointCount(0, mWordStr.length());
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index 8a29dcc13..19287e3f3 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -167,7 +167,7 @@ public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
@Override
public boolean dismissMoreKeysPanel() {
- if (mIsDismissing) return false;
+ if (mIsDismissing || mController == null) return false;
mIsDismissing = true;
final boolean dismissed = mController.dismissMoreKeysPanel();
mIsDismissing = false;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
index 3d593aaa7..e86390b11 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
@@ -670,7 +670,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
}
public void setSuggestions(SuggestedWords suggestedWords) {
- if (suggestedWords == null || suggestedWords.size() == 0)
+ if (suggestedWords == null)
return;
clear();
@@ -884,5 +884,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener,
super.onDetachedFromWindow();
mHandler.cancelAllMessages();
hidePreview();
+ dismissMoreSuggestions();
}
}