aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values/donottranslate.xml1
-rw-r--r--java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java43
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java20
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java150
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java6
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java330
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java4
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java268
-rw-r--r--java/src/com/android/inputmethod/latin/LatinImeLogger.java6
-rw-r--r--java/src/com/android/inputmethod/latin/Settings.java333
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsValues.java329
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java23
-rw-r--r--java/src/com/android/inputmethod/latin/TextEntryState.java209
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java169
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java3
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java4
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java260
-rw-r--r--tests/src/com/android/inputmethod/latin/SuggestHelper.java22
-rw-r--r--tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java5
22 files changed, 1252 insertions, 954 deletions
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index aefaec9ef..1f7736d9c 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -166,4 +166,5 @@
<string name="dictionary_pack_package_name">com.google.android.inputmethod.latin.dictionarypack</string>
<string name="dictionary_pack_settings_activity">com.google.android.inputmethod.latin.dictionarypack.DictionarySettingsActivity</string>
<string name="settings_ms">ms</string>
+ <string name="settings_warning_researcher_mode">Attention! You are using the special keyboard for research purposes.</string>
</resources>
diff --git a/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java
new file mode 100644
index 000000000..6a0d4dd9e
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/SuggestionsInfoCompatUtils.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.view.textservice.SuggestionsInfo;
+
+import java.lang.reflect.Field;
+
+public class SuggestionsInfoCompatUtils {
+ private static final Field FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = CompatUtils.getField(
+ SuggestionsInfo.class, "RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS");
+ private static final Integer OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = (Integer) CompatUtils
+ .getFieldValue(null, null, FIELD_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS);;
+ private static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS =
+ OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS != null
+ ? OBJ_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS : 0;
+
+ private SuggestionsInfoCompatUtils() {
+ }
+
+ /**
+ * Returns the flag value of the attributes of the suggestions that can be obtained by
+ * {@link #getSuggestionsAttributes}: this tells that the text service thinks
+ * the result suggestions include highly recommended ones.
+ */
+ public static int getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS() {
+ return RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS;
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index b2b68f0ad..ced763841 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -22,6 +22,7 @@ import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Xml;
import com.android.inputmethod.keyboard.internal.KeyStyles;
@@ -42,6 +43,8 @@ import java.util.Map;
* Class for describing the position and characteristics of a single key in the keyboard.
*/
public class Key {
+ private static final String TAG = Key.class.getSimpleName();
+
/**
* The key code (unicode or custom code) that this key generates.
*/
@@ -284,7 +287,11 @@ public class Key {
// specified.
final int code = style.getInt(keyAttr, R.styleable.Keyboard_Key_code,
Keyboard.CODE_UNSPECIFIED);
- if (code == Keyboard.CODE_UNSPECIFIED && !TextUtils.isEmpty(mLabel)) {
+ if (code == Keyboard.CODE_UNSPECIFIED && mOutputText == null
+ && !TextUtils.isEmpty(mLabel)) {
+ if (mLabel.length() != 1) {
+ Log.w(TAG, "Label is not a single letter: label=" + mLabel);
+ }
final int firstChar = mLabel.charAt(0);
mCode = getRtlParenthesisCode(firstChar, params.mIsRtlKeyboard);
} else if (code != Keyboard.CODE_UNSPECIFIED) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 2a6e0a2de..8e325b65c 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -222,13 +222,7 @@ public class KeyDetector {
}
public static String printableCode(Key key) {
- return key != null ? printableCode(key.mCode) : "none";
- }
-
- public static String printableCode(int primaryCode) {
- if (primaryCode < 0) return String.format("%4d", primaryCode);
- if (primaryCode < 0x100) return String.format("\\u%02x", primaryCode);
- return String.format("\\u04x", primaryCode);
+ return key != null ? Keyboard.printableCode(key.mCode) : "none";
}
public static String printableCodes(int[] codes) {
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 2bc140ed5..e267aa65c 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
+import android.util.Log;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
@@ -48,6 +49,8 @@ import java.util.Set;
* </pre>
*/
public class Keyboard {
+ private static final String TAG = Keyboard.class.getSimpleName();
+
/** Some common keys code. These should be aligned with values/keycodes.xml */
public static final int CODE_ENTER = '\n';
public static final int CODE_TAB = '\t';
@@ -71,7 +74,6 @@ public class Keyboard {
public static final int CODE_SHIFT = -1;
public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
public static final int CODE_CAPSLOCK = -3;
- public static final int CODE_CANCEL = -4;
public static final int CODE_DELETE = -5;
public static final int CODE_SETTINGS = -6;
public static final int CODE_SHORTCUT = -7;
@@ -242,4 +244,20 @@ public class Keyboard {
default: return null;
}
}
+
+ public static String printableCode(int code) {
+ switch (code) {
+ case CODE_SHIFT: return "shift";
+ case CODE_SWITCH_ALPHA_SYMBOL: return "symbol";
+ case CODE_CAPSLOCK: return "capslock";
+ case CODE_DELETE: return "delete";
+ case CODE_SHORTCUT: return "shortcut";
+ case CODE_DUMMY: return "dummy";
+ case CODE_UNSPECIFIED: return "unspec";
+ default:
+ if (code < 0) Log.w(TAG, "Unknow negative key code=" + code);
+ if (code < 0x100) return String.format("\\u%02x", code);
+ return String.format("\\u04x", code);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 734189689..cae0edd9f 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -36,6 +36,7 @@ import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.LocaleUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.Settings;
+import com.android.inputmethod.latin.SettingsValues;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.Utils;
@@ -47,7 +48,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
- public static final boolean DEBUG_STATE = false;
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916";
private static final int[] KEYBOARD_THEMES = {
@@ -132,12 +132,19 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
}
}
- public void loadKeyboard(EditorInfo editorInfo, Settings.Values settingsValues) {
+ public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) {
try {
mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues);
mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues);
mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
- mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols));
+ mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols),
+ hasDistinctMultitouch());
+ // TODO: Should get rid of this special case handling for Phone Number layouts once we
+ // have separate layouts with unique KeyboardIds for alphabet and alphabet-shifted
+ // respectively.
+ if (mMainKeyboardId.isPhoneKeyboard()) {
+ mState.onToggleAlphabetAndSymbols();
+ }
} catch (RuntimeException e) {
Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
@@ -146,7 +153,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
public void saveKeyboardState() {
if (mCurrentId != null) {
- mState.onSaveKeyboardState(isAlphabetMode(), isSymbolShifted());
+ mState.onSaveKeyboardState();
}
}
@@ -163,11 +170,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
mKeyboardView.setKeyboard(keyboard);
mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
mCurrentId = keyboard.mId;
- mState.onSetKeyboard(isAlphabetMode());
updateShiftLockState(keyboard);
mKeyboardView.setKeyPreviewPopupEnabled(
- Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources),
- Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
+ SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources),
+ SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
final boolean localeChanged = (oldKeyboard == null)
|| !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
@@ -226,7 +232,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
}
private KeyboardId getKeyboardId(EditorInfo editorInfo, final boolean isSymbols,
- final boolean isShift, Settings.Values settingsValues) {
+ final boolean isShift, SettingsValues settingsValues) {
final int mode = Utils.getKeyboardMode(editorInfo);
final int xmlId;
switch (mode) {
@@ -274,19 +280,25 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
voiceKeyEnabled, hasShortcutKey);
}
- public int getKeyboardMode() {
- return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT;
- }
-
- // TODO: Delegate to KeyboardState
public boolean isAlphabetMode() {
- return mCurrentId != null && mCurrentId.isAlphabetKeyboard();
+ final Keyboard keyboard = getLatinKeyboard();
+ return keyboard != null && keyboard.mId.isAlphabetKeyboard();
}
public boolean isInputViewShown() {
return mCurrentInputView != null && mCurrentInputView.isShown();
}
+ public boolean isShiftedOrShiftLocked() {
+ final Keyboard keyboard = getLatinKeyboard();
+ return keyboard != null && keyboard.isShiftedOrShiftLocked();
+ }
+
+ public boolean isManualTemporaryUpperCase() {
+ final Keyboard keyboard = getLatinKeyboard();
+ return keyboard != null && keyboard.isManualTemporaryUpperCase();
+ }
+
public boolean isKeyboardAvailable() {
if (mKeyboardView != null)
return mKeyboardView.getKeyboard() != null;
@@ -302,14 +314,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
return null;
}
- public boolean isShiftedOrShiftLocked() {
- return mState.isShiftedOrShiftLocked();
- }
-
- public boolean isManualTemporaryUpperCase() {
- return mState.isManualTemporaryUpperCase();
- }
-
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setShifted(int shiftMode) {
@@ -318,7 +322,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
if (latinKeyboard == null)
return;
if (shiftMode == AUTOMATIC_SHIFT) {
- mState.setAutomaticTemporaryUpperCase();
latinKeyboard.setAutomaticTemporaryUpperCase();
} else {
final boolean shifted = (shiftMode == MANUAL_SHIFT);
@@ -326,11 +329,9 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
// state when shift key is pressed to go to normal mode.
// On the other hand, on distinct multi touch panel device, turning off the shift
// locked state with shift key pressing is handled by onReleaseShift().
- if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
- mState.setShiftLocked(false);
+ if (!hasDistinctMultitouch() && !shifted && mState.isShiftLocked()) {
latinKeyboard.setShiftLocked(false);
}
- mState.setShifted(shifted);
latinKeyboard.setShifted(shifted);
}
mKeyboardView.invalidateAllKeys();
@@ -343,7 +344,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
LatinKeyboard latinKeyboard = getLatinKeyboard();
if (latinKeyboard == null)
return;
- mState.setShiftLocked(shiftLocked);
latinKeyboard.setShiftLocked(shiftLocked);
mKeyboardView.invalidateAllKeys();
if (!shiftLocked) {
@@ -358,112 +358,57 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
* Toggle keyboard shift state triggered by user touch event.
*/
public void toggleShift() {
- if (DEBUG_STATE) {
- Log.d(TAG, "toggleShift: " + mState);
- }
- if (isAlphabetMode()) {
- setShifted(mState.isShiftedOrShiftLocked() ? UNSHIFT : MANUAL_SHIFT);
- } else {
- if (isSymbolShifted()) {
- setSymbolsKeyboard();
- } else {
- setSymbolsShiftedKeyboard();
- }
- }
+ mState.onToggleShift();
}
/**
* Toggle caps lock state triggered by user touch event.
*/
public void toggleCapsLock() {
- if (DEBUG_STATE) {
- Log.d(TAG, "toggleCapsLock: " + mState);
- }
- if (isAlphabetMode()) {
- if (mState.isShiftLocked()) {
- setShiftLocked(false);
- // TODO: Remove this.
- // Shift key is long pressed while caps lock state, we will toggle back to normal
- // state. And mark as if shift key is released.
- mState.onReleaseCapsLock();
- } else {
- setShiftLocked(true);
- }
- }
+ mState.onToggleCapsLock();
}
/**
- * Toggle keyboard mode triggered by user touch event.
+ * Toggle between alphabet and symbols modes triggered by user touch event.
*/
- public void toggleKeyboardMode() {
- if (DEBUG_STATE) {
- Log.d(TAG, "toggleKeyboardMode: " + mState);
- }
- if (isAlphabetMode()) {
- setSymbolsKeyboard();
- } else {
- setAlphabetKeyboard();
- }
+ public void toggleAlphabetAndSymbols() {
+ mState.onToggleAlphabetAndSymbols();
}
/**
* Update keyboard shift state triggered by connected EditText status change.
*/
public void updateShiftState() {
- if (DEBUG_STATE) {
- Log.d(TAG, "updateShiftState: " + mState
- + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState());
- }
- mState.onUpdateShiftState(isAlphabetMode(), mInputMethodService.getCurrentAutoCapsState());
+ mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState());
}
public void onPressShift(boolean withSliding) {
- if (!isKeyboardAvailable())
- return;
- if (DEBUG_STATE) {
- Log.d(TAG, "onPressShift: " + mState + " sliding=" + withSliding);
- }
- mState.onPressShift(isAlphabetMode(), isSymbolShifted());
+ mState.onPressShift(withSliding);
}
public void onReleaseShift(boolean withSliding) {
- if (!isKeyboardAvailable())
- return;
- if (DEBUG_STATE) {
- Log.d(TAG, "onReleaseShift: " + mState + " sliding=" + withSliding);
- }
- mState.onReleaseShift(isAlphabetMode(), isSymbolShifted(), withSliding);
+ mState.onReleaseShift(withSliding);
}
public void onPressSymbol() {
- if (DEBUG_STATE) {
- Log.d(TAG, "onPressSymbol: " + mState);
- }
- mState.onPressSymbol(isAlphabetMode());
+ mState.onPressSymbol();
}
public void onReleaseSymbol() {
- if (DEBUG_STATE) {
- Log.d(TAG, "onReleaseSymbol: " + mState);
- }
- mState.onReleaseSymbol(isAlphabetMode());
+ mState.onReleaseSymbol();
}
public void onOtherKeyPressed() {
- if (DEBUG_STATE) {
- Log.d(TAG, "onOtherKeyPressed: " + mState);
- }
mState.onOtherKeyPressed();
}
public void onCancelInput() {
- mState.onCancelInput(isAlphabetMode(), isSymbolShifted(), isSinglePointer());
+ mState.onCancelInput(isSinglePointer());
}
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setSymbolsKeyboard() {
- mState.onSaveShiftLockState();
setKeyboard(getKeyboard(mSymbolsKeyboardId));
}
@@ -471,12 +416,6 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
@Override
public void setAlphabetKeyboard() {
setKeyboard(getKeyboard(mMainKeyboardId));
- mState.onRestoreShiftLockState();
- }
-
- // TODO: Remove this method
- private boolean isSymbolShifted() {
- return mCurrentId != null && mCurrentId.equals(mSymbolsShiftedKeyboardId);
}
// Implements {@link KeyboardState.SwitchActions}.
@@ -505,11 +444,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
* Updates state machine to figure out when to automatically snap back to the previous mode.
*/
public void onCodeInput(int code) {
- if (DEBUG_STATE) {
- Log.d(TAG, "onCodeInput: code=" + code + " isSinglePointer=" + isSinglePointer()
- + " " + mState);
- }
- mState.onCodeInput(isAlphabetMode(), isSymbolShifted(), code, isSinglePointer());
+ mState.onCodeInput(code, isSinglePointer());
}
public LatinKeyboardView getKeyboardView() {
@@ -559,13 +494,14 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
}
private void postSetInputView(final View newInputView) {
- mInputMethodService.mHandler.post(new Runnable() {
+ final LatinIME latinIme = mInputMethodService;
+ latinIme.mHandler.post(new Runnable() {
@Override
public void run() {
if (newInputView != null) {
- mInputMethodService.setInputView(newInputView);
+ latinIme.setInputView(newInputView);
}
- mInputMethodService.updateInputViewShown();
+ latinIme.updateInputViewShown();
}
});
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 9e0c5ce02..3a07cdf4d 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -239,7 +239,7 @@ public class PointerTracker {
private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key, boolean withSliding) {
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
if (DEBUG_LISTENER) {
- Log.d(TAG, "onPress : " + KeyDetector.printableCode(key.mCode)
+ Log.d(TAG, "onPress : " + KeyDetector.printableCode(key)
+ " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey
+ " enabled=" + key.isEnabled());
}
@@ -264,7 +264,7 @@ public class PointerTracker {
// If code is CODE_DUMMY here, this key will be ignored or generate text.
final CharSequence text = (code != Keyboard.CODE_DUMMY) ? null : key.mOutputText;
if (DEBUG_LISTENER) {
- Log.d(TAG, "onCodeInput: " + KeyDetector.printableCode(code) + " text=" + text
+ Log.d(TAG, "onCodeInput: " + Keyboard.printableCode(code) + " text=" + text
+ " codes="+ KeyDetector.printableCodes(keyCodes) + " x=" + x + " y=" + y
+ " ignoreModifier=" + ignoreModifierKey + " alterCode=" + alterCode
+ " enabled=" + key.isEnabled());
@@ -289,7 +289,7 @@ public class PointerTracker {
private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) {
final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
if (DEBUG_LISTENER) {
- Log.d(TAG, "onRelease : " + KeyDetector.printableCode(primaryCode)
+ Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode)
+ " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey
+ " enabled="+ key.isEnabled());
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
index 4a77e0735..11fb91a8c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardShiftState.java
@@ -18,11 +18,9 @@ package com.android.inputmethod.keyboard.internal;
import android.util.Log;
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
-
public class KeyboardShiftState {
private static final String TAG = KeyboardShiftState.class.getSimpleName();
- private static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE;
+ private static final boolean DEBUG = false;
private static final int NORMAL = 0;
private static final int MANUAL_SHIFTED = 1;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 95c9162ef..623cab303 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -22,18 +22,35 @@ import android.util.Log;
import com.android.inputmethod.keyboard.Keyboard;
// TODO: Add unit tests
+/**
+ * Keyboard state machine.
+ *
+ * This class contains all keyboard state transition logic.
+ *
+ * The input events are {@link #onLoadKeyboard(String, boolean)}, {@link #onSaveKeyboardState()},
+ * {@link #onPressShift(boolean)}, {@link #onReleaseShift(boolean)}, {@link #onPressSymbol()},
+ * {@link #onReleaseSymbol()}, {@link #onOtherKeyPressed()}, {@link #onCodeInput(int, boolean)},
+ * {@link #onCancelInput(boolean)}, {@link #onUpdateShiftState(boolean)}, {@link #onToggleShift()},
+ * {@link #onToggleCapsLock()}, and {@link #onToggleAlphabetAndSymbols()}.
+ *
+ * The actions are {@link SwitchActions}'s methods.
+ */
public class KeyboardState {
private static final String TAG = KeyboardState.class.getSimpleName();
private static final boolean DEBUG_STATE = false;
public interface SwitchActions {
public void setAlphabetKeyboard();
+
public static final int UNSHIFT = 0;
public static final int MANUAL_SHIFT = 1;
public static final int AUTOMATIC_SHIFT = 2;
public void setShifted(int shiftMode);
+
public void setShiftLocked(boolean shiftLocked);
+
public void setSymbolsKeyboard();
+
public void setSymbolsShiftedKeyboard();
}
@@ -53,13 +70,17 @@ public class KeyboardState {
private int mSwitchState = SWITCH_STATE_ALPHA;
private String mLayoutSwitchBackSymbols;
+ private boolean mHasDistinctMultitouch;
private final SwitchActions mSwitchActions;
+ private boolean mIsAlphabetMode;
+ private boolean mIsSymbolShifted;
+
private final SavedKeyboardState mSavedKeyboardState = new SavedKeyboardState();
private boolean mPrevMainKeyboardWasShiftLocked;
- private static class SavedKeyboardState {
+ static class SavedKeyboardState {
public boolean mIsValid;
public boolean mIsAlphabetMode;
public boolean mIsShiftLocked;
@@ -70,8 +91,12 @@ public class KeyboardState {
mSwitchActions = switchActions;
}
- public void onLoadKeyboard(String layoutSwitchBackSymbols) {
+ public void onLoadKeyboard(String layoutSwitchBackSymbols, boolean hasDistinctMultitouch) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onLoadKeyboard");
+ }
mLayoutSwitchBackSymbols = layoutSwitchBackSymbols;
+ mHasDistinctMultitouch = hasDistinctMultitouch;
mKeyboardShiftState.setShifted(false);
mKeyboardShiftState.setShiftLocked(false);
mShiftKeyState.onRelease();
@@ -80,20 +105,20 @@ public class KeyboardState {
onRestoreKeyboardState();
}
- // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
- public void onSaveKeyboardState(boolean isAlphabetMode, boolean isSymbolShifted) {
+ public void onSaveKeyboardState() {
final SavedKeyboardState state = mSavedKeyboardState;
- state.mIsAlphabetMode = isAlphabetMode;
- if (isAlphabetMode) {
- state.mIsShiftLocked = isShiftLocked();
- state.mIsShifted = !state.mIsShiftLocked && isShiftedOrShiftLocked();
+ state.mIsAlphabetMode = mIsAlphabetMode;
+ if (mIsAlphabetMode) {
+ state.mIsShiftLocked = mKeyboardShiftState.isShiftLocked();
+ state.mIsShifted = !state.mIsShiftLocked
+ && mKeyboardShiftState.isShiftedOrShiftLocked();
} else {
state.mIsShiftLocked = false;
- state.mIsShifted = isSymbolShifted;
+ state.mIsShifted = mIsSymbolShifted;
}
state.mIsValid = true;
if (DEBUG_STATE) {
- Log.d(TAG, "save: alphabet=" + state.mIsAlphabetMode
+ Log.d(TAG, "onSaveKeyboardState: alphabet=" + state.mIsAlphabetMode
+ " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
}
}
@@ -101,16 +126,17 @@ public class KeyboardState {
private void onRestoreKeyboardState() {
final SavedKeyboardState state = mSavedKeyboardState;
if (DEBUG_STATE) {
- Log.d(TAG, "restore: valid=" + state.mIsValid + " alphabet=" + state.mIsAlphabetMode
+ Log.d(TAG, "onRestoreKeyboardState: valid=" + state.mIsValid
+ + " alphabet=" + state.mIsAlphabetMode
+ " shiftLocked=" + state.mIsShiftLocked + " shift=" + state.mIsShifted);
}
if (!state.mIsValid || state.mIsAlphabetMode) {
- mSwitchActions.setAlphabetKeyboard();
+ setAlphabetKeyboard();
} else {
if (state.mIsShifted) {
- mSwitchActions.setSymbolsShiftedKeyboard();
+ setSymbolsShiftedKeyboard();
} else {
- mSwitchActions.setSymbolsKeyboard();
+ setSymbolsKeyboard();
}
}
@@ -118,119 +144,136 @@ public class KeyboardState {
state.mIsValid = false;
if (state.mIsAlphabetMode) {
- mSwitchActions.setShiftLocked(state.mIsShiftLocked);
+ setShiftLocked(state.mIsShiftLocked);
if (!state.mIsShiftLocked) {
- mSwitchActions.setShifted(
- state.mIsShifted ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+ setShifted(state.mIsShifted ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
}
}
}
- // TODO: Get rid of this method
- public void onSetKeyboard(boolean isAlphabetMode) {
- mSwitchState = isAlphabetMode ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN;
- }
-
+ // TODO: Remove this method.
public boolean isShiftLocked() {
return mKeyboardShiftState.isShiftLocked();
}
- public boolean isShiftLockShifted() {
- return mKeyboardShiftState.isShiftLockShifted();
- }
-
- public boolean isShiftedOrShiftLocked() {
- return mKeyboardShiftState.isShiftedOrShiftLocked();
- }
-
- public boolean isAutomaticTemporaryUpperCase() {
- return mKeyboardShiftState.isAutomaticTemporaryUpperCase();
- }
-
- public boolean isManualTemporaryUpperCase() {
- return mKeyboardShiftState.isManualTemporaryUpperCase();
- }
-
- public boolean isManualTemporaryUpperCaseFromAuto() {
- return mKeyboardShiftState.isManualTemporaryUpperCaseFromAuto();
- }
-
- // TODO: Get rid of this method
- public void setShifted(boolean shifted) {
- mKeyboardShiftState.setShifted(shifted);
+ private void setShifted(int shiftMode) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode));
+ }
+ if (shiftMode == SwitchActions.AUTOMATIC_SHIFT) {
+ mKeyboardShiftState.setAutomaticTemporaryUpperCase();
+ } else {
+ // TODO: Duplicated logic in KeyboardSwitcher#setShifted()
+ final boolean shifted = (shiftMode == SwitchActions.MANUAL_SHIFT);
+ // On non-distinct multi touch panel device, we should also turn off the shift locked
+ // state when shift key is pressed to go to normal mode.
+ // On the other hand, on distinct multi touch panel device, turning off the shift
+ // locked state with shift key pressing is handled by onReleaseShift().
+ if (!mHasDistinctMultitouch && !shifted && mKeyboardShiftState.isShiftLocked()) {
+ mKeyboardShiftState.setShiftLocked(false);
+ }
+ mKeyboardShiftState.setShifted(shifted);
+ }
+ mSwitchActions.setShifted(shiftMode);
}
- // TODO: Get rid of this method
- public void setShiftLocked(boolean shiftLocked) {
+ private void setShiftLocked(boolean shiftLocked) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked);
+ }
mKeyboardShiftState.setShiftLocked(shiftLocked);
+ mSwitchActions.setShiftLocked(shiftLocked);
}
- // TODO: Get rid of this method
- public void setAutomaticTemporaryUpperCase() {
- mKeyboardShiftState.setAutomaticTemporaryUpperCase();
- }
-
- private void toggleAlphabetAndSymbols(boolean isAlphabetMode) {
- if (isAlphabetMode) {
- mSwitchActions.setSymbolsKeyboard();
+ private void toggleAlphabetAndSymbols() {
+ if (mIsAlphabetMode) {
+ setSymbolsKeyboard();
} else {
- mSwitchActions.setAlphabetKeyboard();
+ setAlphabetKeyboard();
}
}
- private void toggleShiftInSymbols(boolean isSymbolShifted) {
- if (isSymbolShifted) {
- mSwitchActions.setSymbolsKeyboard();
+ private void toggleShiftInSymbols() {
+ if (mIsSymbolShifted) {
+ setSymbolsKeyboard();
} else {
- mSwitchActions.setSymbolsShiftedKeyboard();
+ setSymbolsShiftedKeyboard();
}
}
- public void onRestoreShiftLockState() {
- mSwitchActions.setShiftLocked(mPrevMainKeyboardWasShiftLocked);
+ private void setAlphabetKeyboard() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "setAlphabetKeyboard");
+ }
+ mSwitchActions.setAlphabetKeyboard();
+ mIsAlphabetMode = true;
+ mIsSymbolShifted = false;
+ mSwitchState = SWITCH_STATE_ALPHA;
+ setShiftLocked(mPrevMainKeyboardWasShiftLocked);
mPrevMainKeyboardWasShiftLocked = false;
}
- public void onSaveShiftLockState() {
- mPrevMainKeyboardWasShiftLocked = isShiftLocked();
+ private void setSymbolsKeyboard() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "setSymbolsKeyboard");
+ }
+ mPrevMainKeyboardWasShiftLocked = mKeyboardShiftState.isShiftLocked();
+ mSwitchActions.setSymbolsKeyboard();
+ mIsAlphabetMode = false;
+ mIsSymbolShifted = false;
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
}
- // TODO: Remove this method.
- public void onReleaseCapsLock() {
- mShiftKeyState.onRelease();
+ private void setSymbolsShiftedKeyboard() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "setSymbolsShiftedKeyboard");
+ }
+ mSwitchActions.setSymbolsShiftedKeyboard();
+ mIsAlphabetMode = false;
+ mIsSymbolShifted = true;
+ mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
}
- // TODO: Get rid of isAlphabetMode argument.
- public void onPressSymbol(boolean isAlphabetMode) {
- toggleAlphabetAndSymbols(isAlphabetMode);
+ public void onPressSymbol() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onPressSymbol: " + this);
+ }
+ toggleAlphabetAndSymbols();
mSymbolKeyState.onPress();
mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
}
- // TODO: Get rid of isAlphabetMode argument.
- public void onReleaseSymbol(boolean isAlphabetMode) {
+ public void onReleaseSymbol() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onReleaseSymbol: " + this);
+ }
// Snap back to the previous keyboard mode if the user chords the mode change key and
// another key, then releases the mode change key.
if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
- toggleAlphabetAndSymbols(isAlphabetMode);
+ toggleAlphabetAndSymbols();
}
mSymbolKeyState.onRelease();
}
public void onOtherKeyPressed() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onOtherKeyPressed: " + this);
+ }
mShiftKeyState.onOtherKeyPressed();
mSymbolKeyState.onOtherKeyPressed();
}
- // TODO: Get rid of isAlphabetMode argument.
- public void onUpdateShiftState(boolean isAlphabetMode, boolean autoCaps) {
- if (isAlphabetMode) {
- if (!isShiftLocked() && !mShiftKeyState.isIgnoring()) {
+ public void onUpdateShiftState(boolean autoCaps) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this);
+ }
+ if (mIsAlphabetMode) {
+ if (!mKeyboardShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) {
if (mShiftKeyState.isReleasing() && autoCaps) {
// Only when shift key is releasing, automatic temporary upper case will be set.
- mSwitchActions.setShifted(SwitchActions.AUTOMATIC_SHIFT);
+ setShifted(SwitchActions.AUTOMATIC_SHIFT);
} else {
- mSwitchActions.setShifted(mShiftKeyState.isMomentary()
+ setShifted(mShiftKeyState.isMomentary()
? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
}
}
@@ -241,79 +284,84 @@ public class KeyboardState {
}
}
- // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
- public void onPressShift(boolean isAlphabetMode, boolean isSymbolShifted) {
- if (isAlphabetMode) {
- if (isShiftLocked()) {
+ public void onPressShift(boolean withSliding) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onPressShift: sliding=" + withSliding + " " + this);
+ }
+ if (mIsAlphabetMode) {
+ if (mKeyboardShiftState.isShiftLocked()) {
// Shift key is pressed while caps lock state, we will treat this state as shifted
// caps lock state and mark as if shift key pressed while normal state.
- mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
+ setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isAutomaticTemporaryUpperCase()) {
+ } else if (mKeyboardShiftState.isAutomaticTemporaryUpperCase()) {
// Shift key is pressed while automatic temporary upper case, we have to move to
// manual temporary upper case.
- mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
+ setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
- } else if (isShiftedOrShiftLocked()) {
+ } else if (mKeyboardShiftState.isShiftedOrShiftLocked()) {
// In manual upper case state, we just record shift key has been pressing while
// shifted state.
mShiftKeyState.onPressOnShifted();
} else {
// In base layout, chording or manual temporary upper case mode is started.
- mSwitchActions.setShifted(SwitchActions.MANUAL_SHIFT);
+ setShifted(SwitchActions.MANUAL_SHIFT);
mShiftKeyState.onPress();
}
} else {
// In symbol mode, just toggle symbol and symbol more keyboard.
- toggleShiftInSymbols(isSymbolShifted);
+ toggleShiftInSymbols();
mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
mShiftKeyState.onPress();
}
}
- // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
- public void onReleaseShift(boolean isAlphabetMode, boolean isSymbolShifted,
- boolean withSliding) {
- if (isAlphabetMode) {
- final boolean isShiftLocked = isShiftLocked();
+ public void onReleaseShift(boolean withSliding) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onReleaseShift: sliding=" + withSliding + " " + this);
+ }
+ if (mIsAlphabetMode) {
+ final boolean isShiftLocked = mKeyboardShiftState.isShiftLocked();
if (mShiftKeyState.isMomentary()) {
// After chording input while normal state.
- mSwitchActions.setShifted(SwitchActions.UNSHIFT);
- } else if (isShiftLocked && !isShiftLockShifted() && (mShiftKeyState.isPressing()
- || mShiftKeyState.isPressingOnShifted()) && !withSliding) {
+ setShifted(SwitchActions.UNSHIFT);
+ } else if (isShiftLocked && !mKeyboardShiftState.isShiftLockShifted()
+ && (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted())
+ && !withSliding) {
// Shift has been long pressed, ignore this release.
} else if (isShiftLocked && !mShiftKeyState.isIgnoring() && !withSliding) {
// Shift has been pressed without chording while caps lock state.
- mSwitchActions.setShiftLocked(false);
- } else if (isShiftedOrShiftLocked() && mShiftKeyState.isPressingOnShifted()
- && !withSliding) {
+ setShiftLocked(false);
+ } else if (mKeyboardShiftState.isShiftedOrShiftLocked()
+ && mShiftKeyState.isPressingOnShifted() && !withSliding) {
// Shift has been pressed without chording while shifted state.
- mSwitchActions.setShifted(SwitchActions.UNSHIFT);
- } else if (isManualTemporaryUpperCaseFromAuto() && mShiftKeyState.isPressing()
- && !withSliding) {
+ setShifted(SwitchActions.UNSHIFT);
+ } else if (mKeyboardShiftState.isManualTemporaryUpperCaseFromAuto()
+ && mShiftKeyState.isPressing() && !withSliding) {
// Shift has been pressed without chording while manual temporary upper case
// transited from automatic temporary upper case.
- mSwitchActions.setShifted(SwitchActions.UNSHIFT);
+ setShifted(SwitchActions.UNSHIFT);
}
} else {
// In symbol mode, snap back to the previous keyboard mode if the user chords the shift
// key and another key, then releases the shift key.
if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
- toggleShiftInSymbols(isSymbolShifted);
+ toggleShiftInSymbols();
}
}
mShiftKeyState.onRelease();
}
- // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
- public void onCancelInput(boolean isAlphabetMode, boolean isSymbolShifted,
- boolean isSinglePointer) {
+ public void onCancelInput(boolean isSinglePointer) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onCancelInput: isSinglePointer=" + isSinglePointer + " " + this);
+ }
// Snap back to the previous keyboard mode if the user cancels sliding input.
if (isSinglePointer) {
if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
- toggleAlphabetAndSymbols(isAlphabetMode);
+ toggleAlphabetAndSymbols();
} else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
- toggleShiftInSymbols(isSymbolShifted);
+ toggleShiftInSymbols();
}
}
}
@@ -333,9 +381,11 @@ public class KeyboardState {
return false;
}
- // TODO: Get rid of isAlphabetMode and isSymbolShifted arguments.
- public void onCodeInput(boolean isAlphabetMode, boolean isSymbolShifted, int code,
- boolean isSinglePointer) {
+ public void onCodeInput(int code, boolean isSinglePointer) {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onCodeInput: code=" + code + " isSinglePointer=" + isSinglePointer
+ + " " + this);
+ }
switch (mSwitchState) {
case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
// Only distinct multi touch devices can be in this state.
@@ -346,7 +396,7 @@ public class KeyboardState {
// {@link #SWITCH_STATE_MOMENTARY}.
if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released.
- if (isAlphabetMode) {
+ if (mIsAlphabetMode) {
mSwitchState = SWITCH_STATE_ALPHA;
} else {
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
@@ -356,7 +406,7 @@ public class KeyboardState {
// and slid to other key, then released the finger.
// If the user cancels the sliding input, snapping back to the previous keyboard
// mode is handled by {@link #onCancelInput}.
- toggleAlphabetAndSymbols(isAlphabetMode);
+ toggleAlphabetAndSymbols();
} else {
// Chording input is being started. The keyboard mode will be snapped back to the
// previous mode in {@link onReleaseSymbol} when the mode change key is released.
@@ -370,7 +420,7 @@ public class KeyboardState {
} else if (isSinglePointer) {
// Snap back to the previous keyboard mode if the user pressed the shift key on
// symbol mode and slid to other key, then released the finger.
- toggleShiftInSymbols(isSymbolShifted);
+ toggleShiftInSymbols();
mSwitchState = SWITCH_STATE_SYMBOL;
} else {
// Chording input is being started. The keyboard mode will be snapped back to the
@@ -384,7 +434,7 @@ public class KeyboardState {
}
// Snap back to alpha keyboard mode immediately if user types a quote character.
if (isLayoutSwitchBackCharacter(code)) {
- mSwitchActions.setAlphabetKeyboard();
+ setAlphabetKeyboard();
}
break;
case SWITCH_STATE_SYMBOL:
@@ -392,12 +442,56 @@ public class KeyboardState {
// Snap back to alpha keyboard mode if user types one or more non-space/enter
// characters followed by a space/enter or a quote character.
if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
- mSwitchActions.setAlphabetKeyboard();
+ setAlphabetKeyboard();
}
break;
}
}
+ public void onToggleShift() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onToggleShift: " + this);
+ }
+ if (mIsAlphabetMode) {
+ setShifted(mKeyboardShiftState.isShiftedOrShiftLocked()
+ ? SwitchActions.UNSHIFT : SwitchActions.MANUAL_SHIFT);
+ } else {
+ toggleShiftInSymbols();
+ }
+ }
+
+ public void onToggleCapsLock() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onToggleCapsLock: " + this);
+ }
+ if (mIsAlphabetMode) {
+ if (mKeyboardShiftState.isShiftLocked()) {
+ setShiftLocked(false);
+ // Shift key is long pressed while caps lock state, we will toggle back to normal
+ // state. And mark as if shift key is released.
+ mShiftKeyState.onRelease();
+ } else {
+ setShiftLocked(true);
+ }
+ }
+ }
+
+ public void onToggleAlphabetAndSymbols() {
+ if (DEBUG_STATE) {
+ Log.d(TAG, "onToggleAlphabetAndSymbols: " + this);
+ }
+ toggleAlphabetAndSymbols();
+ }
+
+ private static String shiftModeToString(int shiftMode) {
+ switch (shiftMode) {
+ case SwitchActions.UNSHIFT: return "UNSHIFT";
+ case SwitchActions.MANUAL_SHIFT: return "MANUAL";
+ case SwitchActions.AUTOMATIC_SHIFT: return "AUTOMATIC";
+ default: return null;
+ }
+ }
+
private static String switchStateToString(int switchState) {
switch (switchState) {
case SWITCH_STATE_ALPHA: return "ALPHA";
diff --git a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java
index f8620910a..f95c91636 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/ModifierKeyState.java
@@ -18,11 +18,9 @@ package com.android.inputmethod.keyboard.internal;
import android.util.Log;
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
-
/* package */ class ModifierKeyState {
protected static final String TAG = "ModifierKeyState";
- protected static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE;
+ protected static final boolean DEBUG = false;
protected static final int RELEASING = 0;
protected static final int PRESSING = 1;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5ee69d1c4..6ea642c92 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -78,7 +78,6 @@ import java.util.Locale;
public class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener,
SuggestionsView.Listener {
private static final String TAG = LatinIME.class.getSimpleName();
- private static final boolean PERF_DEBUG = false;
private static final boolean TRACE = false;
private static boolean DEBUG;
@@ -144,6 +143,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
*/
private static final String SCHEME_PACKAGE = "package";
+ // TODO: migrate this to SettingsValues
private int mSuggestionVisibility;
private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
= R.string.prefs_suggestion_visibility_show_value;
@@ -174,7 +174,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// Current space state of the input method. This can be any of the above constants.
private int mSpaceState;
- private Settings.Values mSettingsValues;
+ private SettingsValues mSettingsValues;
private View mExtractArea;
private View mKeyPreviewBackingView;
@@ -186,7 +186,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private InputMethodManagerCompatWrapper mImm;
private Resources mResources;
private SharedPreferences mPrefs;
- private String mInputMethodId;
private KeyboardSwitcher mKeyboardSwitcher;
private SubtypeSwitcher mSubtypeSwitcher;
private VoiceProxy mVoiceProxy;
@@ -203,13 +202,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private boolean mIsSettingsSuggestionStripOn;
private boolean mApplicationSpecifiedCompletionOn;
- private final StringBuilder mComposingStringBuilder = new StringBuilder();
private WordComposer mWordComposer = new WordComposer();
private CharSequence mBestWord;
private boolean mHasUncommittedTypedChars;
private int mCorrectionMode;
- private int mCommittedLength;
+ private String mWordSavedForAutoCorrectCancellation;
// Keep track of the last selection range to decide if we need to show word alternatives
private int mLastSelectionStart;
private int mLastSelectionEnd;
@@ -221,11 +219,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private long mLastKeyTime;
private AudioManager mAudioManager;
- private float mFxVolume = -1.0f; // default volume
private boolean mSilentModeOn; // System-wide current configuration
private VibratorCompatWrapper mVibrator;
- private long mKeypressVibrationDuration = -1;
// TODO: Move this flag to VoiceProxy
private boolean mConfigurationChanging;
@@ -499,7 +495,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
super.onCreate();
mImm = InputMethodManagerCompatWrapper.getInstance();
- mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mKeyboardSwitcher = KeyboardSwitcher.getInstance();
mVibrator = VibratorCompatWrapper.getInstance(this);
@@ -548,10 +543,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
/* package */ void loadSettings() {
if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
- mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
+ mSettingsValues = new SettingsValues(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
- updateSoundEffectVolume();
- updateKeypressVibrationDuration();
}
private void initSuggest() {
@@ -743,8 +736,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mSubtypeSwitcher.updateParametersOnStartInputView();
- TextEntryState.reset();
-
// Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
// know now whether this is a password text field, because we need to know now whether we
// want to enable the voice button.
@@ -760,7 +751,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
inputView.closing();
mEnteredText = null;
- mComposingStringBuilder.setLength(0);
+ mWordComposer.reset();
mHasUncommittedTypedChars = false;
mDeleteCount = 0;
mSpaceState = SPACE_STATE_NONE;
@@ -932,12 +923,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// newly inserted punctuation.
mSpaceState = SPACE_STATE_NONE;
}
- if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars)
+ if (((mWordComposer.size() > 0 && mHasUncommittedTypedChars)
|| mVoiceProxy.isVoiceInputHighlighted())
&& (selectionChanged || candidatesCleared)) {
- mComposingStringBuilder.setLength(0);
+ mWordComposer.reset();
mHasUncommittedTypedChars = false;
- TextEntryState.reset();
updateSuggestions();
final InputConnection ic = getCurrentInputConnection();
if (ic != null) {
@@ -946,7 +936,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mComposingStateManager.onFinishComposingText();
mVoiceProxy.setVoiceInputHighlighted(false);
} else if (!mHasUncommittedTypedChars) {
- TextEntryState.reset();
updateSuggestions();
}
}
@@ -1091,8 +1080,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
@Override
public boolean onEvaluateFullscreenMode() {
- return super.onEvaluateFullscreenMode()
- && mResources.getBoolean(R.bool.config_use_fullscreen_mode);
+ return super.onEvaluateFullscreenMode() && mSettingsValues.mUseFullScreenMode;
}
@Override
@@ -1150,13 +1138,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
public void commitTyped(final InputConnection ic) {
if (!mHasUncommittedTypedChars) return;
mHasUncommittedTypedChars = false;
- if (mComposingStringBuilder.length() > 0) {
+ final CharSequence typedWord = mWordComposer.getTypedWord();
+ if (typedWord.length() > 0) {
if (ic != null) {
- ic.commitText(mComposingStringBuilder, 1);
+ ic.commitText(typedWord, 1);
}
- mCommittedLength = mComposingStringBuilder.length();
- TextEntryState.acceptedTyped(mComposingStringBuilder);
- addToUserUnigramAndBigramDictionaries(mComposingStringBuilder,
+ addToUserUnigramAndBigramDictionaries(typedWord,
UserUnigramDictionary.FREQUENCY_FOR_TYPED);
}
updateSuggestions();
@@ -1335,12 +1322,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
// Symbol key is handled in onPress() when device has distinct multi-touch panel.
if (!distinctMultiTouch) {
- switcher.toggleKeyboardMode();
- }
- break;
- case Keyboard.CODE_CANCEL:
- if (!isShowingOptionDialog()) {
- handleClose();
+ switcher.toggleAlphabetAndSymbols();
}
break;
case Keyboard.CODE_SETTINGS:
@@ -1392,6 +1374,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mKeyboardSwitcher.updateShiftState();
mKeyboardSwitcher.onCodeInput(Keyboard.CODE_DUMMY);
mSpaceState = SPACE_STATE_NONE;
+ mWordSavedForAutoCorrectCancellation = null;
mEnteredText = text;
}
@@ -1410,19 +1393,30 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mVoiceProxy.handleBackspace();
+ if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
+ // Cancel multi-character input: remove the text we just entered.
+ // This is triggered on backspace after a key that inputs multiple characters,
+ // like the smiley key or the .com key.
+ ic.deleteSurroundingText(mEnteredText.length(), 0);
+ // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
+ // In addition we know that spaceState is false, and that we should not be
+ // reverting any autocorrect at this point. So we can safely return.
+ ic.endBatchEdit();
+ return;
+ }
+
final boolean deleteChar = !mHasUncommittedTypedChars;
if (mHasUncommittedTypedChars) {
- final int length = mComposingStringBuilder.length();
+ final int length = mWordComposer.size();
if (length > 0) {
- mComposingStringBuilder.delete(length - 1, length);
mWordComposer.deleteLast();
final CharSequence textWithUnderline =
mComposingStateManager.isAutoCorrectionIndicatorOn()
? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
- this, mComposingStringBuilder)
- : mComposingStringBuilder;
+ this, mWordComposer.getTypedWord())
+ : mWordComposer.getTypedWord();
ic.setComposingText(textWithUnderline, 1);
- if (mComposingStringBuilder.length() == 0) {
+ if (mWordComposer.size() == 0) {
mHasUncommittedTypedChars = false;
}
if (1 == length) {
@@ -1436,16 +1430,26 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
} else {
ic.deleteSurroundingText(1, 0);
}
+ // If we deleted the last remaining char of a word, we may have to put the keyboard
+ // in auto-shift state again.
+ mHandler.postUpdateShiftKeyState();
+ // If we had uncommitted chars then we know it's not time to revert any auto-correct
+ // and that spaceState is NONE.
+ ic.endBatchEdit();
+ return;
}
mHandler.postUpdateShiftKeyState();
- // TODO: Merge space state with TextEntryState
- TextEntryState.backspace();
- if (TextEntryState.isUndoCommit()) {
- revertLastWord(ic);
+ if (null != mWordSavedForAutoCorrectCancellation) {
+ Utils.Stats.onAutoCorrectionCancellation();
+ cancelAutoCorrect(ic);
+ mWordSavedForAutoCorrectCancellation = null;
ic.endBatchEdit();
return;
+ } else {
+ mWordSavedForAutoCorrectCancellation = null;
}
+
if (SPACE_STATE_DOUBLE == spaceState) {
if (revertDoubleSpace(ic)) {
ic.endBatchEdit();
@@ -1461,9 +1465,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
- if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
- ic.deleteSurroundingText(mEnteredText.length(), 0);
- } else if (deleteChar) {
+ if (deleteChar) {
if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) {
// Go back to the suggestion mode if the user canceled the
// "Touch again to save".
@@ -1472,7 +1474,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// different behavior only in the case of picking the first
// suggestion (typed word). It's intentional to have made this
// inconsistent with backspacing after selecting other suggestions.
- revertLastWord(ic);
+ restartSuggestionsOnManuallyPickedTypedWord(ic);
} else {
ic.deleteSurroundingText(1, 0);
if (mDeleteCount > DELETE_ACCELERATE_AT) {
@@ -1525,7 +1527,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
// Reset entirely the composing state anyway, then start composing a new word unless
// the character is a single quote.
mHasUncommittedTypedChars = (Keyboard.CODE_SINGLE_QUOTE != code);
- mComposingStringBuilder.setLength(0);
mWordComposer.reset();
clearSuggestions();
mComposingStateManager.onFinishComposingText();
@@ -1555,7 +1556,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
if (mHasUncommittedTypedChars) {
- mComposingStringBuilder.append((char) code);
mWordComposer.add(code, keyCodes, x, y);
if (ic != null) {
// If it's the first letter, make note of auto-caps state
@@ -1566,8 +1566,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final CharSequence textWithUnderline =
mComposingStateManager.isAutoCorrectionIndicatorOn()
? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
- this, mComposingStringBuilder)
- : mComposingStringBuilder;
+ this, mWordComposer.getTypedWord())
+ : mWordComposer.getTypedWord();
ic.setComposingText(textWithUnderline, 1);
}
mHandler.postUpdateSuggestions();
@@ -1580,8 +1580,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
switcher.updateShiftState();
- if (LatinIME.PERF_DEBUG) measureCps();
- TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y);
+ if (mSettingsValues.isWordSeparator(code)) {
+ Utils.Stats.onSeparator((char)code, x, y);
+ } else {
+ Utils.Stats.onNonSeparator((char)code, x, y);
+ }
if (null != ic) ic.endBatchEdit();
}
@@ -1602,6 +1605,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (ic != null) {
ic.beginBatchEdit();
}
+ // Reset the saved word in all cases. If this separator causes an autocorrection,
+ // it will overwrite this null with the actual word we need to save.
+ mWordSavedForAutoCorrectCancellation = null;
if (mHasUncommittedTypedChars) {
// In certain languages where single quote is a separator, it's better
// not to auto correct, but accept the typed word. For instance,
@@ -1661,11 +1667,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
setPunctuationSuggestions();
}
- TextEntryState.typedCharacter((char) primaryCode, true, x, y);
+ Utils.Stats.onSeparator((char)primaryCode, x, y);
if (pickedDefault) {
CharSequence typedWord = mWordComposer.getTypedWord();
- TextEntryState.backToAcceptedDefault(typedWord);
if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
InputConnectionCompatUtils.commitCorrection(
ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
@@ -1756,8 +1761,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
final CharSequence textWithUnderline = newAutoCorrectionIndicator
? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
- this, mComposingStringBuilder)
- : mComposingStringBuilder;
+ this, mWordComposer.getTypedWord())
+ : mWordComposer.getTypedWord();
if (!TextUtils.isEmpty(textWithUnderline)) {
ic.setComposingText(textWithUnderline, 1);
}
@@ -1791,8 +1796,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
}
// getSuggestedWordBuilder handles gracefully a null value of prevWord
- final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
- wordComposer, prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo());
+ final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(wordComposer,
+ prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode);
boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
final CharSequence typedWord = wordComposer.getTypedWord();
@@ -1873,9 +1878,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
updateSuggestions();
}
if (mBestWord != null && mBestWord.length() > 0) {
- TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode);
+ Utils.Stats.onAutoCorrection(mWordComposer.getTypedWord(), mBestWord.toString(),
+ separatorCode);
mExpectingUpdateSelection = true;
commitBestWord(mBestWord);
+ if (!mBestWord.equals(mWordComposer.getTypedWord())) {
+ mWordSavedForAutoCorrectCancellation = mBestWord.toString();
+ }
// Add the word to the user unigram dictionary if it's not a known word
addToUserUnigramAndBigramDictionaries(mBestWord,
UserUnigramDictionary.FREQUENCY_FOR_TYPED);
@@ -1901,7 +1910,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
ic.commitCompletion(completionInfo);
}
- mCommittedLength = suggestion.length();
if (mSuggestionsView != null) {
mSuggestionsView.clear();
}
@@ -1950,9 +1958,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
} else {
addToOnlyBigramDictionary(suggestion, 1);
}
- LatinImeLogger.logOnManualSuggestion(mComposingStringBuilder.toString(),
+ LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(),
suggestion.toString(), index, suggestions.mWords);
- TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion);
// Follow it with a space
if (mInsertSpaceOnPickSuggestionManually) {
sendMagicSpace();
@@ -1974,11 +1981,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|| !AutoCorrection.isValidWord(
mSuggest.getUnigramDictionaries(), suggestion, true));
- // Fool the state watcher so that a subsequent backspace will not do a revert, unless
- // we just did a correction, in which case we need to stay in
- // TextEntryState.State.PICKED_SUGGESTION state.
- TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
- WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
+ Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE,
+ WordComposer.NOT_A_COORDINATE);
if (!showingAddToDictionaryHint) {
// If we're not showing the "Touch again to save", then show corrections again.
// In case the cursor position doesn't change, make sure we show the suggestions again.
@@ -2019,7 +2023,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
}
mHasUncommittedTypedChars = false;
- mCommittedLength = bestWord.length();
}
private static final WordComposer sEmptyWordComposer = new WordComposer();
@@ -2035,7 +2038,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
mSettingsValues.mWordSeparators);
SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(sEmptyWordComposer,
- prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo());
+ prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo(), mCorrectionMode);
if (builder.size() > 0) {
// Explicitly supply an empty typed word (the no-second-arg version of
@@ -2162,52 +2165,68 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic,
final CharSequence word) {
mWordComposer.setComposingWord(word, mKeyboardSwitcher.getLatinKeyboard());
- mComposingStringBuilder.setLength(0);
- mComposingStringBuilder.append(word);
// mBestWord will be set appropriately by updateSuggestions() called by the handler
mBestWord = null;
mHasUncommittedTypedChars = true;
mComposingStateManager.onStartComposingText();
- TextEntryState.restartSuggestionsOnWordBeforeCursor();
ic.deleteSurroundingText(word.length(), 0);
ic.setComposingText(word, 1);
mHandler.postUpdateSuggestions();
}
// "ic" must not be null
- private void revertLastWord(final InputConnection ic) {
- if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) {
- sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
- return;
+ private void cancelAutoCorrect(final InputConnection ic) {
+ final int cancelLength = mWordSavedForAutoCorrectCancellation.length();
+ final CharSequence separator = ic.getTextBeforeCursor(1, 0);
+ if (DEBUG) {
+ final String wordBeforeCursor =
+ ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength)
+ .toString();
+ if (!mWordSavedForAutoCorrectCancellation.equals(wordBeforeCursor)) {
+ throw new RuntimeException("cancelAutoCorrect check failed: we thought we were "
+ + "reverting \"" + mWordSavedForAutoCorrectCancellation
+ + "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
+ }
+ if (mWordComposer.getTypedWord().equals(wordBeforeCursor)) {
+ throw new RuntimeException("cancelAutoCorrect check failed: we wanted to cancel "
+ + "auto correction and revert to \"" + mWordComposer.getTypedWord()
+ + "\" but we found this very string before the cursor");
+ }
}
+ ic.deleteSurroundingText(cancelLength + 1, 0);
- final CharSequence separator = ic.getTextBeforeCursor(1, 0);
- ic.deleteSurroundingText(1, 0);
- final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
- ic.deleteSurroundingText(mCommittedLength, 0);
-
- // Re-insert "separator" only when the deleted character was word separator and the
- // composing text wasn't equal to the auto-corrected text which can be found before
- // the cursor.
- if (!TextUtils.isEmpty(separator)
- && mSettingsValues.isWordSeparator(separator.charAt(0))
- && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) {
- ic.commitText(mComposingStringBuilder, 1);
- TextEntryState.acceptedTyped(mComposingStringBuilder);
- ic.commitText(separator, 1);
- TextEntryState.typedCharacter(separator.charAt(0), true,
- WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
- // Clear composing text
- mComposingStringBuilder.setLength(0);
- } else {
- // Note: this relies on the last word still being held in the WordComposer
- // Note: in the interest of code simplicity, we may want to just call
- // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving
- // the old WordComposer allows to reuse the actual typed coordinates.
- mHasUncommittedTypedChars = true;
- ic.setComposingText(mComposingStringBuilder, 1);
- TextEntryState.backspace();
+ // Re-insert the separator
+ ic.commitText(mWordComposer.getTypedWord(), 1);
+ ic.commitText(separator, 1);
+ Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE,
+ WordComposer.NOT_A_COORDINATE);
+ mHandler.cancelUpdateBigramPredictions();
+ mHandler.postUpdateSuggestions();
+ }
+
+ // "ic" must not be null
+ private void restartSuggestionsOnManuallyPickedTypedWord(final InputConnection ic) {
+ final int restartLength = mWordComposer.size();
+ if (DEBUG) {
+ final String wordBeforeCursor =
+ ic.getTextBeforeCursor(restartLength + 1, 0).subSequence(0, restartLength)
+ .toString();
+ if (!mWordComposer.getTypedWord().equals(wordBeforeCursor)) {
+ throw new RuntimeException("restartSuggestionsOnManuallyPickedTypedWord "
+ + "check failed: we thought we were reverting \""
+ + mWordComposer.getTypedWord()
+ + "\", but before the cursor we found \""
+ + wordBeforeCursor + "\"");
+ }
}
+ ic.deleteSurroundingText(restartLength + 1, 0);
+
+ // Note: this relies on the last word still being held in the WordComposer
+ // Note: in the interest of code simplicity, we may want to just call
+ // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving
+ // the old WordComposer allows to reuse the actual typed coordinates.
+ mHasUncommittedTypedChars = true;
+ ic.setComposingText(mWordComposer.getTypedWord(), 1);
mHandler.cancelUpdateBigramPredictions();
mHandler.postUpdateSuggestions();
}
@@ -2321,11 +2340,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
};
- // update keypress sound volume
- private void updateSoundEffectVolume() {
- mFxVolume = Utils.getCurrentKeypressSoundVolume(mPrefs, mResources);
- }
-
// update flags for silent mode
private void updateRingerMode() {
if (mAudioManager == null) {
@@ -2335,10 +2349,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
}
- private void updateKeypressVibrationDuration() {
- mKeypressVibrationDuration = Utils.getCurrentVibrationDuration(mPrefs, mResources);
- }
-
private void playKeyClick(int primaryCode) {
// if mAudioManager is null, we don't have the ringer state yet
// mAudioManager will be set by updateRingerMode
@@ -2363,7 +2373,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
sound = AudioManager.FX_KEYPRESS_STANDARD;
break;
}
- mAudioManager.playSoundEffect(sound, mFxVolume);
+ mAudioManager.playSoundEffect(sound, mSettingsValues.mFxVolume);
}
}
@@ -2371,7 +2381,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
if (!mSettingsValues.mVibrateOn) {
return;
}
- if (mKeypressVibrationDuration < 0) {
+ if (mSettingsValues.mKeypressVibrationDuration < 0) {
// Go ahead with the system default
LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
if (inputView != null) {
@@ -2380,7 +2390,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
} else if (mVibrator != null) {
- mVibrator.vibrate(mKeypressVibrationDuration);
+ mVibrator.vibrate(mSettingsValues.mKeypressVibrationDuration);
}
}
@@ -2399,15 +2409,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE;
mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect)
? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
- if (mSuggest != null) {
- mSuggest.setCorrectionMode(mCorrectionMode);
- }
}
private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) {
- final String suggestionVisiblityStr = prefs.getString(
- Settings.PREF_SHOW_SUGGESTIONS_SETTING,
- res.getString(R.string.prefs_suggestion_visibility_default_value));
+ final String suggestionVisiblityStr = mSettingsValues.mShowSuggestionsSetting;
for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
if (suggestionVisiblityStr.equals(res.getString(visibility))) {
mSuggestionVisibility = visibility;
@@ -2446,7 +2451,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
switch (position) {
case 0:
Intent intent = CompatUtils.getInputLanguageSelectionIntent(
- mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
+ Utils.getInputMethodId(mImm, getPackageName()),
+ Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
@@ -2495,35 +2501,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final Printer p = new PrintWriterPrinter(fout);
p.println("LatinIME state :");
- p.println(" Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
- p.println(" mComposingStringBuilder=" + mComposingStringBuilder.toString());
+ final Keyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
+ final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
+ p.println(" Keyboard mode = " + keyboardMode);
p.println(" mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
p.println(" mCorrectionMode=" + mCorrectionMode);
p.println(" mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
p.println(" mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
p.println(" mInsertSpaceOnPickSuggestionManually=" + mInsertSpaceOnPickSuggestionManually);
p.println(" mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
- p.println(" TextEntryState.state=" + TextEntryState.getState());
p.println(" mSoundOn=" + mSettingsValues.mSoundOn);
p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn);
p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
}
-
- // Characters per second measurement
-
- private long mLastCpsTime;
- private static final int CPS_BUFFER_SIZE = 16;
- private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
- private int mCpsIndex;
-
- private void measureCps() {
- long now = System.currentTimeMillis();
- if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
- mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
- mLastCpsTime = now;
- mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
- long total = 0;
- for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
- System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
- }
}
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index ae8eb374b..cbac4d31c 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -33,7 +33,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
}
- public static void init(Context context, SharedPreferences prefs) {
+ public static void init(LatinIME context, SharedPreferences prefs) {
}
public static void commit() {
@@ -78,4 +78,8 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void onPrintAllUsabilityStudyLogs() {
}
+
+ public static boolean isResearcherPackage(Context context) {
+ return false;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index 7d6efa584..5af21452a 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -38,7 +38,6 @@ import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.View;
-import android.view.inputmethod.EditorInfo;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
@@ -46,12 +45,10 @@ import android.widget.TextView;
import com.android.inputmethod.compat.CompatUtils;
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
import com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
-import com.android.inputmethod.compat.InputTypeCompatUtils;
import com.android.inputmethod.compat.VibratorCompatWrapper;
import com.android.inputmethod.deprecated.VoiceProxy;
import com.android.inputmethodcommon.InputMethodSettingsActivity;
-import java.util.Arrays;
import java.util.Locale;
public class Settings extends InputMethodSettingsActivity
@@ -61,257 +58,39 @@ public class Settings extends InputMethodSettingsActivity
public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false;
- public static final String PREF_GENERAL_SETTINGS_KEY = "general_settings";
+ // In the same order as xml/prefs.xml
+ public static final String PREF_GENERAL_SETTINGS = "general_settings";
+ public static final String PREF_SUBTYPES_SETTINGS = "subtype_settings";
+ public static final String PREF_AUTO_CAP = "auto_cap";
public static final String PREF_VIBRATE_ON = "vibrate_on";
public static final String PREF_SOUND_ON = "sound_on";
- public static final String PREF_KEY_PREVIEW_POPUP_ON = "popup_on";
- public static final String PREF_AUTO_CAP = "auto_cap";
+ public static final String PREF_POPUP_ON = "popup_on";
public static final String PREF_SHOW_SETTINGS_KEY = "show_settings_key";
- public static final String PREF_VOICE_SETTINGS_KEY = "voice_mode";
- public static final String PREF_INPUT_LANGUAGE = "input_language";
- public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
- public static final String PREF_SUBTYPES = "subtype_settings";
-
+ public static final String PREF_VOICE_MODE = "voice_mode";
+ public static final String PREF_CORRECTION_SETTINGS = "correction_settings";
public static final String PREF_CONFIGURE_DICTIONARIES_KEY = "configure_dictionaries_key";
- public static final String PREF_CORRECTION_SETTINGS_KEY = "correction_settings";
- public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting";
public static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
- public static final String PREF_DEBUG_SETTINGS = "debug_settings";
-
- public static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
- public static final String PREF_BIGRAM_PREDICTIONS = "bigram_prediction";
-
- public static final String PREF_MISC_SETTINGS_KEY = "misc_settings";
-
+ public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting";
+ public static final String PREF_MISC_SETTINGS = "misc_settings";
+ public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
+ public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings";
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_KEY_ENABLE_SPAN_INSERT =
- "enable_span_insert";
-
- public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
-
- public static final String PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS =
+ public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict";
+ public static final String PREF_BIGRAM_SUGGESTION = "bigram_suggestion";
+ public static final String PREF_BIGRAM_PREDICTIONS = "bigram_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 =
"pref_keypress_sound_volume";
- // Dialog ids
- private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
-
- public static class Values {
- // From resources:
- public final int mDelayUpdateOldSuggestions;
- public final String mWordSeparators;
- public final String mMagicSpaceStrippers;
- public final String mMagicSpaceSwappers;
- public final String mSuggestPuncs;
- public final SuggestedWords mSuggestPuncList;
- private final String mSymbolsExcludedFromWordSeparators;
- public final CharSequence mHintToSaveText;
-
- // From preferences:
- public final boolean mSoundOn; // Sound setting private to Latin IME (see mSilentModeOn)
- public final boolean mVibrateOn;
- public final boolean mKeyPreviewPopupOn;
- public final int mKeyPreviewPopupDismissDelay;
- public final boolean mAutoCap;
- public final boolean mAutoCorrectEnabled;
- public final double mAutoCorrectionThreshold;
- // 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
- public final boolean mBigramPredictionEnabled;
- public final boolean mUseContactsDict;
- public final boolean mEnableSuggestionSpanInsertion;
-
- private final boolean mShowSettingsKey;
- private final boolean mVoiceKeyEnabled;
- private final boolean mVoiceKeyOnMain;
-
- public Values(final SharedPreferences prefs, final Context context,
- final String localeStr) {
- final Resources res = context.getResources();
- final Locale savedLocale;
- if (null != localeStr) {
- final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
- savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
- } else {
- savedLocale = null;
- }
-
- // Get the resources
- mDelayUpdateOldSuggestions = res.getInteger(
- R.integer.config_delay_update_old_suggestions);
- mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
- mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
- String wordSeparators = mMagicSpaceStrippers + mMagicSpaceSwappers
- + res.getString(R.string.magic_space_promoting_symbols);
- final String symbolsExcludedFromWordSeparators =
- res.getString(R.string.symbols_excluded_from_word_separators);
- for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
- wordSeparators = wordSeparators.replace(
- symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
- }
- mSymbolsExcludedFromWordSeparators = symbolsExcludedFromWordSeparators;
- mWordSeparators = wordSeparators;
- mSuggestPuncs = res.getString(R.string.suggested_punctuations);
- // TODO: it would be nice not to recreate this each time we change the configuration
- mSuggestPuncList = createSuggestPuncList(mSuggestPuncs);
- mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
-
- // Get the settings preferences
- final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator();
- mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON,
- res.getBoolean(R.bool.config_default_vibration_enabled));
- mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
- res.getBoolean(R.bool.config_default_sound_enabled));
- mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res);
- mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res);
- mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
- mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res);
- mBigramSuggestionEnabled = mAutoCorrectEnabled
- && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
- mBigramPredictionEnabled = mBigramSuggestionEnabled
- && isBigramPredictionEnabled(prefs, res);
- mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res);
- mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
- mEnableSuggestionSpanInsertion =
- prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
- final boolean defaultShowSettingsKey = res.getBoolean(
- R.bool.config_default_show_settings_key);
- mShowSettingsKey = isShowSettingsKeyOption(res)
- ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey)
- : defaultShowSettingsKey;
- final String voiceModeMain = res.getString(R.string.voice_mode_main);
- final String voiceModeOff = res.getString(R.string.voice_mode_off);
- final String voiceMode = prefs.getString(PREF_VOICE_SETTINGS_KEY, voiceModeMain);
- mVoiceKeyEnabled = voiceMode != null && !voiceMode.equals(voiceModeOff);
- mVoiceKeyOnMain = voiceMode != null && voiceMode.equals(voiceModeMain);
-
- LocaleUtils.setSystemLocale(res, savedLocale);
- }
- public boolean isSuggestedPunctuation(int code) {
- return mSuggestPuncs.contains(String.valueOf((char)code));
- }
-
- public boolean isWordSeparator(int code) {
- return mWordSeparators.contains(String.valueOf((char)code));
- }
-
- public boolean isSymbolExcludedFromWordSeparators(int code) {
- return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
- }
-
- public boolean isMagicSpaceStripper(int code) {
- return mMagicSpaceStrippers.contains(String.valueOf((char)code));
- }
-
- public boolean isMagicSpaceSwapper(int code) {
- return mMagicSpaceSwappers.contains(String.valueOf((char)code));
- }
-
- private static boolean isAutoCorrectEnabled(SharedPreferences sp, Resources resources) {
- final String currentAutoCorrectionSetting = sp.getString(
- Settings.PREF_AUTO_CORRECTION_THRESHOLD,
- resources.getString(R.string.auto_correction_threshold_mode_index_modest));
- final String autoCorrectionOff = resources.getString(
- R.string.auto_correction_threshold_mode_index_off);
- return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
- }
-
- // Public to access from KeyboardSwitcher. Should it have access to some
- // process-global instance instead?
- public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) {
- final boolean showPopupOption = resources.getBoolean(
- R.bool.config_enable_show_popup_on_keypress_option);
- if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview);
- return sp.getBoolean(Settings.PREF_KEY_PREVIEW_POPUP_ON,
- resources.getBoolean(R.bool.config_default_popup_preview));
- }
-
- // Likewise
- public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp,
- Resources resources) {
- return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
- Integer.toString(resources.getInteger(R.integer.config_delay_after_preview))));
- }
-
- private static boolean isBigramSuggestionEnabled(SharedPreferences sp, Resources resources,
- boolean autoCorrectEnabled) {
- final boolean showBigramSuggestionsOption = resources.getBoolean(
- R.bool.config_enable_bigram_suggestions_option);
- if (!showBigramSuggestionsOption) {
- return autoCorrectEnabled;
- }
- return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, resources.getBoolean(
- R.bool.config_default_bigram_suggestions));
- }
-
- private static boolean isBigramPredictionEnabled(SharedPreferences sp,
- Resources resources) {
- return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean(
- R.bool.config_default_bigram_prediction));
- }
-
- private static double getAutoCorrectionThreshold(SharedPreferences sp,
- Resources resources) {
- final String currentAutoCorrectionSetting = sp.getString(
- Settings.PREF_AUTO_CORRECTION_THRESHOLD,
- resources.getString(R.string.auto_correction_threshold_mode_index_modest));
- final String[] autoCorrectionThresholdValues = resources.getStringArray(
- R.array.auto_correction_threshold_values);
- // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
- double autoCorrectionThreshold = Double.MAX_VALUE;
- try {
- final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
- if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
- autoCorrectionThreshold = Double.parseDouble(
- autoCorrectionThresholdValues[arrayIndex]);
- }
- } catch (NumberFormatException e) {
- // Whenever the threshold settings are correct, never come here.
- autoCorrectionThreshold = Double.MAX_VALUE;
- Log.w(TAG, "Cannot load auto correction threshold setting."
- + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
- + ", autoCorrectionThresholdValues: "
- + Arrays.toString(autoCorrectionThresholdValues));
- }
- return autoCorrectionThreshold;
- }
-
- private static SuggestedWords createSuggestPuncList(final String puncs) {
- SuggestedWords.Builder builder = new SuggestedWords.Builder();
- if (puncs != null) {
- for (int i = 0; i < puncs.length(); i++) {
- builder.addWord(puncs.subSequence(i, i + 1));
- }
- }
- return builder.setIsPunctuationSuggestions().build();
- }
-
- public static boolean isShowSettingsKeyOption(final Resources resources) {
- return resources.getBoolean(R.bool.config_enable_show_settings_key_option);
-
- }
-
- public boolean isSettingsKeyEnabled() {
- return mShowSettingsKey;
- }
-
- public boolean isVoiceKeyEnabled(EditorInfo editorInfo) {
- final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
- final int inputType = (editorInfo != null) ? editorInfo.inputType : 0;
- return shortcutImeEnabled && mVoiceKeyEnabled
- && !InputTypeCompatUtils.isPasswordInputType(inputType);
- }
+ public static final String PREF_INPUT_LANGUAGE = "input_language";
+ public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
+ public static final String PREF_DEBUG_SETTINGS = "debug_settings";
- public boolean isVoiceKeyOnMain() {
- return mVoiceKeyOnMain;
- }
- }
+ // Dialog ids
+ private static final int VOICE_INPUT_CONFIRM_DIALOG = 0;
private PreferenceScreen mInputLanguageSelection;
private PreferenceScreen mKeypressVibrationDurationSettingsPref;
@@ -365,9 +144,9 @@ public class Settings extends InputMethodSettingsActivity
final Context context = getActivityInternal();
addPreferencesFromResource(R.xml.prefs);
- mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES);
+ mInputLanguageSelection = (PreferenceScreen) findPreference(PREF_SUBTYPES_SETTINGS);
mInputLanguageSelection.setOnPreferenceClickListener(this);
- mVoicePreference = (ListPreference) findPreference(PREF_VOICE_SETTINGS_KEY);
+ mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE);
mShowSettingsKeyPreference = (CheckBoxPreference) findPreference(PREF_SHOW_SETTINGS_KEY);
mShowCorrectionSuggestionsPreference =
(ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING);
@@ -375,12 +154,12 @@ public class Settings extends InputMethodSettingsActivity
prefs.registerOnSharedPreferenceChangeListener(this);
mVoiceModeOff = getString(R.string.voice_mode_off);
- mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
+ mVoiceOn = !(prefs.getString(PREF_VOICE_MODE, mVoiceModeOff)
.equals(mVoiceModeOff));
mAutoCorrectionThresholdPreference =
(ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD);
- mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
+ mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTION);
mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS);
mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS);
if (mDebugSettingsPreference != null) {
@@ -393,13 +172,13 @@ public class Settings extends InputMethodSettingsActivity
ensureConsistencyOfAutoCorrectionSettings();
final PreferenceGroup generalSettings =
- (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS_KEY);
+ (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS);
final PreferenceGroup textCorrectionGroup =
- (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS_KEY);
+ (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS);
final PreferenceGroup miscSettings =
- (PreferenceGroup) findPreference(PREF_MISC_SETTINGS_KEY);
+ (PreferenceGroup) findPreference(PREF_MISC_SETTINGS);
- if (!Values.isShowSettingsKeyOption(res)) {
+ if (!SettingsValues.isShowSettingsKeyOptionEnabled(res)) {
generalSettings.removePreference(mShowSettingsKeyPreference);
}
@@ -414,13 +193,13 @@ public class Settings extends InputMethodSettingsActivity
}
if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
- generalSettings.removePreference(findPreference(PREF_SUBTYPES));
+ generalSettings.removePreference(findPreference(PREF_SUBTYPES_SETTINGS));
}
final boolean showPopupOption = res.getBoolean(
R.bool.config_enable_show_popup_on_keypress_option);
if (!showPopupOption) {
- generalSettings.removePreference(findPreference(PREF_KEY_PREVIEW_POPUP_ON));
+ generalSettings.removePreference(findPreference(PREF_POPUP_ON));
}
final boolean showBigramSuggestionsOption = res.getBoolean(
@@ -446,7 +225,8 @@ public class Settings extends InputMethodSettingsActivity
if (null == mKeyPreviewPopupDismissDelay.getValue()) {
mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue);
}
- mKeyPreviewPopupDismissDelay.setEnabled(Values.isKeyPreviewPopupEnabled(prefs, res));
+ mKeyPreviewPopupDismissDelay.setEnabled(
+ SettingsValues.isKeyPreviewPopupEnabled(prefs, res));
final PreferenceScreen dictionaryLink =
(PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY);
@@ -457,17 +237,26 @@ public class Settings extends InputMethodSettingsActivity
textCorrectionGroup.removePreference(dictionaryLink);
}
- final boolean showUsabilityModeStudyOption = res.getBoolean(
- R.bool.config_enable_usability_study_mode_option);
- if (!showUsabilityModeStudyOption || !ENABLE_EXPERIMENTAL_SETTINGS) {
- final Preference pref = findPreference(PREF_USABILITY_STUDY_MODE);
- if (pref != null) {
- miscSettings.removePreference(pref);
+ final boolean isResearcherPackage = LatinImeLogger.isResearcherPackage(this);
+ final boolean showUsabilityStudyModeOption =
+ res.getBoolean(R.bool.config_enable_usability_study_mode_option)
+ || isResearcherPackage || ENABLE_EXPERIMENTAL_SETTINGS;
+ final Preference usabilityStudyPref = findPreference(PREF_USABILITY_STUDY_MODE);
+ if (!showUsabilityStudyModeOption) {
+ if (usabilityStudyPref != null) {
+ miscSettings.removePreference(usabilityStudyPref);
+ }
+ }
+ if (isResearcherPackage) {
+ if (usabilityStudyPref instanceof CheckBoxPreference) {
+ CheckBoxPreference checkbox = (CheckBoxPreference)usabilityStudyPref;
+ checkbox.setChecked(prefs.getBoolean(PREF_USABILITY_STUDY_MODE, true));
+ checkbox.setSummary(R.string.settings_warning_researcher_mode);
}
}
mKeypressVibrationDurationSettingsPref =
- (PreferenceScreen) findPreference(PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS);
+ (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS);
if (mKeypressVibrationDurationSettingsPref != null) {
mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener(
new OnPreferenceClickListener() {
@@ -523,20 +312,20 @@ public class Settings extends InputMethodSettingsActivity
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
(new BackupManager(getActivityInternal())).dataChanged();
// If turning on voice input, show dialog
- if (key.equals(PREF_VOICE_SETTINGS_KEY) && !mVoiceOn) {
- if (!prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
+ if (key.equals(PREF_VOICE_MODE) && !mVoiceOn) {
+ if (!prefs.getString(PREF_VOICE_MODE, mVoiceModeOff)
.equals(mVoiceModeOff)) {
showVoiceConfirmation();
}
- } else if (key.equals(PREF_KEY_PREVIEW_POPUP_ON)) {
+ } else if (key.equals(PREF_POPUP_ON)) {
final ListPreference popupDismissDelay =
(ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
if (null != popupDismissDelay) {
- popupDismissDelay.setEnabled(prefs.getBoolean(PREF_KEY_PREVIEW_POPUP_ON, true));
+ popupDismissDelay.setEnabled(prefs.getBoolean(PREF_POPUP_ON, true));
}
}
ensureConsistencyOfAutoCorrectionSettings();
- mVoiceOn = !(prefs.getString(PREF_VOICE_SETTINGS_KEY, mVoiceModeOff)
+ mVoiceOn = !(prefs.getString(PREF_VOICE_MODE, mVoiceModeOff)
.equals(mVoiceModeOff));
updateVoiceModeSummary();
updateShowCorrectionSuggestionsSummary();
@@ -662,7 +451,7 @@ public class Settings extends InputMethodSettingsActivity
SharedPreferences sp, Resources res) {
if (mKeypressVibrationDurationSettingsPref != null) {
mKeypressVibrationDurationSettingsPref.setSummary(
- Utils.getCurrentVibrationDuration(sp, res)
+ SettingsValues.getCurrentVibrationDuration(sp, res)
+ res.getString(R.string.settings_ms));
}
}
@@ -678,7 +467,7 @@ public class Settings extends InputMethodSettingsActivity
public void onClick(DialogInterface dialog, int whichButton) {
final int ms = Integer.valueOf(
mKeypressVibrationDurationSettingsTextView.getText().toString());
- sp.edit().putInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, ms).apply();
+ sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply();
updateKeypressVibrationDurationSettingsSummary(sp, res);
}
});
@@ -690,7 +479,7 @@ public class Settings extends InputMethodSettingsActivity
});
final View v = context.getLayoutInflater().inflate(
R.layout.vibration_settings_dialog, null);
- final int currentMs = Utils.getCurrentVibrationDuration(
+ final int currentMs = SettingsValues.getCurrentVibrationDuration(
getPreferenceManager().getSharedPreferences(), getResources());
mKeypressVibrationDurationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value);
final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings);
@@ -719,8 +508,8 @@ public class Settings extends InputMethodSettingsActivity
private void updateKeypressSoundVolumeSummary(SharedPreferences sp, Resources res) {
if (mKeypressSoundVolumeSettingsPref != null) {
- mKeypressSoundVolumeSettingsPref.setSummary(
- String.valueOf((int)(Utils.getCurrentKeypressSoundVolume(sp, res) * 100)));
+ mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf(
+ (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100)));
}
}
@@ -749,8 +538,8 @@ public class Settings extends InputMethodSettingsActivity
});
final View v = context.getLayoutInflater().inflate(
R.layout.sound_effect_volume_dialog, null);
- final int currentVolumeInt = (int)(Utils.getCurrentKeypressSoundVolume(
- getPreferenceManager().getSharedPreferences(), getResources()) * 100);
+ final int currentVolumeInt =
+ (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100);
mKeypressSoundVolumeSettingsTextView =
(TextView)v.findViewById(R.id.sound_effect_volume_value);
final SeekBar sb = (SeekBar)v.findViewById(R.id.sound_effect_volume_bar);
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
new file mode 100644
index 000000000..0ad1c1529
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Build;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.inputmethod.compat.InputTypeCompatUtils;
+import com.android.inputmethod.compat.VibratorCompatWrapper;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+public class SettingsValues {
+ private static final String TAG = SettingsValues.class.getSimpleName();
+
+ // From resources:
+ public final int mDelayUpdateOldSuggestions;
+ public final String mMagicSpaceStrippers;
+ public final String mMagicSpaceSwappers;
+ public final String mSuggestPuncs;
+ public final SuggestedWords mSuggestPuncList;
+ private final String mSymbolsExcludedFromWordSeparators;
+ public final String mWordSeparators;
+ public final CharSequence mHintToSaveText;
+ public final boolean mUseFullScreenMode;
+
+ // From preferences, in the same order as xml/prefs.xml:
+ public final boolean mAutoCap;
+ public final boolean mVibrateOn;
+ public final boolean mSoundOn;
+ public final boolean mKeyPreviewPopupOn;
+ private final boolean mShowSettingsKey;
+ private final String mVoiceMode;
+ private final String mAutoCorrectionThresholdRawValue;
+ public final String mShowSuggestionsSetting;
+ private final boolean mUsabilityStudyMode;
+ 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
+ public final boolean mBigramPredictionEnabled;
+ public final boolean mEnableSuggestionSpanInsertion;
+ private final int mVibrationDurationSettingsRawValue;
+ private final float mKeypressSoundVolumeRawValue;
+
+ // Deduced settings
+ public final int mKeypressVibrationDuration;
+ public final float mFxVolume;
+ public final int mKeyPreviewPopupDismissDelay;
+ public final boolean mAutoCorrectEnabled;
+ public final double mAutoCorrectionThreshold;
+ private final boolean mVoiceKeyEnabled;
+ private final boolean mVoiceKeyOnMain;
+
+ public SettingsValues(final SharedPreferences prefs, final Context context,
+ final String localeStr) {
+ final Resources res = context.getResources();
+ final Locale savedLocale;
+ if (null != localeStr) {
+ final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
+ savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
+ } else {
+ savedLocale = null;
+ }
+
+ // Get the resources
+ mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
+ mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
+ mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
+ mSuggestPuncs = res.getString(R.string.suggested_punctuations);
+ // TODO: it would be nice not to recreate this each time we change the configuration
+ mSuggestPuncList = createSuggestPuncList(mSuggestPuncs);
+ mSymbolsExcludedFromWordSeparators =
+ res.getString(R.string.symbols_excluded_from_word_separators);
+ mWordSeparators = createWordSeparators(mMagicSpaceStrippers, mMagicSpaceSwappers,
+ mSymbolsExcludedFromWordSeparators, res);
+ mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
+ mUseFullScreenMode = res.getBoolean(R.bool.config_use_fullscreen_mode);
+
+ // Get the settings preferences
+ mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
+ mVibrateOn = isVibrateOn(context, prefs, res);
+ mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
+ res.getBoolean(R.bool.config_default_sound_enabled));
+ mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res);
+ mShowSettingsKey = isSettingsKeyShown(prefs, res);
+ final String voiceModeMain = res.getString(R.string.voice_mode_main);
+ final String voiceModeOff = res.getString(R.string.voice_mode_off);
+ mVoiceMode = prefs.getString(Settings.PREF_VOICE_MODE, voiceModeMain);
+ mAutoCorrectionThresholdRawValue = prefs.getString(Settings.PREF_AUTO_CORRECTION_THRESHOLD,
+ res.getString(R.string.auto_correction_threshold_mode_index_modest));
+ mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING,
+ res.getString(R.string.prefs_suggestion_visibility_default_value));
+ mUsabilityStudyMode = getUsabilityStudyMode(prefs, res);
+ mKeyPreviewPopupDismissDelayRawValue = prefs.getString(
+ Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
+ Integer.toString(res.getInteger(R.integer.config_delay_after_preview)));
+ mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true);
+ mAutoCorrectEnabled = isAutoCorrectEnabled(prefs, res, mAutoCorrectionThresholdRawValue);
+ mBigramSuggestionEnabled = mAutoCorrectEnabled
+ && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
+ mBigramPredictionEnabled = mBigramSuggestionEnabled
+ && isBigramPredictionEnabled(prefs, res);
+ mEnableSuggestionSpanInsertion =
+ prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
+ mVibrationDurationSettingsRawValue =
+ prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1);
+ mKeypressSoundVolumeRawValue = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
+
+ // Compute other readable settings
+ mKeypressVibrationDuration = getCurrentVibrationDuration(prefs, res);
+ mFxVolume = getCurrentKeypressSoundVolume(prefs, res);
+ mKeyPreviewPopupDismissDelay = getKeyPreviewPopupDismissDelay(prefs, res);
+ mAutoCorrectionThreshold = getAutoCorrectionThreshold(prefs, res,
+ mAutoCorrectionThresholdRawValue);
+ mVoiceKeyEnabled = mVoiceMode != null && !mVoiceMode.equals(voiceModeOff);
+ mVoiceKeyOnMain = mVoiceMode != null && mVoiceMode.equals(voiceModeMain);
+
+ LocaleUtils.setSystemLocale(res, savedLocale);
+ }
+
+ // Helper functions to create member values.
+ private static SuggestedWords createSuggestPuncList(final String puncs) {
+ SuggestedWords.Builder builder = new SuggestedWords.Builder();
+ if (puncs != null) {
+ for (int i = 0; i < puncs.length(); i++) {
+ builder.addWord(puncs.subSequence(i, i + 1));
+ }
+ }
+ return builder.setIsPunctuationSuggestions().build();
+ }
+
+ private static String createWordSeparators(final String magicSpaceStrippers,
+ final String magicSpaceSwappers, final String symbolsExcludedFromWordSeparators,
+ final Resources res) {
+ String wordSeparators = magicSpaceStrippers + magicSpaceSwappers
+ + res.getString(R.string.magic_space_promoting_symbols);
+ for (int i = symbolsExcludedFromWordSeparators.length() - 1; i >= 0; --i) {
+ wordSeparators = wordSeparators.replace(
+ symbolsExcludedFromWordSeparators.substring(i, i + 1), "");
+ }
+ return wordSeparators;
+ }
+
+ private static boolean isSettingsKeyShown(final SharedPreferences prefs, final Resources res) {
+ final boolean defaultShowSettingsKey = res.getBoolean(
+ R.bool.config_default_show_settings_key);
+ return isShowSettingsKeyOptionEnabled(res)
+ ? prefs.getBoolean(Settings.PREF_SHOW_SETTINGS_KEY, defaultShowSettingsKey)
+ : defaultShowSettingsKey;
+ }
+
+ public static boolean isShowSettingsKeyOptionEnabled(final Resources resources) {
+ // TODO: Read this once and for all into a public final member
+ return resources.getBoolean(R.bool.config_enable_show_settings_key_option);
+ }
+
+ private static boolean isVibrateOn(final Context context, final SharedPreferences prefs,
+ final Resources res) {
+ final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator();
+ return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON,
+ res.getBoolean(R.bool.config_default_vibration_enabled));
+ }
+
+ public boolean isSuggestedPunctuation(int code) {
+ return mSuggestPuncs.contains(String.valueOf((char)code));
+ }
+
+ public boolean isWordSeparator(int code) {
+ return mWordSeparators.contains(String.valueOf((char)code));
+ }
+
+ public boolean isSymbolExcludedFromWordSeparators(int code) {
+ return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code));
+ }
+
+ public boolean isMagicSpaceStripper(int code) {
+ return mMagicSpaceStrippers.contains(String.valueOf((char)code));
+ }
+
+ public boolean isMagicSpaceSwapper(int code) {
+ return mMagicSpaceSwappers.contains(String.valueOf((char)code));
+ }
+
+ private static boolean isAutoCorrectEnabled(final SharedPreferences sp,
+ final Resources resources, final String currentAutoCorrectionSetting) {
+ final String autoCorrectionOff = resources.getString(
+ R.string.auto_correction_threshold_mode_index_off);
+ return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
+ }
+
+ // Public to access from KeyboardSwitcher. Should it have access to some
+ // process-global instance instead?
+ public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) {
+ final boolean showPopupOption = resources.getBoolean(
+ R.bool.config_enable_show_popup_on_keypress_option);
+ if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview);
+ return sp.getBoolean(Settings.PREF_POPUP_ON,
+ resources.getBoolean(R.bool.config_default_popup_preview));
+ }
+
+ // Likewise
+ public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp,
+ Resources resources) {
+ // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here.
+ return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
+ Integer.toString(resources.getInteger(R.integer.config_delay_after_preview))));
+ }
+
+ private static boolean isBigramSuggestionEnabled(final SharedPreferences sp,
+ final Resources resources, final boolean autoCorrectEnabled) {
+ final boolean showBigramSuggestionsOption = resources.getBoolean(
+ R.bool.config_enable_bigram_suggestions_option);
+ if (!showBigramSuggestionsOption) {
+ return autoCorrectEnabled;
+ }
+ return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTION, resources.getBoolean(
+ R.bool.config_default_bigram_suggestions));
+ }
+
+ private static boolean isBigramPredictionEnabled(final SharedPreferences sp,
+ final Resources resources) {
+ return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean(
+ R.bool.config_default_bigram_prediction));
+ }
+
+ private static double getAutoCorrectionThreshold(final SharedPreferences sp,
+ final Resources resources, final String currentAutoCorrectionSetting) {
+ final String[] autoCorrectionThresholdValues = resources.getStringArray(
+ R.array.auto_correction_threshold_values);
+ // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
+ double autoCorrectionThreshold = Double.MAX_VALUE;
+ try {
+ final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
+ if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
+ autoCorrectionThreshold = Double.parseDouble(
+ autoCorrectionThresholdValues[arrayIndex]);
+ }
+ } catch (NumberFormatException e) {
+ // Whenever the threshold settings are correct, never come here.
+ autoCorrectionThreshold = Double.MAX_VALUE;
+ Log.w(TAG, "Cannot load auto correction threshold setting."
+ + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
+ + ", autoCorrectionThresholdValues: "
+ + Arrays.toString(autoCorrectionThresholdValues));
+ }
+ return autoCorrectionThreshold;
+ }
+
+ public boolean isSettingsKeyEnabled() {
+ return mShowSettingsKey;
+ }
+
+ public boolean isVoiceKeyEnabled(final EditorInfo editorInfo) {
+ final boolean shortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled();
+ final int inputType = (editorInfo != null) ? editorInfo.inputType : 0;
+ return shortcutImeEnabled && mVoiceKeyEnabled
+ && !InputTypeCompatUtils.isPasswordInputType(inputType);
+ }
+
+ public boolean isVoiceKeyOnMain() {
+ return mVoiceKeyOnMain;
+ }
+
+ // Accessed from the settings interface, hence public
+ public static float getCurrentKeypressSoundVolume(final SharedPreferences sp,
+ final Resources res) {
+ // TODO: use mVibrationDurationSettingsRawValue instead of reading it again here
+ final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
+ if (volume >= 0) {
+ return volume;
+ }
+
+ final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes);
+ final String hardwarePrefix = Build.HARDWARE + ",";
+ for (final String element : volumePerHardwareList) {
+ if (element.startsWith(hardwarePrefix)) {
+ return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1));
+ }
+ }
+ return -1.0f;
+ }
+
+ // Likewise
+ public static int getCurrentVibrationDuration(final SharedPreferences sp,
+ final Resources res) {
+ // TODO: use mKeypressVibrationDuration instead of reading it again here
+ final int ms = sp.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1);
+ if (ms >= 0) {
+ return ms;
+ }
+ final String[] durationPerHardwareList = res.getStringArray(
+ R.array.keypress_vibration_durations);
+ final String hardwarePrefix = Build.HARDWARE + ",";
+ for (final String element : durationPerHardwareList) {
+ if (element.startsWith(hardwarePrefix)) {
+ return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1));
+ }
+ }
+ return -1;
+ }
+
+ // Likewise
+ public static boolean getUsabilityStudyMode(final SharedPreferences prefs,
+ final Resources res) {
+ // TODO: use mUsabilityStudyMode instead of reading it again here
+ return prefs.getBoolean(Settings.PREF_USABILITY_STUDY_MODE, true);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index b618ca7ed..e9ca390d3 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -43,9 +43,8 @@ public class Suggest implements Dictionary.WordCallback {
public static final int APPROX_MAX_WORD_LENGTH = 32;
public static final int CORRECTION_NONE = 0;
- public static final int CORRECTION_BASIC = 1;
- public static final int CORRECTION_FULL = 2;
- public static final int CORRECTION_FULL_BIGRAM = 3;
+ public static final int CORRECTION_FULL = 1;
+ public static final int CORRECTION_FULL_BIGRAM = 2;
/**
* Words that appear in both bigram and unigram data gets multiplier ranging from
@@ -109,8 +108,6 @@ public class Suggest implements Dictionary.WordCallback {
private boolean mIsAllUpperCase;
private int mTrailingSingleQuotesCount;
- private int mCorrectionMode = CORRECTION_BASIC;
-
public Suggest(final Context context, final int dictionaryResId, final Locale locale) {
initAsynchronously(context, dictionaryResId, locale);
}
@@ -171,10 +168,6 @@ public class Suggest implements Dictionary.WordCallback {
}.start();
}
- public void setCorrectionMode(int mode) {
- mCorrectionMode = mode;
- }
-
// The main dictionary could have been loaded asynchronously. Don't cache the return value
// of this method.
public boolean hasMainDictionary() {
@@ -253,9 +246,10 @@ public class Suggest implements Dictionary.WordCallback {
* @return suggested words object.
*/
public SuggestedWords getSuggestions(final WordComposer wordComposer,
- final CharSequence prevWordForBigram, final ProximityInfo proximityInfo) {
+ final CharSequence prevWordForBigram, final ProximityInfo proximityInfo,
+ final int correctionMode) {
return getSuggestedWordBuilder(wordComposer, prevWordForBigram,
- proximityInfo).build();
+ proximityInfo, correctionMode).build();
}
private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) {
@@ -288,7 +282,7 @@ public class Suggest implements Dictionary.WordCallback {
// TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
public SuggestedWords.Builder getSuggestedWordBuilder(
final WordComposer wordComposer, CharSequence prevWordForBigram,
- final ProximityInfo proximityInfo) {
+ final ProximityInfo proximityInfo, final int correctionMode) {
LatinImeLogger.onStartSuggestion(prevWordForBigram);
mAutoCorrection.init();
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
@@ -308,8 +302,7 @@ public class Suggest implements Dictionary.WordCallback {
}
mConsideredWord = consideredWord;
- if (wordComposer.size() <= 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM
- || mCorrectionMode == CORRECTION_BASIC)) {
+ if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) {
// At first character typed, search only the bigrams
Arrays.fill(mBigramScores, 0);
collectGarbage(mBigramSuggestions, PREF_MAX_BIGRAMS);
@@ -373,7 +366,7 @@ public class Suggest implements Dictionary.WordCallback {
mWhiteListDictionary.getWhitelistedWord(consideredWordString));
mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer,
- mSuggestions, mScores, consideredWord, mAutoCorrectionThreshold, mCorrectionMode,
+ mSuggestions, mScores, consideredWord, mAutoCorrectionThreshold, correctionMode,
whitelistedWord);
if (whitelistedWord != null) {
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
deleted file mode 100644
index a6041b310..000000000
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.latin.Utils.RingCharBuffer;
-
-import android.util.Log;
-
-public class TextEntryState {
- private static final String TAG = TextEntryState.class.getSimpleName();
- private static final boolean DEBUG = false;
-
- private static final int UNKNOWN = 0;
- private static final int START = 1;
- private static final int IN_WORD = 2;
- private static final int ACCEPTED_DEFAULT = 3;
- private static final int PICKED_SUGGESTION = 4;
- private static final int PUNCTUATION_AFTER_ACCEPTED = 5;
- private static final int SPACE_AFTER_ACCEPTED = 6;
- private static final int SPACE_AFTER_PICKED = 7;
- private static final int UNDO_COMMIT = 8;
-
- private static int sState = UNKNOWN;
- private static int sPreviousState = UNKNOWN;
-
- private static void setState(final int newState) {
- sPreviousState = sState;
- sState = newState;
- }
-
- public static void acceptedDefault(CharSequence typedWord, CharSequence actualWord,
- int separatorCode) {
- if (typedWord == null) return;
- setState(ACCEPTED_DEFAULT);
- LatinImeLogger.logOnAutoCorrection(
- typedWord.toString(), actualWord.toString(), separatorCode);
- if (DEBUG)
- displayState("acceptedDefault", "typedWord", typedWord, "actualWord", actualWord);
- }
-
- // State.ACCEPTED_DEFAULT will be changed to other sub-states
- // (see "case ACCEPTED_DEFAULT" in typedCharacter() below),
- // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state.
- public static void backToAcceptedDefault(CharSequence typedWord) {
- if (typedWord == null) return;
- switch (sState) {
- case SPACE_AFTER_ACCEPTED:
- case PUNCTUATION_AFTER_ACCEPTED:
- case IN_WORD:
- setState(ACCEPTED_DEFAULT);
- break;
- default:
- break;
- }
- if (DEBUG) displayState("backToAcceptedDefault", "typedWord", typedWord);
- }
-
- public static void acceptedTyped(CharSequence typedWord) {
- setState(PICKED_SUGGESTION);
- if (DEBUG) displayState("acceptedTyped", "typedWord", typedWord);
- }
-
- public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
- setState(PICKED_SUGGESTION);
- if (DEBUG)
- displayState("acceptedSuggestion", "typedWord", typedWord, "actualWord", actualWord);
- }
-
- public static void typedCharacter(char c, boolean isSeparator, int x, int y) {
- final boolean isSpace = (c == Keyboard.CODE_SPACE);
- switch (sState) {
- case IN_WORD:
- if (isSpace || isSeparator) {
- setState(START);
- } else {
- // State hasn't changed.
- }
- break;
- case ACCEPTED_DEFAULT:
- case SPACE_AFTER_PICKED:
- case PUNCTUATION_AFTER_ACCEPTED:
- if (isSpace) {
- setState(SPACE_AFTER_ACCEPTED);
- } else if (isSeparator) {
- // Swap
- setState(PUNCTUATION_AFTER_ACCEPTED);
- } else {
- setState(IN_WORD);
- }
- break;
- case PICKED_SUGGESTION:
- if (isSpace) {
- setState(SPACE_AFTER_PICKED);
- } else if (isSeparator) {
- // Swap
- setState(PUNCTUATION_AFTER_ACCEPTED);
- } else {
- setState(IN_WORD);
- }
- break;
- case START:
- case UNKNOWN:
- case SPACE_AFTER_ACCEPTED:
- if (!isSpace && !isSeparator) {
- setState(IN_WORD);
- } else {
- setState(START);
- }
- break;
- case UNDO_COMMIT:
- if (isSpace || isSeparator) {
- setState(START);
- } else {
- setState(IN_WORD);
- }
- break;
- }
- RingCharBuffer.getInstance().push(c, x, y);
- if (isSeparator) {
- LatinImeLogger.logOnInputSeparator();
- } else {
- LatinImeLogger.logOnInputChar();
- }
- if (DEBUG) displayState("typedCharacter", "char", c, "isSeparator", isSeparator);
- }
-
- public static void backspace() {
- if (sState == ACCEPTED_DEFAULT) {
- setState(UNDO_COMMIT);
- LatinImeLogger.logOnAutoCorrectionCancelled();
- } else if (sState == UNDO_COMMIT) {
- setState(IN_WORD);
- }
- // TODO: tidy up this logic. At the moment, for example, writing a word goes to
- // ACCEPTED_DEFAULT, backspace will go to UNDO_COMMIT, another backspace will go to IN_WORD,
- // and subsequent backspaces will leave the status at IN_WORD, even if the user backspaces
- // past the end of the word. We are not in a word any more but the state is still IN_WORD.
- if (DEBUG) displayState("backspace");
- }
-
- public static void restartSuggestionsOnWordBeforeCursor() {
- if (UNKNOWN == sState || ACCEPTED_DEFAULT == sState) {
- // Here we can come from pretty much any state, except the ones that we can't
- // come from after backspace, so supposedly anything except UNKNOWN and
- // ACCEPTED_DEFAULT. Note : we could be in UNDO_COMMIT if
- // LatinIME#revertLastWord() was calling LatinIME#restartSuggestions...()
- Log.e(TAG, "Strange state change : coming from state " + sState);
- }
- setState(IN_WORD);
- }
-
- public static void reset() {
- setState(START);
- if (DEBUG) displayState("reset");
- }
-
- public static boolean isUndoCommit() {
- return sState == UNDO_COMMIT;
- }
-
- public static String getState() {
- return stateName(sState);
- }
-
- private static String stateName(int state) {
- switch (state) {
- case START: return "START";
- case IN_WORD: return "IN_WORD";
- case ACCEPTED_DEFAULT: return "ACCEPTED_DEFAULT";
- case PICKED_SUGGESTION: return "PICKED_SUGGESTION";
- case PUNCTUATION_AFTER_ACCEPTED: return "PUNCTUATION_AFTER_ACCEPTED";
- case SPACE_AFTER_ACCEPTED: return "SPACE_AFTER_ACCEPTED";
- case SPACE_AFTER_PICKED: return "SPACE_AFTER_PICKED";
- case UNDO_COMMIT: return "UNDO_COMMIT";
- default: return "UNKNOWN";
- }
- }
-
- private static void displayState(String title, Object ... args) {
- final StringBuilder sb = new StringBuilder(title);
- sb.append(':');
- for (int i = 0; i < args.length; i += 2) {
- sb.append(' ');
- sb.append(args[i]);
- sb.append('=');
- sb.append(args[i+1].toString());
- }
- sb.append(" state=");
- sb.append(stateName(sState));
- sb.append(" previous=");
- sb.append(stateName(sPreviousState));
- Log.d(TAG, sb.toString());
- }
-}
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 3d0aa09f1..de29e8f74 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -16,12 +16,21 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
+import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
+import com.android.inputmethod.compat.InputTypeCompatUtils;
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardId;
+
import android.content.Context;
-import android.content.SharedPreferences;
+import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.inputmethodservice.InputMethodService;
+import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
@@ -31,20 +40,15 @@ import android.text.format.DateUtils;
import android.util.Log;
import android.view.inputmethod.EditorInfo;
-import com.android.inputmethod.compat.InputMethodInfoCompatWrapper;
-import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
-import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper;
-import com.android.inputmethod.compat.InputTypeCompatUtils;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardId;
-
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -504,32 +508,89 @@ public class Utils {
});
}
- public void printAll() {
+ private synchronized String getBufferedLogs() {
+ mWriter.flush();
+ StringBuilder sb = new StringBuilder();
+ BufferedReader br = getBufferedReader();
+ String line;
+ try {
+ while ((line = br.readLine()) != null) {
+ sb.append('\n');
+ sb.append(line);
+ }
+ } catch (IOException e) {
+ Log.e(USABILITY_TAG, "Can't read log file.");
+ } finally {
+ if (LatinImeLogger.sDBG) {
+ Log.d(USABILITY_TAG, "Got all buffered logs\n" + sb.toString());
+ }
+ try {
+ br.close();
+ } catch (IOException e) {
+ // ignore.
+ }
+ }
+ return sb.toString();
+ }
+
+ public void emailResearcherLogsAll() {
mLoggingHandler.post(new Runnable() {
@Override
public void run() {
+ final Date date = new Date();
+ date.setTime(System.currentTimeMillis());
+ final String currentDateTimeString =
+ new SimpleDateFormat("yyyyMMdd-HHmmssZ").format(date);
+ if (mFile == null) {
+ Log.w(TAG, "No internal log file found.");
+ return;
+ }
+ if (mIms.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "Doesn't have the permission WRITE_EXTERNAL_STORAGE");
+ return;
+ }
mWriter.flush();
- StringBuilder sb = new StringBuilder();
- BufferedReader br = getBufferedReader();
- String line;
+ final String destPath = Environment.getExternalStorageDirectory()
+ + "/research-" + currentDateTimeString + ".log";
+ final File destFile = new File(destPath);
try {
- while ((line = br.readLine()) != null) {
- sb.append('\n');
- sb.append(line);
- }
- } catch (IOException e) {
- Log.e(USABILITY_TAG, "Can't read log file.");
- } finally {
- if (LatinImeLogger.sDBG) {
- Log.d(USABILITY_TAG, "output all logs\n" + sb.toString());
- }
- mIms.getCurrentInputConnection().commitText(sb.toString(), 0);
- try {
- br.close();
- } catch (IOException e) {
- // ignore.
- }
+ final FileChannel src = (new FileInputStream(mFile)).getChannel();
+ final FileChannel dest = (new FileOutputStream(destFile)).getChannel();
+ src.transferTo(0, src.size(), dest);
+ src.close();
+ dest.close();
+ } catch (FileNotFoundException e1) {
+ Log.w(TAG, e1);
+ return;
+ } catch (IOException e2) {
+ Log.w(TAG, e2);
+ return;
+ }
+ if (destFile == null || !destFile.exists()) {
+ Log.w(TAG, "Dest file doesn't exist.");
+ return;
}
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (LatinImeLogger.sDBG) {
+ Log.d(TAG, "Destination file URI is " + destFile.toURI());
+ }
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath));
+ intent.putExtra(Intent.EXTRA_SUBJECT,
+ "[Research Logs] " + currentDateTimeString);
+ mIms.startActivity(intent);
+ }
+ });
+ }
+
+ public void printAll() {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mIms.getCurrentInputConnection().commitText(getBufferedLogs(), 0);
}
});
}
@@ -778,40 +839,32 @@ public class Utils {
return s.toUpperCase(locale).charAt(0) + s.substring(1);
}
- public static int getCurrentVibrationDuration(SharedPreferences sp, Resources res) {
- final int ms = sp.getInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, -1);
- if (ms >= 0) {
- return ms;
- }
- final String[] durationPerHardwareList = res.getStringArray(
- R.array.keypress_vibration_durations);
- final String hardwarePrefix = Build.HARDWARE + ",";
- for (final String element : durationPerHardwareList) {
- if (element.startsWith(hardwarePrefix)) {
- return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1));
- }
- }
- return -1;
+ public static boolean willAutoCorrect(SuggestedWords suggestions) {
+ return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate
+ && !suggestions.shouldBlockAutoCorrection();
}
- public static float getCurrentKeypressSoundVolume(SharedPreferences sp, Resources res) {
- final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
- if (volume >= 0) {
- return volume;
+ public static class Stats {
+ public static void onNonSeparator(final char code, final int x,
+ final int y) {
+ RingCharBuffer.getInstance().push(code, x, y);
+ LatinImeLogger.logOnInputChar();
}
- final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes);
- final String hardwarePrefix = Build.HARDWARE + ",";
- for (final String element : volumePerHardwareList) {
- if (element.startsWith(hardwarePrefix)) {
- return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1));
- }
+ public static void onSeparator(final char code, final int x,
+ final int y) {
+ RingCharBuffer.getInstance().push(code, x, y);
+ LatinImeLogger.logOnInputSeparator();
}
- return -1.0f;
- }
- public static boolean willAutoCorrect(SuggestedWords suggestions) {
- return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate
- && !suggestions.shouldBlockAutoCorrection();
+ public static void onAutoCorrection(final String typedWord, final String correctedWord,
+ final int separatorCode) {
+ if (TextUtils.isEmpty(typedWord)) return;
+ LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, separatorCode);
+ }
+
+ public static void onAutoCorrectionCancellation() {
+ LatinImeLogger.logOnAutoCorrectionCancelled();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 44c89f73c..dfb00c8ab 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -231,9 +231,6 @@ public class WordComposer {
* @return the word that was typed so far
*/
public String getTypedWord() {
- if (size() == 0) {
- return null;
- }
return mTypedWord.toString();
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 8b6ecbef9..1ffee0de0 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -27,6 +27,7 @@ import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.ArraysCompatUtils;
+import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.BinaryDictionary;
import com.android.inputmethod.latin.Dictionary;
@@ -632,7 +633,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService
(isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
: SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO)
| (result.mHasRecommendedSuggestions
- ? SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS
+ ? SuggestionsInfoCompatUtils
+ .getValueOf_RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS()
: 0);
return new SuggestionsInfo(flags, result.mSuggestions);
} catch (RuntimeException e) {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java
new file mode 100644
index 000000000..3cd6a8944
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011 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.keyboard.internal;
+
+import android.test.AndroidTestCase;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.internal.KeyboardState.SwitchActions;
+
+public class KeyboardStateTests extends AndroidTestCase {
+ private static final int ALPHABET_UNSHIFTED = 0;
+ private static final int ALPHABET_MANUAL_SHIFTED = 1;
+ private static final int ALPHABET_AUTOMATIC_SHIFTED = 2;
+ private static final int ALPHABET_SHIFT_LOCKED = 3;
+ private static final int SYMBOLS_UNSHIFTED = 4;
+ private static final int SYMBOLS_SHIFTED = 5;
+
+ static class KeyboardSwitcher implements KeyboardState.SwitchActions {
+ public int mLayout = ALPHABET_UNSHIFTED;
+
+ @Override
+ public void setAlphabetKeyboard() {
+ mLayout = ALPHABET_UNSHIFTED;
+ }
+
+ @Override
+ public void setShifted(int shiftMode) {
+ if (shiftMode == SwitchActions.UNSHIFT) {
+ mLayout = ALPHABET_UNSHIFTED;
+ } else if (shiftMode == SwitchActions.MANUAL_SHIFT) {
+ mLayout = ALPHABET_MANUAL_SHIFTED;
+ } else if (shiftMode == SwitchActions.AUTOMATIC_SHIFT) {
+ mLayout = ALPHABET_AUTOMATIC_SHIFTED;
+ }
+ }
+
+ @Override
+ public void setShiftLocked(boolean shiftLocked) {
+ if (shiftLocked) {
+ mLayout = ALPHABET_SHIFT_LOCKED;
+ } else {
+ mLayout = ALPHABET_UNSHIFTED;
+ }
+ }
+
+ @Override
+ public void setSymbolsKeyboard() {
+ mLayout = SYMBOLS_UNSHIFTED;
+ }
+
+ @Override
+ public void setSymbolsShiftedKeyboard() {
+ mLayout = SYMBOLS_SHIFTED;
+ }
+ }
+
+ private KeyboardSwitcher mSwitcher;
+ private KeyboardState mState;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mSwitcher = new KeyboardSwitcher();
+ mState = new KeyboardState(mSwitcher);
+
+ final String layoutSwitchBackCharacter = "";
+ // TODO: Unit tests for non-distinct multi touch device.
+ final boolean hasDistinctMultitouch = true;
+ mState.onLoadKeyboard(layoutSwitchBackCharacter, hasDistinctMultitouch);
+ }
+
+ // Argument for KeyboardState.onPressShift and onReleaseShift.
+ private static final boolean NOT_SLIDING = false;
+ private static final boolean SLIDING = true;
+ // Argument for KeyboardState.onCodeInput.
+ private static final boolean SINGLE = true;
+ private static final boolean MULTI = false;
+
+
+ private void assertAlphabetNormal() {
+ assertEquals(ALPHABET_UNSHIFTED, mSwitcher.mLayout);
+ }
+
+ private void assertAlphabetManualShifted() {
+ assertEquals(ALPHABET_MANUAL_SHIFTED, mSwitcher.mLayout);
+ }
+
+ private void assertAlphabetAutomaticShifted() {
+ assertEquals(ALPHABET_AUTOMATIC_SHIFTED, mSwitcher.mLayout);
+ }
+
+ private void assertAlphabetShiftLocked() {
+ assertEquals(ALPHABET_SHIFT_LOCKED, mSwitcher.mLayout);
+ }
+
+ private void assertSymbolsNormal() {
+ assertEquals(SYMBOLS_UNSHIFTED, mSwitcher.mLayout);
+ }
+
+ private void assertSymbolsShifted() {
+ assertEquals(SYMBOLS_SHIFTED, mSwitcher.mLayout);
+ }
+
+ // Initial state test.
+ public void testLoadKeyboard() {
+ assertAlphabetNormal();
+ }
+
+ // Shift key in alphabet mode.
+ public void testShift() {
+ // Press/release shift key.
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+
+ // Press/release shift key.
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetNormal();
+
+ // TODO: Sliding test
+ }
+
+ // Switching between alphabet and symbols.
+ public void testAlphabetAndSymbols() {
+ // Press/release "?123" key.
+ mState.onPressSymbol();
+ assertSymbolsNormal();
+ mState.onReleaseSymbol();
+ assertSymbolsNormal();
+
+ // Press/release "ABC" key.
+ mState.onPressSymbol();
+ assertAlphabetNormal();
+ mState.onReleaseSymbol();
+ assertAlphabetNormal();
+
+ // TODO: Sliding test
+ // TODO: Snap back test
+ }
+
+ // Switching between symbols and symbols shifted.
+ public void testSymbolsAndSymbolsShifted() {
+ // Press/release "?123" key.
+ mState.onPressSymbol();
+ assertSymbolsNormal();
+ mState.onReleaseSymbol();
+ assertSymbolsNormal();
+
+ // Press/release "=\<" key.
+ mState.onPressShift(NOT_SLIDING);
+ assertSymbolsShifted();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertSymbolsShifted();
+
+ // Press/release "ABC" key.
+ mState.onPressSymbol();
+ assertAlphabetNormal();
+ mState.onReleaseSymbol();
+ assertAlphabetNormal();
+
+ // TODO: Sliding test
+ // TODO: Snap back test
+ }
+
+ // Automatic upper case test
+ public void testAutomaticUpperCase() {
+ // Update shift state with auto caps enabled.
+ mState.onUpdateShiftState(true);
+ assertAlphabetAutomaticShifted();
+
+ // Press shift key.
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ // Release shift key.
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetNormal();
+
+ // TODO: Chording test.
+ }
+
+ // TODO: UpdateShiftState with shift locked, etc.
+
+ // TODO: Multitouch test
+
+ // TODO: Change focus test.
+
+ // TODO: Change orientation test.
+
+ // Long press shift key.
+ // TODO: Move long press recognizing timer/logic into KeyboardState.
+ public void testLongPressShift() {
+ // Long press shift key
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ // Long press recognized in LatinKeyboardView.KeyTimerHandler.
+ mState.onToggleCapsLock();
+ assertAlphabetShiftLocked();
+ mState.onCodeInput(Keyboard.CODE_CAPSLOCK, SINGLE);
+ assertAlphabetShiftLocked();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetShiftLocked();
+
+ // Long press shift key.
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ // Long press recognized in LatinKeyboardView.KeyTimerHandler.
+ mState.onToggleCapsLock();
+ assertAlphabetNormal();
+ mState.onCodeInput(Keyboard.CODE_CAPSLOCK, SINGLE);
+ assertAlphabetNormal();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetNormal();
+ }
+
+ // Double tap shift key.
+ // TODO: Move double tap recognizing timer/logic into KeyboardState.
+ public void testDoubleTapShift() {
+ // First shift key tap.
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE);
+ assertAlphabetManualShifted();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ // Second shift key tap.
+ // Double tap recognized in LatinKeyboardView.KeyTimerHandler.
+ mState.onToggleCapsLock();
+ assertAlphabetShiftLocked();
+ mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE);
+ assertAlphabetShiftLocked();
+
+ // First shift key tap.
+ mState.onPressShift(NOT_SLIDING);
+ assertAlphabetManualShifted();
+ mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE);
+ assertAlphabetManualShifted();
+ mState.onReleaseShift(NOT_SLIDING);
+ assertAlphabetNormal();
+ // Second shift key tap.
+ // Second tap is ignored in LatinKeyboardView.KeyTimerHandler.
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
index 0d90e0ef3..06b192440 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
@@ -28,6 +28,7 @@ import java.util.Locale;
public class SuggestHelper {
protected final Suggest mSuggest;
+ protected int mCorrectionMode;
protected final LatinKeyboard mKeyboard;
private final KeyDetector mKeyDetector;
@@ -50,14 +51,14 @@ public class SuggestHelper {
}
private void init() {
- mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL);
+ setCorrectionMode(Suggest.CORRECTION_FULL);
mKeyDetector.setKeyboard(mKeyboard, 0, 0);
mKeyDetector.setProximityCorrectionEnabled(true);
mKeyDetector.setProximityThreshold(mKeyboard.mMostCommonKeyWidth);
}
public void setCorrectionMode(int correctionMode) {
- mSuggest.setCorrectionMode(correctionMode);
+ mCorrectionMode = correctionMode;
}
public boolean hasMainDictionary() {
@@ -78,13 +79,13 @@ public class SuggestHelper {
// TODO: This may be slow, but is OK for test so far.
public SuggestedWords getSuggestions(CharSequence typed) {
return mSuggest.getSuggestions(createWordComposer(typed), null,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
}
public CharSequence getFirstSuggestion(CharSequence typed) {
WordComposer word = createWordComposer(typed);
SuggestedWords suggestions = mSuggest.getSuggestions(word, null,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
// Note that suggestions.getWord(0) is the word user typed.
return suggestions.size() > 1 ? suggestions.getWord(1) : null;
}
@@ -92,7 +93,7 @@ public class SuggestHelper {
public CharSequence getAutoCorrection(CharSequence typed) {
WordComposer word = createWordComposer(typed);
SuggestedWords suggestions = mSuggest.getSuggestions(word, null,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
// Note that suggestions.getWord(0) is the word user typed.
return (suggestions.size() > 1 && mSuggest.hasAutoCorrection())
? suggestions.getWord(1) : null;
@@ -101,7 +102,7 @@ public class SuggestHelper {
public int getSuggestIndex(CharSequence typed, CharSequence expected) {
WordComposer word = createWordComposer(typed);
SuggestedWords suggestions = mSuggest.getSuggestions(word, null,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
// Note that suggestions.getWord(0) is the word user typed.
for (int i = 1; i < suggestions.size(); i++) {
if (TextUtils.equals(suggestions.getWord(i), expected))
@@ -113,7 +114,8 @@ public class SuggestHelper {
private void getBigramSuggestions(CharSequence previous, CharSequence typed) {
if (!TextUtils.isEmpty(previous) && (typed.length() > 1)) {
WordComposer firstChar = createWordComposer(Character.toString(typed.charAt(0)));
- mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo());
+ mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo(),
+ mCorrectionMode);
}
}
@@ -121,7 +123,7 @@ public class SuggestHelper {
WordComposer word = createWordComposer(typed);
getBigramSuggestions(previous, typed);
SuggestedWords suggestions = mSuggest.getSuggestions(word, previous,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
return suggestions.size() > 1 ? suggestions.getWord(1) : null;
}
@@ -129,7 +131,7 @@ public class SuggestHelper {
WordComposer word = createWordComposer(typed);
getBigramSuggestions(previous, typed);
SuggestedWords suggestions = mSuggest.getSuggestions(word, previous,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
return (suggestions.size() > 1 && mSuggest.hasAutoCorrection())
? suggestions.getWord(1) : null;
}
@@ -139,7 +141,7 @@ public class SuggestHelper {
WordComposer word = createWordComposer(typed);
getBigramSuggestions(previous, typed);
SuggestedWords suggestions = mSuggest.getSuggestions(word, previous,
- mKeyboard.getProximityInfo());
+ mKeyboard.getProximityInfo(), mCorrectionMode);
for (int i = 1; i < suggestions.size(); i++) {
if (TextUtils.equals(suggestions.getWord(i), expected))
return i;
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
index 023e20a10..863c2b254 100644
--- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
+++ b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
@@ -38,7 +38,7 @@ public class UserBigramSuggestHelper extends SuggestHelper {
Suggest.DIC_USER);
mUserBigram.setDatabaseMax(userBigramMax);
mUserBigram.setDatabaseDelete(userBigramDelete);
- mSuggest.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
+ setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
mSuggest.setUserBigramDictionary(mUserBigram);
}
@@ -59,7 +59,8 @@ public class UserBigramSuggestHelper extends SuggestHelper {
flushUserBigrams();
if (!TextUtils.isEmpty(previous) && !TextUtils.isEmpty(Character.toString(typed))) {
WordComposer firstChar = createWordComposer(Character.toString(typed));
- mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo());
+ mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo(),
+ mCorrectionMode);
boolean reloading = mUserBigram.reloadDictionaryIfRequired();
if (reloading) mUserBigram.waitForDictionaryLoading();
mUserBigram.getBigrams(firstChar, previous, mSuggest);