diff options
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); |