diff options
Diffstat (limited to 'java/src')
14 files changed, 302 insertions, 379 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index bc9dbc049..bad9a8aed 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -149,7 +149,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { settingsValues.isLanguageSwitchKeyEnabled()); mKeyboardLayoutSet = builder.build(); try { - mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); + mState.onLoadKeyboard(); mFeedbackManager.onSettingsChanged(settingsValues); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 25a1c6a00..5a77044b5 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -26,7 +26,7 @@ import com.android.inputmethod.latin.Constants; * * This class contains all keyboard state transition logic. * - * The input events are {@link #onLoadKeyboard(String)}, {@link #onSaveKeyboardState()}, + * The input events are {@link #onLoadKeyboard()}, {@link #onSaveKeyboardState()}, * {@link #onPressKey(int, boolean, int)}, {@link #onReleaseKey(int, boolean)}, * {@link #onCodeInput(int, boolean, int)}, {@link #onCancelInput(boolean)}, * {@link #onUpdateShiftState(int)}, {@link #onLongPressTimeout(int)}. @@ -74,7 +74,6 @@ public final class KeyboardState { private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3; private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4; private int mSwitchState = SWITCH_STATE_ALPHA; - private String mLayoutSwitchBackSymbols; private boolean mIsAlphabetMode; private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState(); @@ -109,15 +108,14 @@ public final class KeyboardState { } } - public KeyboardState(SwitchActions switchActions) { + public KeyboardState(final SwitchActions switchActions) { mSwitchActions = switchActions; } - public void onLoadKeyboard(String layoutSwitchBackSymbols) { + public void onLoadKeyboard() { if (DEBUG_EVENT) { Log.d(TAG, "onLoadKeyboard: " + this); } - mLayoutSwitchBackSymbols = layoutSwitchBackSymbols; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mPrevMainKeyboardWasShiftLocked = false; @@ -177,7 +175,7 @@ public final class KeyboardState { private static final int AUTOMATIC_SHIFT = 2; private static final int SHIFT_LOCK_SHIFTED = 3; - private void setShifted(int shiftMode) { + private void setShifted(final int shiftMode) { if (DEBUG_ACTION) { Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this); } @@ -216,7 +214,7 @@ public final class KeyboardState { } } - private void setShiftLocked(boolean shiftLocked) { + private void setShiftLocked(final boolean shiftLocked) { if (DEBUG_ACTION) { Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this); } @@ -313,7 +311,7 @@ public final class KeyboardState { mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; } - public void onPressKey(int code, boolean isSinglePointer, int autoCaps) { + public void onPressKey(final int code, final boolean isSinglePointer, final int autoCaps) { if (DEBUG_EVENT) { Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code) + " single=" + isSinglePointer + " autoCaps=" + autoCaps + " " + this); @@ -346,7 +344,7 @@ public final class KeyboardState { } } - public void onReleaseKey(int code, boolean withSliding) { + public void onReleaseKey(final int code, final boolean withSliding) { if (DEBUG_EVENT) { Log.d(TAG, "onReleaseKey: code=" + Constants.printableCode(code) + " sliding=" + withSliding + " " + this); @@ -364,7 +362,7 @@ public final class KeyboardState { mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; } - private void onReleaseSymbol(boolean withSliding) { + private void onReleaseSymbol(final boolean withSliding) { if (mSymbolKeyState.isChording()) { // Switch back to the previous keyboard mode if the user chords the mode change key and // another key, then releases the mode change key. @@ -378,7 +376,7 @@ public final class KeyboardState { mSymbolKeyState.onRelease(); } - public void onLongPressTimeout(int code) { + public void onLongPressTimeout(final int code) { if (DEBUG_EVENT) { Log.d(TAG, "onLongPressTimeout: code=" + Constants.printableCode(code) + " " + this); } @@ -388,7 +386,7 @@ public final class KeyboardState { } } - public void onUpdateShiftState(int autoCaps) { + public void onUpdateShiftState(final int autoCaps) { if (DEBUG_EVENT) { Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this); } @@ -404,7 +402,7 @@ public final class KeyboardState { resetKeyboardStateToAlphabet(); } - private void updateAlphabetShiftState(int autoCaps) { + private void updateAlphabetShiftState(final int autoCaps) { if (!mIsAlphabetMode) return; if (!mShiftKeyState.isReleasing()) { // Ignore update shift state event while the shift key is being pressed (including @@ -468,7 +466,7 @@ public final class KeyboardState { } } - private void onReleaseShift(boolean withSliding) { + private void onReleaseShift(final boolean withSliding) { if (mIsAlphabetMode) { final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked(); mIsInAlphabetUnshiftedFromShifted = false; @@ -523,7 +521,7 @@ public final class KeyboardState { mShiftKeyState.onRelease(); } - public void onCancelInput(boolean isSinglePointer) { + public void onCancelInput(final boolean isSinglePointer) { if (DEBUG_EVENT) { Log.d(TAG, "onCancelInput: single=" + isSinglePointer + " " + this); } @@ -542,17 +540,11 @@ public final class KeyboardState { || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; } - private static boolean isSpaceCharacter(int c) { + private static boolean isSpaceCharacter(final int c) { return c == Constants.CODE_SPACE || c == Constants.CODE_ENTER; } - private boolean isLayoutSwitchBackCharacter(int c) { - if (TextUtils.isEmpty(mLayoutSwitchBackSymbols)) return false; - if (mLayoutSwitchBackSymbols.indexOf(c) >= 0) return true; - return false; - } - - public void onCodeInput(int code, boolean isSinglePointer, int autoCaps) { + public void onCodeInput(final int code, final boolean isSinglePointer, final int autoCaps) { if (DEBUG_EVENT) { Log.d(TAG, "onCodeInput: code=" + Constants.printableCode(code) + " single=" + isSinglePointer @@ -592,17 +584,11 @@ public final class KeyboardState { || code == Constants.CODE_OUTPUT_TEXT)) { mSwitchState = SWITCH_STATE_SYMBOL; } - // Switch back to alpha keyboard mode immediately if user types one of the switch back - // characters. - if (isLayoutSwitchBackCharacter(code)) { - toggleAlphabetAndSymbols(); - mPrevSymbolsKeyboardWasShifted = false; - } break; case SWITCH_STATE_SYMBOL: // Switch back to alpha keyboard mode if user types one or more non-space/enter - // characters followed by a space/enter or one of the switch back characters. - if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) { + // characters followed by a space/enter. + if (isSpaceCharacter(code)) { toggleAlphabetAndSymbols(); mPrevSymbolsKeyboardWasShifted = false; } @@ -615,7 +601,7 @@ public final class KeyboardState { } } - private static String shiftModeToString(int shiftMode) { + private static String shiftModeToString(final int shiftMode) { switch (shiftMode) { case UNSHIFT: return "UNSHIFT"; case MANUAL_SHIFT: return "MANUAL"; @@ -624,7 +610,7 @@ public final class KeyboardState { } } - private static String switchStateToString(int switchState) { + private static String switchStateToString(final int switchState) { switch (switchState) { case SWITCH_STATE_ALPHA: return "ALPHA"; case SWITCH_STATE_SYMBOL_BEGIN: return "SYMBOL-BEGIN"; diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 8a1613120..f859d0ba3 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -29,8 +29,6 @@ import android.view.View; * complexity of settings and the like. */ public final class AudioAndHapticFeedbackManager { - public static final int MAX_KEYPRESS_VIBRATION_DURATION = 250; // millisecond - private AudioManager mAudioManager; private Vibrator mVibrator; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d02c4df7e..f4b7a1708 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -773,7 +773,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // to the user dictionary. if (null != mPositionalInfoForUserDictPendingAddition && mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord( - mConnection, editorInfo, mLastSelectionEnd)) { + mConnection, editorInfo, mLastSelectionEnd, + mSubtypeSwitcher.getCurrentSubtypeLocale())) { mPositionalInfoForUserDictPendingAddition = null; } // If tryReplaceWithActualWord returns false, we don't know what word was @@ -1223,11 +1224,17 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mPositionalInfoForUserDictPendingAddition = null; return; } + final String wordToEdit; + if (StringUtils.isAutoCapsMode(mLastComposedWord.mCapitalizedMode)) { + wordToEdit = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); + } else { + wordToEdit = word; + } mPositionalInfoForUserDictPendingAddition = new PositionalInfoForUserDictPendingAddition( - word, mLastSelectionEnd, getCurrentInputEditorInfo(), + wordToEdit, mLastSelectionEnd, getCurrentInputEditorInfo(), mLastComposedWord.mCapitalizedMode); - mUserDictionary.addWordToUserDictionary(word, 128); + mUserDictionary.addWordToUserDictionary(wordToEdit); } public void onWordAddedToUserDictionary(final String newSpelling) { @@ -1240,7 +1247,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mPositionalInfoForUserDictPendingAddition.setActualWordBeingAdded(newSpelling); if (mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord( - mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd)) { + mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd, + mSubtypeSwitcher.getCurrentSubtypeLocale())) { mPositionalInfoForUserDictPendingAddition = null; } } @@ -1476,7 +1484,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); } } - if (mWordComposer.size() <= 1) { + final int wordComposerSize = mWordComposer.size(); + // Since isComposingWord() is true, the size is at least 1. + final int lastChar = mWordComposer.getCodeAt(wordComposerSize - 1); + if (wordComposerSize <= 1) { // We auto-correct the previous (typed, not gestured) string iff it's one character // long. The reason for this is, even in the middle of gesture typing, you'll still // tap one-letter words and you want them auto-corrected (typically, "i" in English @@ -1490,8 +1501,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mExpectingUpdateSelection = true; // The following is necessary for the case where the user typed something but didn't - // manual pick it and didn't input any separator. - mSpaceState = SPACE_STATE_PHANTOM; + // manual pick it and didn't input any separator: we want to put a space between what + // has been entered and the coming gesture input result, so we go into phantom space + // state, which will be promoted to a space when the gesture result is committed. But if + // the current input ends in a word connector on the other hand, then we want to have + // the next input stick to the current input so we don't switch to phantom space state. + if (!mSettings.getCurrent().isWordConnector(lastChar)) { + mSpaceState = SPACE_STATE_PHANTOM; + } } else { final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); if (mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) { diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java index a33cefcd6..8493ef669 100644 --- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java +++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java @@ -18,6 +18,8 @@ package com.android.inputmethod.latin; import android.view.inputmethod.EditorInfo; +import java.util.Locale; + /** * Holder class for data about a word already committed but that may still be edited. * @@ -70,10 +72,11 @@ public final class PositionalInfoForUserDictPendingAddition { * @param connection The RichInputConnection through which to contact the editor. * @param editorInfo Information pertaining to the editor we are currently in. * @param currentCursorPosition The current cursor position, for checking purposes. + * @param locale The locale for changing case, if necessary * @return true if the edit has been successfully made, false if we need to try again later */ public boolean tryReplaceWithActualWord(final RichInputConnection connection, - final EditorInfo editorInfo, final int currentCursorPosition) { + final EditorInfo editorInfo, final int currentCursorPosition, final Locale locale) { // If we still don't know the actual word being added, we need to try again later. if (null == mActualWordBeingAdded) return false; // The entered text and the registered text were the same anyway : we can @@ -92,9 +95,12 @@ public final class PositionalInfoForUserDictPendingAddition { // so that it won't be tried again if (currentCursorPosition != mCursorPos) return true; // We have made all the checks : do the replacement and report success + // If this was auto-capitalized, we need to restore the case before committing + final String wordWithCaseFixed = StringUtils.applyAutoCapsMode(mActualWordBeingAdded, + mCapitalizedMode, locale); connection.setComposingRegion(currentCursorPosition - mOriginalWord.length(), currentCursorPosition); - connection.commitText(mActualWordBeingAdded, mActualWordBeingAdded.length()); + connection.commitText(wordWithCaseFixed, wordWithCaseFixed.length()); return true; } } diff --git a/java/src/com/android/inputmethod/latin/SeekBarDialog.java b/java/src/com/android/inputmethod/latin/SeekBarDialog.java deleted file mode 100644 index c736d1b1a..000000000 --- a/java/src/com/android/inputmethod/latin/SeekBarDialog.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2012 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.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; - -public final class SeekBarDialog implements DialogInterface.OnClickListener, - OnSeekBarChangeListener { - public interface Listener { - public void onPositiveButtonClick(final SeekBarDialog dialog); - public void onNegativeButtonClick(final SeekBarDialog dialog); - public void onNeutralButtonClick(final SeekBarDialog dialog); - public void onDismiss(final SeekBarDialog dialog); - public void onProgressChanged(final SeekBarDialog dialog); - public void onStartTrackingTouch(final SeekBarDialog dialog); - public void onStopTrackingTouch(final SeekBarDialog dialog); - } - - public static class Adapter implements Listener { - @Override - public void onPositiveButtonClick(final SeekBarDialog dialog) {} - @Override - public void onNegativeButtonClick(final SeekBarDialog dialog) {} - @Override - public void onNeutralButtonClick(final SeekBarDialog dialog) {} - @Override - public void onDismiss(final SeekBarDialog dialog) {} - @Override - public void onProgressChanged(final SeekBarDialog dialog) {} - @Override - public void onStartTrackingTouch(final SeekBarDialog dialog) {} - @Override - public void onStopTrackingTouch(final SeekBarDialog dialog) {} - } - - private static final Listener EMPTY_ADAPTER = new Adapter(); - - private final AlertDialog mDialog; - private final Listener mListener; - private final TextView mValueView; - private final SeekBar mSeekBar; - private final String mValueFormat; - - private int mValue; - - private SeekBarDialog(final Builder builder) { - final AlertDialog.Builder dialogBuilder = builder.mDialogBuilder; - dialogBuilder.setView(builder.mView); - dialogBuilder.setPositiveButton(android.R.string.ok, this); - dialogBuilder.setNegativeButton(android.R.string.cancel, this); - if (builder.mNeutralButtonTextResId != 0) { - dialogBuilder.setNeutralButton(builder.mNeutralButtonTextResId, this); - } - mDialog = dialogBuilder.create(); - mListener = (builder.mListener == null) ? EMPTY_ADAPTER : builder.mListener; - mValueView = (TextView)builder.mView.findViewById(R.id.seek_bar_dialog_value); - mSeekBar = (SeekBar)builder.mView.findViewById(R.id.seek_bar_dialog_bar); - mSeekBar.setMax(builder.mMaxValue); - mSeekBar.setOnSeekBarChangeListener(this); - if (builder.mValueFormatResId == 0) { - mValueFormat = "%s"; - } else { - mValueFormat = mDialog.getContext().getString(builder.mValueFormatResId); - } - } - - public void setValue(final int value, final boolean fromUser) { - mValue = value; - mValueView.setText(String.format(mValueFormat, value)); - if (!fromUser) { - mSeekBar.setProgress(value); - } - } - - public int getValue() { - return mValue; - } - - public CharSequence getValueText() { - return mValueView.getText(); - } - - public void show() { - mDialog.show(); - } - - public void dismiss() { - mDialog.dismiss(); - } - - @Override - public void onClick(final DialogInterface dialog, final int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - mListener.onPositiveButtonClick(this); - break; - case DialogInterface.BUTTON_NEGATIVE: - mListener.onNegativeButtonClick(this); - break; - case DialogInterface.BUTTON_NEUTRAL: - mListener.onNeutralButtonClick(this); - break; - default: - return; - } - mListener.onDismiss(this); - } - - @Override - public void onProgressChanged(final SeekBar seekBar, final int progress, - final boolean fromUser) { - setValue(progress, fromUser); - if (fromUser) { - mListener.onProgressChanged(this); - } - } - - @Override - public void onStartTrackingTouch(final SeekBar seekBar) { - mListener.onStartTrackingTouch(this); - } - - @Override - public void onStopTrackingTouch(final SeekBar seekBar) { - mListener.onStopTrackingTouch(this); - } - - public static final class Builder { - final AlertDialog.Builder mDialogBuilder; - final View mView; - - int mNeutralButtonTextResId; - int mMaxValue; - int mValueFormatResId; - int mValue; - Listener mListener; - - public Builder(final Context context) { - mDialogBuilder = new AlertDialog.Builder(context); - mView = LayoutInflater.from(context).inflate(R.layout.seek_bar_dialog, null); - } - - public Builder setTitle(final int resId) { - mDialogBuilder.setTitle(resId); - return this; - } - - public Builder setNeutralButtonText(final int resId) { - mNeutralButtonTextResId = resId; - return this; - } - - public Builder setMaxValue(final int max) { - mMaxValue = max; - mValue = Math.min(mValue, max); - return this; - } - - public Builder setValueFromat(final int resId) { - mValueFormatResId = resId; - return this; - } - - public Builder setValue(final int value) { - mValue = Math.min(value, mMaxValue); - return this; - } - - public Builder setListener(final Listener listener) { - mListener = listener; - return this; - } - - public SeekBarDialog create() { - final SeekBarDialog dialog = new SeekBarDialog(this); - dialog.setValue(mValue, false /* fromUser */); - return dialog; - } - } -} diff --git a/java/src/com/android/inputmethod/latin/SeekBarDialogPreference.java b/java/src/com/android/inputmethod/latin/SeekBarDialogPreference.java new file mode 100644 index 000000000..56a6a9b01 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SeekBarDialogPreference.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.TypedArray; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.SeekBar; +import android.widget.TextView; + +public final class SeekBarDialogPreference extends DialogPreference + implements SeekBar.OnSeekBarChangeListener { + public interface ValueProxy { + public int readValue(final String key); + public int readDefaultValue(final String key); + public void writeValue(final int value, final String key); + public void feedbackValue(final int value); + } + + private final int mValueFormatResId; + private final int mMaxValue; + + private TextView mValueView; + private SeekBar mSeekBar; + + private ValueProxy mValueProxy; + + public SeekBarDialogPreference(final Context context, final AttributeSet attrs) { + super(context, attrs); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.SeekBarDialogPreference, 0, 0); + mValueFormatResId = a.getResourceId(R.styleable.SeekBarDialogPreference_valueFormatText, 0); + mMaxValue = a.getInt(R.styleable.SeekBarDialogPreference_maxValue, 0); + a.recycle(); + setDialogLayoutResource(R.layout.seek_bar_dialog); + } + + public void setInterface(final ValueProxy proxy) { + mValueProxy = proxy; + setSummary(getValueText(proxy.readValue(getKey()))); + } + + private String getValueText(final int value) { + if (mValueFormatResId == 0) { + return Integer.toString(value); + } else { + return getContext().getString(mValueFormatResId, value); + } + } + + @Override + protected View onCreateDialogView() { + final View view = super.onCreateDialogView(); + mSeekBar = (SeekBar)view.findViewById(R.id.seek_bar_dialog_bar); + mSeekBar.setMax(mMaxValue); + mSeekBar.setOnSeekBarChangeListener(this); + mValueView = (TextView)view.findViewById(R.id.seek_bar_dialog_value); + return view; + } + + private void setValue(final int value, final boolean fromUser) { + mValueView.setText(getValueText(value)); + if (!fromUser) { + mSeekBar.setProgress(value); + } + } + + @Override + protected void onBindDialogView(final View view) { + setValue(mValueProxy.readValue(getKey()), false /* fromUser */); + } + + @Override + protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) { + builder.setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .setNeutralButton(R.string.button_default, this); + } + + @Override + public void onClick(final DialogInterface dialog, final int which) { + super.onClick(dialog, which); + if (which == DialogInterface.BUTTON_NEUTRAL) { + setValue(mValueProxy.readDefaultValue(getKey()), false /* fromUser */); + } + if (which != DialogInterface.BUTTON_NEGATIVE) { + setSummary(mValueView.getText()); + mValueProxy.writeValue(mSeekBar.getProgress(), getKey()); + } + } + + @Override + public void onProgressChanged(final SeekBar seekBar, final int progress, + final boolean fromUser) { + setValue(progress, fromUser); + } + + @Override + public void onStartTrackingTouch(final SeekBar seekBar) {} + + @Override + public void onStopTrackingTouch(final SeekBar seekBar) { + mValueProxy.feedbackValue(seekBar.getProgress()); + } +} diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java index 6a4371835..3558d817d 100644 --- a/java/src/com/android/inputmethod/latin/SettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -26,7 +26,6 @@ import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; -import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import android.view.inputmethod.InputMethodSubtype; @@ -36,8 +35,6 @@ import com.android.inputmethodcommon.InputMethodSettingsFragment; public final class SettingsFragment extends InputMethodSettingsFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private PreferenceScreen mKeypressVibrationDurationSettingsPref; - private PreferenceScreen mKeypressSoundVolumeSettingsPref; private ListPreference mVoicePreference; private ListPreference mShowCorrectionSuggestionsPreference; private ListPreference mAutoCorrectionThresholdPreference; @@ -167,36 +164,8 @@ public final class SettingsFragment extends InputMethodSettingsFragment getPreferenceScreen().removePreference(gestureTypingSettings); } - mKeypressVibrationDurationSettingsPref = - (PreferenceScreen) findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS); - if (mKeypressVibrationDurationSettingsPref != null) { - mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference arg0) { - showKeypressVibrationDurationSettingsDialog(); - return true; - } - }); - mKeypressVibrationDurationSettingsPref.setSummary( - res.getString(R.string.settings_keypress_vibration_duration, - Settings.readKeypressVibrationDuration(prefs, res))); - } - - mKeypressSoundVolumeSettingsPref = - (PreferenceScreen) findPreference(Settings.PREF_KEYPRESS_SOUND_VOLUME); - if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference arg0) { - showKeypressSoundVolumeSettingDialog(); - return true; - } - }); - mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( - getCurrentKeyPressSoundVolumePercent(prefs, res))); - } + setupKeypressVibrationDurationSettings(prefs, res); + setupKeypressSoundVolumeSettings(prefs, res); refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); } @@ -287,127 +256,86 @@ public final class SettingsFragment extends InputMethodSettingsFragment private void refreshEnablingsOfKeypressSoundAndVibrationSettings( final SharedPreferences sp, final Resources res) { - if (mKeypressVibrationDurationSettingsPref != null) { - final boolean hasVibratorHardware = - AudioAndHapticFeedbackManager.getInstance().hasVibrator(); - final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON, - res.getBoolean(R.bool.config_default_vibration_enabled)); - mKeypressVibrationDurationSettingsPref.setEnabled( - hasVibratorHardware && vibrateOnByUser); - } - - if (mKeypressSoundVolumeSettingsPref != null) { - final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, - res.getBoolean(R.bool.config_default_sound_enabled)); - mKeypressSoundVolumeSettingsPref.setEnabled(soundOn); - } + final boolean hasVibratorHardware = + AudioAndHapticFeedbackManager.getInstance().hasVibrator(); + final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON, + res.getBoolean(R.bool.config_default_vibration_enabled)); + setPreferenceEnabled(Settings.PREF_VIBRATION_DURATION_SETTINGS, + hasVibratorHardware && vibrateOnByUser); + + final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, + res.getBoolean(R.bool.config_default_sound_enabled)); + setPreferenceEnabled(Settings.PREF_KEYPRESS_SOUND_VOLUME, soundOn); } - private void showKeypressVibrationDurationSettingsDialog() { - final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); - final Context context = getActivity(); - final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref; - final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { - private void writePreference(final SharedPreferences sp, final int value) { - sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, value).apply(); - } - - private void feedbackSettingsValue(final int value) { - AudioAndHapticFeedbackManager.getInstance().vibrate(value); - } - + private void setupKeypressVibrationDurationSettings(final SharedPreferences sp, + final Resources res) { + final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( + Settings.PREF_VIBRATION_DURATION_SETTINGS); + if (pref == null) { + return; + } + pref.setInterface(new SeekBarDialogPreference.ValueProxy() { @Override - public void onPositiveButtonClick(final SeekBarDialog dialog) { - writePreference(sp, dialog.getValue()); + public void writeValue(final int value, final String key) { + sp.edit().putInt(key, value).apply(); } @Override - public void onNeutralButtonClick(final SeekBarDialog dialog) { - final int defaultValue = - Settings.readDefaultKeypressVibrationDuration(context.getResources()); - dialog.setValue(defaultValue, false /* fromUser */); - writePreference(sp, defaultValue); + public int readValue(final String key) { + return Settings.readKeypressVibrationDuration(sp, res); } @Override - public void onDismiss(final SeekBarDialog dialog) { - if (settingsPref != null) { - settingsPref.setSummary(dialog.getValueText()); - } + public int readDefaultValue(final String key) { + return Settings.readDefaultKeypressVibrationDuration(res); } @Override - public void onStopTrackingTouch(final SeekBarDialog dialog) { - feedbackSettingsValue(dialog.getValue()); + public void feedbackValue(final int value) { + AudioAndHapticFeedbackManager.getInstance().vibrate(value); } - }; - final int currentMs = Settings.readKeypressVibrationDuration(sp, getResources()); - final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); - builder.setTitle(R.string.prefs_keypress_vibration_duration_settings) - .setNeutralButtonText(R.string.button_default) - .setListener(listener) - .setMaxValue(AudioAndHapticFeedbackManager.MAX_KEYPRESS_VIBRATION_DURATION) - .setValueFromat(R.string.settings_keypress_vibration_duration) - .setValue(currentMs) - .create() - .show(); + }); } - private static final int PERCENT_INT = 100; - private static final float PERCENT_FLOAT = 100.0f; - - private static int getCurrentKeyPressSoundVolumePercent(final SharedPreferences sp, - final Resources res) { - return (int)(Settings.readKeypressSoundVolume(sp, res) * PERCENT_FLOAT); - } + private void setupKeypressSoundVolumeSettings(final SharedPreferences sp, final Resources res) { + final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference( + Settings.PREF_KEYPRESS_SOUND_VOLUME); + if (pref == null) { + return; + } + final AudioManager am = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE); + pref.setInterface(new SeekBarDialogPreference.ValueProxy() { + private static final float PERCENTAGE_FLOAT = 100.0f; - private void showKeypressSoundVolumeSettingDialog() { - final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); - final Context context = getActivity(); - final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - final PreferenceScreen settingsPref = mKeypressSoundVolumeSettingsPref; - final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { - private void writePreference(final SharedPreferences sp, final float value) { - sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, value).apply(); + private float getValueFromPercentage(final int percentage) { + return percentage / PERCENTAGE_FLOAT; } - private void feedbackSettingsValue(final float value) { - am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, value); + private int getPercentageFromValue(final float floatValue) { + return (int)(floatValue * PERCENTAGE_FLOAT); } @Override - public void onPositiveButtonClick(final SeekBarDialog dialog) { - writePreference(sp, dialog.getValue() / PERCENT_FLOAT); + public void writeValue(final int value, final String key) { + sp.edit().putFloat(key, getValueFromPercentage(value)).apply(); } @Override - public void onNeutralButtonClick(final SeekBarDialog dialog) { - final float defaultValue = - Settings.readDefaultKeypressSoundVolume(context.getResources()); - dialog.setValue((int)(defaultValue * PERCENT_INT), false /* fromUser */); - writePreference(sp, defaultValue); + public int readValue(final String key) { + return getPercentageFromValue(Settings.readKeypressSoundVolume(sp, res)); } @Override - public void onDismiss(final SeekBarDialog dialog) { - if (settingsPref != null) { - settingsPref.setSummary(dialog.getValueText()); - } + public int readDefaultValue(final String key) { + return getPercentageFromValue(Settings.readDefaultKeypressSoundVolume(res)); } @Override - public void onStopTrackingTouch(final SeekBarDialog dialog) { - feedbackSettingsValue(dialog.getValue() / PERCENT_FLOAT); + public void feedbackValue(final int value) { + am.playSoundEffect( + AudioManager.FX_KEYPRESS_STANDARD, getValueFromPercentage(value)); } - }; - final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); - final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources()); - builder.setTitle(R.string.prefs_keypress_sound_volume_settings) - .setNeutralButtonText(R.string.button_default) - .setListener(listener) - .setMaxValue(PERCENT_INT) - .setValue(currentVolumeInt) - .create() - .show(); + }); } } diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index ddaa5ff5b..d00edbe92 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -103,6 +103,37 @@ public final class StringUtils { } } + /** + * Apply an auto-caps mode to a string. + * + * This intentionally does NOT apply manual caps mode. It only changes the capitalization if + * the mode is one of the auto-caps modes. + * @param s The string to capitalize. + * @param capitalizeMode The mode in which to capitalize. + * @param locale The locale for capitalizing. + * @return The capitalized string. + */ + public static String applyAutoCapsMode(final String s, final int capitalizeMode, + final Locale locale) { + if (WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == capitalizeMode) { + return s.toUpperCase(locale); + } else if (WordComposer.CAPS_MODE_AUTO_SHIFTED == capitalizeMode) { + return toTitleCase(s, locale); + } else { + return s; + } + } + + /** + * Return whether a constant represents an auto-caps mode (either auto-shift or auto-shift-lock) + * @param mode The mode to test for + * @return true if this represents an auto-caps mode, false otherwise + */ + public static boolean isAutoCapsMode(final int mode) { + return WordComposer.CAPS_MODE_AUTO_SHIFTED == mode + || WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED == mode; + } + public static String toTitleCase(final String s, final Locale locale) { if (s.length() <= 1) { // TODO: is this really correct? Shouldn't this be s.toUpperCase()? diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index a16784985..0d5bde623 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -216,17 +216,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { * * @param word the word to add. If the word is capitalized, then the dictionary will * recognize it as a capitalized word when searched. - * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered - * the highest. - * @TODO use a higher or float range for frequency */ - public synchronized void addWordToUserDictionary(final String word, final int frequency) { + public synchronized void addWordToUserDictionary(final String word) { // TODO: do something for the UI. With the following, any sufficiently long word will // look like it will go to the user dictionary but it won't. // Safeguard against adding long words. Can cause stack overflow. if (word.length() >= MAX_WORD_LENGTH) return; - // TODO: Add an argument to the intent to specify the frequency. Intent intent = new Intent(ACTION_USER_DICTIONARY_INSERT); intent.putExtra(Words.WORD, word); intent.putExtra(Words.LOCALE, mLocale); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index b9ec4979d..01629fefa 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -360,8 +360,10 @@ public final class WordComposer { mDigitsCount = 0; mIsBatchMode = false; mTypedWord.setLength(0); + mCodePointSize = 0; mTrailingSingleQuotesCount = 0; mIsFirstCharCapitalized = false; + mCapitalizedMode = CAPS_MODE_OFF; refreshSize(); mAutoCorrection = null; mIsResumed = false; diff --git a/java/src/com/android/inputmethod/research/LogUnit.java b/java/src/com/android/inputmethod/research/LogUnit.java index cfba28909..70bbf9dc0 100644 --- a/java/src/com/android/inputmethod/research/LogUnit.java +++ b/java/src/com/android/inputmethod/research/LogUnit.java @@ -60,6 +60,7 @@ import java.util.Map; private String mWord; private boolean mMayContainDigit; private boolean mIsPartOfMegaword; + private boolean mContainsCorrection; public LogUnit() { mLogStatementList = new ArrayList<LogStatement>(); @@ -274,6 +275,14 @@ import java.util.Map; return mMayContainDigit; } + public void setContainsCorrection() { + mContainsCorrection = true; + } + + public boolean containsCorrection() { + return mContainsCorrection; + } + public boolean isEmpty() { return mLogStatementList.isEmpty(); } @@ -301,6 +310,7 @@ import java.util.Map; true /* isPartOfMegaword */); newLogUnit.mWord = null; newLogUnit.mMayContainDigit = mMayContainDigit; + newLogUnit.mContainsCorrection = mContainsCorrection; // Purge the logStatements and associated data from this LogUnit. laterLogStatements.clear(); @@ -320,6 +330,7 @@ import java.util.Map; mTimeList.addAll(logUnit.mTimeList); mWord = null; mMayContainDigit = mMayContainDigit || logUnit.mMayContainDigit; + mContainsCorrection = mContainsCorrection || logUnit.mContainsCorrection; mIsPartOfMegaword = false; } } diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java index a2bcf4441..a46216c5e 100644 --- a/java/src/com/android/inputmethod/research/ResearchLogger.java +++ b/java/src/com/android/inputmethod/research/ResearchLogger.java @@ -720,6 +720,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mCurrentLogUnit.setMayContainDigit(); } + private void setCurrentLogUnitContainsCorrection() { + mCurrentLogUnit.setContainsCorrection(); + } + /* package for test */ void commitCurrentLogUnit() { if (DEBUG) { Log.d(TAG, "commitCurrentLogUnit" + (mCurrentLogUnit.hasWord() ? @@ -850,7 +854,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mCurrentLogUnit.setWord(word); final boolean isDictionaryWord = dictionary != null && dictionary.isValidWord(word); - mStatistics.recordWordEntered(isDictionaryWord); + mStatistics.recordWordEntered(isDictionaryWord, mCurrentLogUnit.containsCorrection()); } final LogUnit newLogUnit = mCurrentLogUnit.splitByTime(maxTime); enqueueCommitText(word, isBatchMode); @@ -1181,6 +1185,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang scrubDigitsFromString(replacedWord), index, suggestion == null ? null : scrubbedWord, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); + researchLogger.setCurrentLogUnitContainsCorrection(); researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, Long.MAX_VALUE, isBatchMode); researchLogger.mStatistics.recordManualSuggestion(SystemClock.uptimeMillis()); } @@ -1340,6 +1345,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang researchLogger.enqueueEvent(logUnit != null ? logUnit : researchLogger.mCurrentLogUnit, LOGSTATEMENT_LATINIME_REVERTCOMMIT, committedWord, originallyTypedWord, separatorString); + if (logUnit != null) { + logUnit.setContainsCorrection(); + } researchLogger.mStatistics.recordRevertCommit(SystemClock.uptimeMillis()); researchLogger.commitCurrentLogUnitAsWord(originallyTypedWord, Long.MAX_VALUE, isBatchMode); } @@ -1500,6 +1508,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang final ResearchLogger researchLogger = getInstance(); final String scrubbedWord = scrubDigitsFromString(committedWord); researchLogger.enqueueEvent(LOGSTATEMENT_COMMIT_PARTIAL_TEXT); + researchLogger.mStatistics.recordAutoCorrection(SystemClock.uptimeMillis()); researchLogger.commitCurrentLogUnitAsWord(scrubbedWord, lastTimestampOfWordData, isBatchMode); } @@ -1740,7 +1749,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang "averageTimeDuringRepeatedDelete", "averageTimeAfterDelete", "dictionaryWordCount", "splitWordsCount", "gestureInputCount", "gestureCharsCount", "gesturesDeletedCount", "manualSuggestionsCount", - "revertCommitsCount"); + "revertCommitsCount", "correctedWordsCount", "autoCorrectionsCount"); private static void logStatistics() { final ResearchLogger researchLogger = getInstance(); final Statistics statistics = researchLogger.mStatistics; @@ -1754,6 +1763,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang statistics.mDictionaryWordCount, statistics.mSplitWordsCount, statistics.mGesturesInputCount, statistics.mGesturesCharsCount, statistics.mGesturesDeletedCount, statistics.mManualSuggestionsCount, - statistics.mRevertCommitsCount); + statistics.mRevertCommitsCount, statistics.mCorrectedWordsCount, + statistics.mAutoCorrectionsCount); } } diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java index a9202651e..f0cb1578c 100644 --- a/java/src/com/android/inputmethod/research/Statistics.java +++ b/java/src/com/android/inputmethod/research/Statistics.java @@ -25,6 +25,7 @@ public class Statistics { private static final String TAG = Statistics.class.getSimpleName(); private static final boolean DEBUG = false && ProductionFlag.IS_EXPERIMENTAL_DEBUG; + // TODO: Cleanup comments to only including those giving meaningful information. // Number of characters entered during a typing session int mCharCount; // Number of letter characters entered during a typing session @@ -41,6 +42,8 @@ public class Statistics { int mDictionaryWordCount; // Number of words split and spaces automatically entered. int mSplitWordsCount; + // Number of words entered during a session. + int mCorrectedWordsCount; // Number of gestures that were input. int mGesturesInputCount; // Number of gestures that were deleted. @@ -49,6 +52,8 @@ public class Statistics { int mGesturesCharsCount; // Number of manual suggestions chosen. int mManualSuggestionsCount; + // Number of times that autocorrection was invoked. + int mAutoCorrectionsCount; // Number of times a commit was reverted in this session. int mRevertCommitsCount; // Whether the text field was empty upon editing @@ -113,10 +118,12 @@ public class Statistics { mWordCount = 0; mDictionaryWordCount = 0; mSplitWordsCount = 0; + mCorrectedWordsCount = 0; mGesturesInputCount = 0; mGesturesDeletedCount = 0; mManualSuggestionsCount = 0; mRevertCommitsCount = 0; + mAutoCorrectionsCount = 0; mIsEmptyUponStarting = true; mIsEmptinessStateKnown = false; mKeyCounter.reset(); @@ -152,11 +159,15 @@ public class Statistics { } } - public void recordWordEntered(final boolean isDictionaryWord) { + public void recordWordEntered(final boolean isDictionaryWord, + final boolean containsCorrection) { mWordCount++; if (isDictionaryWord) { mDictionaryWordCount++; } + if (containsCorrection) { + mCorrectedWordsCount++; + } } public void recordSplitWords() { @@ -184,6 +195,11 @@ public class Statistics { recordUserAction(time, false /* isDeletion */); } + public void recordAutoCorrection(final long time) { + mAutoCorrectionsCount++; + recordUserAction(time, false /* isDeletion */); + } + public void recordRevertCommit(final long time) { mRevertCommitsCount++; recordUserAction(time, true /* isDeletion */); |