diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
26 files changed, 943 insertions, 781 deletions
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java index 509fc1ba3..820733bdc 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java @@ -45,7 +45,7 @@ public final class AdditionalSubtype { final String keyboardLayoutSetName, final String extraValue) { final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; final String layoutDisplayNameExtraValue; - if (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && SubtypeLocale.isExceptionalLocale(localeString)) { final String layoutDisplayName = SubtypeLocale.getKeyboardLayoutSetDisplayName( keyboardLayoutSetName); diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index 08f08d24e..6ac5a9b94 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -387,7 +387,7 @@ public final class AdditionalSubtypeSettings extends PreferenceFragment { super.onCreate(savedInstanceState); mPrefs = getPreferenceManager().getSharedPreferences(); - RichInputMethodManager.init(getActivity(), mPrefs); + RichInputMethodManager.init(getActivity()); mRichImm = RichInputMethodManager.getInstance(); addPreferencesFromResource(R.xml.additional_subtype_settings); setHasOptionsMenu(true); diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 024726391..6367156ef 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -18,11 +18,10 @@ package com.android.inputmethod.latin; import android.content.Context; import android.media.AudioManager; +import android.os.Vibrator; import android.view.HapticFeedbackConstants; import android.view.View; -import com.android.inputmethod.latin.VibratorUtils; - /** * This class gathers audio feedback and haptic feedback functions. * @@ -30,34 +29,63 @@ import com.android.inputmethod.latin.VibratorUtils; * complexity of settings and the like. */ public final class AudioAndHapticFeedbackManager { - private final AudioManager mAudioManager; - private final VibratorUtils mVibratorUtils; + public static final int MAX_KEYPRESS_VIBRATION_DURATION = 250; // millisecond + + private AudioManager mAudioManager; + private Vibrator mVibrator; private SettingsValues mSettingsValues; private boolean mSoundOn; - public AudioAndHapticFeedbackManager(final LatinIME latinIme) { - mVibratorUtils = VibratorUtils.getInstance(latinIme); - mAudioManager = (AudioManager) latinIme.getSystemService(Context.AUDIO_SERVICE); + private static final AudioAndHapticFeedbackManager sInstance = + new AudioAndHapticFeedbackManager(); + + public static AudioAndHapticFeedbackManager getInstance() { + return sInstance; + } + + private AudioAndHapticFeedbackManager() { + // Intentional empty constructor for singleton. + } + + public static void init(final Context context) { + sInstance.initInternal(context); + } + + private void initInternal(final Context context) { + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } public void hapticAndAudioFeedback(final int primaryCode, final View viewToPerformHapticFeedbackOn) { - vibrate(viewToPerformHapticFeedbackOn); + vibrateInternal(viewToPerformHapticFeedbackOn); playKeyClick(primaryCode); } + public boolean hasVibrator() { + return mVibrator != null && mVibrator.hasVibrator(); + } + + public void vibrate(final long milliseconds) { + if (mVibrator == null) { + return; + } + mVibrator.vibrate(milliseconds); + } + private boolean reevaluateIfSoundIsOn() { if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) { return false; - } else { - return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL; } + return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL; } - private void playKeyClick(int primaryCode) { + private void playKeyClick(final int primaryCode) { // if mAudioManager is null, we can't play a sound anyway, so return - if (mAudioManager == null) return; + if (mAudioManager == null) { + return; + } if (mSoundOn) { final int sound; switch (primaryCode) { @@ -78,7 +106,7 @@ public final class AudioAndHapticFeedbackManager { } } - private void vibrate(final View viewToPerformHapticFeedbackOn) { + private void vibrateInternal(final View viewToPerformHapticFeedbackOn) { if (!mSettingsValues.mVibrateOn) { return; } @@ -89,9 +117,9 @@ public final class AudioAndHapticFeedbackManager { HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } - } else if (mVibratorUtils != null) { - mVibratorUtils.vibrate(mSettingsValues.mKeypressVibrationDuration); + return; } + vibrate(mSettingsValues.mKeypressVibrationDuration); } public void onSettingsChanged(final SettingsValues settingsValues) { diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java index 16ec5b5db..3a7772452 100644 --- a/java/src/com/android/inputmethod/latin/Constants.java +++ b/java/src/com/android/inputmethod/latin/Constants.java @@ -111,7 +111,7 @@ public final class Constants { } } - public static class TextUtils { + public static final class TextUtils { /** * Capitalization mode for {@link android.text.TextUtils#getCapsMode}: don't capitalize * characters. This value may be used with @@ -126,7 +126,7 @@ public final class Constants { } } - public static class Dictionary { + public static final class Dictionary { public static final int MAX_WORD_LENGTH = 48; private Dictionary() { @@ -139,6 +139,7 @@ public final class Constants { public static final int NOT_A_COORDINATE = -1; public static final int SUGGESTION_STRIP_COORDINATE = -2; public static final int SPELL_CHECKER_COORDINATE = -3; + public static final int EXTERNAL_KEYBOARD_COORDINATE = -4; public static boolean isValidCoordinate(final int coordinate) { // Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE}, diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 7f78ac8a2..9a771cf1e 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -38,7 +38,7 @@ public final class DictionaryCollection extends Dictionary { mDictionaries = CollectionUtils.newCopyOnWriteArrayList(); } - public DictionaryCollection(final String dictType, Dictionary... dictionaries) { + public DictionaryCollection(final String dictType, final Dictionary... dictionaries) { super(dictType); if (null == dictionaries) { mDictionaries = CollectionUtils.newCopyOnWriteArrayList(); @@ -48,7 +48,7 @@ public final class DictionaryCollection extends Dictionary { } } - public DictionaryCollection(final String dictType, Collection<Dictionary> dictionaries) { + public DictionaryCollection(final String dictType, final Collection<Dictionary> dictionaries) { super(dictType); mDictionaries = CollectionUtils.newCopyOnWriteArrayList(dictionaries); mDictionaries.removeAll(Collections.singleton(null)); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index dcc131fc5..28994dc8e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -35,6 +35,7 @@ import android.graphics.Rect; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; +import android.os.Build.VERSION_CODES; import android.os.Debug; import android.os.Handler; import android.os.HandlerThread; @@ -72,7 +73,6 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.MainKeyboardView; -import com.android.inputmethod.latin.LocaleUtils.RunInLocale; import com.android.inputmethod.latin.Utils.Stats; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethod.latin.suggestions.SuggestionStripView; @@ -127,7 +127,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Current space state of the input method. This can be any of the above constants. private int mSpaceState; - private SettingsValues mCurrentSettings; + private final Settings mSettings; private View mExtractArea; private View mKeyPreviewBackingView; @@ -138,14 +138,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private ApplicationInfo mTargetApplicationInfo; private RichInputMethodManager mRichImm; - private Resources mResources; - private SharedPreferences mPrefs; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); // At start, create a default event interpreter that does nothing by passing it no decoder spec. // The event interpreter should never be null. - private EventInterpreter mEventInterpreter = new EventInterpreter(); + private EventInterpreter mEventInterpreter = new EventInterpreter(this); private boolean mIsMainDictionaryAvailable; private UserBinaryDictionary mUserDictionary; @@ -400,6 +398,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public LatinIME() { super(); + mSettings = Settings.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); mIsHardwareAcceleratedDrawingEnabled = @@ -409,17 +408,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public void onCreate() { - mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - mResources = getResources(); - - LatinImeLogger.init(this, mPrefs); + Settings.init(this); + LatinImeLogger.init(this); if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.getInstance().init(this, mPrefs); + ResearchLogger.getInstance().init(this); } - RichInputMethodManager.init(this, mPrefs); + RichInputMethodManager.init(this); mRichImm = RichInputMethodManager.getInstance(); SubtypeSwitcher.init(this); - KeyboardSwitcher.init(this, mPrefs); + KeyboardSwitcher.init(this); + AudioAndHapticFeedbackManager.init(this); AccessibilityUtils.init(this); super.onCreate(); @@ -430,7 +428,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction loadSettings(); initSuggest(); - mDisplayOrientation = mResources.getConfiguration().orientation; + mDisplayOrientation = getResources().getConfiguration().orientation; // Register to receive ringer mode change and network state change. // Also receive installation and removal of a dictionary pack. @@ -457,18 +455,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // Has to be package-visible for unit tests @UsedForTesting void loadSettings() { - // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() - // is not guaranteed. It may even be called at the same time on a different thread. - if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); + final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); final InputAttributes inputAttributes = new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode()); - final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { - @Override - protected SettingsValues job(Resources res) { - return new SettingsValues(mPrefs, inputAttributes, LatinIME.this); - } - }; - mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale()); + mSettings.loadSettings(locale, inputAttributes); resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); } @@ -495,8 +485,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mSuggest = new Suggest(this /* Context */, subtypeLocale, this /* SuggestInitializationListener */); - if (mCurrentSettings.mCorrectionEnabled) { - mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); + if (mSettings.getCurrent().mCorrectionEnabled) { + mSuggest.setAutoCorrectionThreshold(mSettings.getCurrent().mAutoCorrectionThreshold); } mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); @@ -510,10 +500,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction resetContactsDictionary(oldContactsDictionary); - // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() - // is not guaranteed. It may even be called at the same time on a different thread. - if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); - mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, mPrefs); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, prefs); mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); } @@ -526,7 +514,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction * @param oldContactsDictionary an optional dictionary to use, or null */ private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { - final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict); + final boolean shouldSetDictionary = + (null != mSuggest && mSettings.getCurrent().mUseContactsDict); final ContactsBinaryDictionary dictionaryToUse; if (!shouldSetDictionary) { @@ -570,6 +559,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mSuggest.close(); mSuggest = null; } + mSettings.onDestroy(); unregisterReceiver(mReceiver); // TODO: The experimental version is not supported by the Dictionary Pack Service yet. if (!ProductionFlag.IS_EXPERIMENTAL) { @@ -582,10 +572,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public void onConfigurationChanged(final Configuration conf) { - // System locale has been changed. Needs to reload keyboard. - if (mSubtypeSwitcher.onConfigurationChanged(conf)) { - loadKeyboard(); - } // If orientation changed while predicting, commit the change if (mDisplayOrientation != conf.orientation) { mDisplayOrientation = conf.orientation; @@ -651,7 +637,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) { // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() // is not guaranteed. It may even be called at the same time on a different thread. - mSubtypeSwitcher.updateSubtype(subtype); + mSubtypeSwitcher.onSubtypeChanged(subtype); loadKeyboard(); } @@ -684,7 +670,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); } if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs); } if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " @@ -716,18 +703,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting); } - final boolean inputTypeChanged = !mCurrentSettings.isSameInputType(editorInfo); + final boolean inputTypeChanged = !mSettings.getCurrent().isSameInputType(editorInfo); final boolean isDifferentTextField = !restarting || inputTypeChanged; if (isDifferentTextField) { - final boolean currentSubtypeEnabled = mSubtypeSwitcher - .updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled(); - if (!currentSubtypeEnabled) { - // Current subtype is disabled. Needs to update subtype and keyboard. - final InputMethodSubtype newSubtype = mRichImm.getCurrentInputMethodSubtype( - mSubtypeSwitcher.getNoLanguageSubtype()); - mSubtypeSwitcher.updateSubtype(newSubtype); - loadKeyboard(); - } + mSubtypeSwitcher.updateParametersOnStartInputView(); } // The EditorInfo might have a flag that affects fullscreen mode. @@ -754,11 +733,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mainKeyboardView.closing(); loadSettings(); - if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) { - mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); + if (mSuggest != null && mSettings.getCurrent().mCorrectionEnabled) { + mSuggest.setAutoCorrectionThreshold( + mSettings.getCurrent().mAutoCorrectionThreshold); } - switcher.loadKeyboard(editorInfo, mCurrentSettings); + switcher.loadKeyboard(editorInfo, mSettings.getCurrent()); } else if (restarting) { // TODO: Come up with a more comprehensive way to reset the keyboard layout when // a keyboard layout set doesn't get reloaded in this method. @@ -779,11 +759,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mHandler.cancelDoubleSpacePeriodTimer(); mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable); - mainKeyboardView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn, - mCurrentSettings.mKeyPreviewPopupDismissDelay); - mainKeyboardView.setGestureHandlingEnabledByUser(mCurrentSettings.mGestureInputEnabled); - mainKeyboardView.setGesturePreviewMode(mCurrentSettings.mGesturePreviewTrailEnabled, - mCurrentSettings.mGestureFloatingPreviewTextEnabled); + mainKeyboardView.setKeyPreviewPopupEnabled(mSettings.getCurrent().mKeyPreviewPopupOn, + mSettings.getCurrent().mKeyPreviewPopupDismissDelay); + mainKeyboardView.setGestureHandlingEnabledByUser( + mSettings.getCurrent().mGestureInputEnabled); + mainKeyboardView.setGesturePreviewMode(mSettings.getCurrent().mGesturePreviewTrailEnabled, + mSettings.getCurrent().mGestureFloatingPreviewTextEnabled); // If we have a user dictionary addition in progress, we should check now if we should // replace the previously committed string with the word that has actually been added @@ -941,7 +922,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction */ @Override public void onExtractedTextClicked() { - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; super.onExtractedTextClicked(); } @@ -957,7 +938,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction */ @Override public void onExtractedCursorMovement(final int dx, final int dy) { - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; super.onExtractedCursorMovement(dx, dy); } @@ -985,7 +966,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } } - if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return; + if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return; mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; if (applicationSpecifiedCompletions == null) { clearSuggestionStrip(); @@ -1009,9 +990,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final boolean isAutoCorrection = false; setSuggestionStrip(suggestedWords, isAutoCorrection); setAutoCorrectionIndicator(isAutoCorrection); - // TODO: is this the right thing to do? What should we auto-correct to in - // this case? This says to keep whatever the user typed. - mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); setSuggestionStripShown(true); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); @@ -1053,7 +1031,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } final int keyboardHeight = mainKeyboardView.getHeight(); final int suggestionsHeight = mSuggestionsContainer.getHeight(); - final int displayHeight = mResources.getDisplayMetrics().heightPixels; + final int displayHeight = getResources().getDisplayMetrics().heightPixels; final Rect rect = new Rect(); mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); final int notificationBarHeight = rect.top; @@ -1132,10 +1110,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // the composing word, reset the last composed word, tell the inputconnection about it. private void resetEntireInputState(final int newCursorPosition) { resetComposingState(true /* alsoResetLastComposedWord */); - if (mCurrentSettings.mBigramPredictionEnabled) { + if (mSettings.getCurrent().mBigramPredictionEnabled) { clearSuggestionStrip(); } else { - setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); + setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false); } mConnection.resetCachesUponCursorMove(newCursorPosition); } @@ -1152,13 +1130,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (typedWord.length() > 0) { commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, separatorString); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(typedWord, Long.MAX_VALUE); + } } } // Called from the KeyboardSwitcher which needs to know auto caps state to display // the right layout. public int getCurrentAutoCapsState() { - if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; + if (!mSettings.getCurrent().mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; final EditorInfo ei = getCurrentInputEditorInfo(); if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; @@ -1187,8 +1168,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (lastTwo != null && lastTwo.length() == 2 && lastTwo.charAt(0) == Constants.CODE_SPACE) { mConnection.deleteSurroundingText(2, 0); - mConnection.commitText(lastTwo.charAt(1) + " ", 1); + final String text = lastTwo.charAt(1) + " "; + mConnection.commitText(text, 1); if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE); ResearchLogger.latinIME_swapSwapperAndSpace(); } mKeyboardSwitcher.updateShiftState(); @@ -1196,8 +1179,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } private boolean maybeDoubleSpacePeriod() { - if (!mCurrentSettings.mCorrectionEnabled) return false; - if (!mCurrentSettings.mUseDoubleSpacePeriod) return false; + if (!mSettings.getCurrent().mCorrectionEnabled) return false; + if (!mSettings.getCurrent().mUseDoubleSpacePeriod) return false; if (!mHandler.isAcceptingDoubleSpacePeriod()) return false; final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 @@ -1206,7 +1189,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction && lastThree.charAt(2) == Constants.CODE_SPACE) { mHandler.cancelDoubleSpacePeriodTimer(); mConnection.deleteSurroundingText(2, 0); - mConnection.commitText(". ", 1); + final String textToInsert = ". "; + mConnection.commitText(textToInsert, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(textToInsert, Long.MAX_VALUE); + } mKeyboardSwitcher.updateShiftState(); return true; } @@ -1296,7 +1283,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // TODO: Revise the language switch key behavior to make it much smarter and more reasonable. private void handleLanguageSwitchKey() { final IBinder token = getWindow().getWindow().getAttributes().token; - if (mCurrentSettings.mIncludesOtherImesInLanguageSwitchList) { + if (mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList) { mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */); return; } @@ -1324,10 +1311,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction return; } - // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because - // we want to be able to compile against the Ice Cream Sandwich SDK. if (Constants.CODE_ENTER == code && mTargetApplicationInfo != null - && mTargetApplicationInfo.targetSdkVersion < 16) { + && mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { // Backward compatibility mode. Before Jelly bean, the keyboard would simulate // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are @@ -1400,7 +1385,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction break; default: mSpaceState = SPACE_STATE_NONE; - if (mCurrentSettings.isWordSeparator(primaryCode)) { + if (mSettings.getCurrent().isWordSeparator(primaryCode)) { didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { if (SPACE_STATE_PHANTOM == spaceState) { @@ -1445,7 +1430,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction public void onTextInput(final String rawText) { mConnection.beginBatchEdit(); if (mWordComposer.isComposingWord()) { - commitCurrentAutoCorrection(rawText.toString()); + commitCurrentAutoCorrection(rawText); } else { resetComposingState(true /* alsoResetLastComposedWord */); } @@ -1455,6 +1440,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction promotePhantomSpace(); } mConnection.commitText(text, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE); + } mConnection.endBatchEdit(); // Space state must be updated before calling updateShiftState mSpaceState = SPACE_STATE_NONE; @@ -1495,8 +1483,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // should usually be followed by a space, and it should be more readable. if (Constants.NOT_A_CODE != codePointBeforeCursor && !Character.isWhitespace(codePointBeforeCursor) - && !mCurrentSettings.isPhantomSpacePromotingSymbol(codePointBeforeCursor) - && !mCurrentSettings.isWeakSpaceStripper(codePointBeforeCursor)) { + && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(codePointBeforeCursor) + && !mSettings.getCurrent().isWeakSpaceStripper(codePointBeforeCursor)) { mSpaceState = SPACE_STATE_PHANTOM; } } @@ -1603,9 +1591,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (dismissGestureFloatingPreviewText) { mainKeyboardView.dismissGestureFloatingPreviewText(); } else { - final String batchInputText = suggestedWords.isEmpty() - ? null : suggestedWords.getWord(0); - mainKeyboardView.showGestureFloatingPreviewText(batchInputText); + mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); } } @@ -1739,10 +1725,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // This should never happen. Log.e(TAG, "Backspace when we don't know the selection position"); } - // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because - // we want to be able to compile against the Ice Cream Sandwich SDK. if (mTargetApplicationInfo != null - && mTargetApplicationInfo.targetSdkVersion < 16) { + && mTargetApplicationInfo.targetSdkVersion < VERSION_CODES.JELLY_BEAN) { // Backward compatibility mode. Before Jelly bean, the keyboard would simulate // a hardware keyboard event on pressing enter or delete. This is bad for many // reasons (there are race conditions with commits) but some applications are @@ -1755,7 +1739,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mConnection.deleteSurroundingText(1, 0); } } - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); } } @@ -1769,10 +1753,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } else if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState) && isFromSuggestionStrip) { - if (mCurrentSettings.isWeakSpaceSwapper(code)) { + if (mSettings.getCurrent().isWeakSpaceSwapper(code)) { return true; } else { - if (mCurrentSettings.isWeakSpaceStripper(code)) { + if (mSettings.getCurrent().isWeakSpaceStripper(code)) { mConnection.removeTrailingSpace(); } return false; @@ -1787,7 +1771,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction boolean isComposingWord = mWordComposer.isComposingWord(); if (SPACE_STATE_PHANTOM == spaceState && - !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) { + !mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) { if (isComposingWord) { // Sanity check throw new RuntimeException("Should not be composing here"); @@ -1799,9 +1783,9 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI // thread here. if (!isComposingWord && (isAlphabet(primaryCode) - || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) - && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) && - !mConnection.isCursorTouchingWord(mCurrentSettings)) { + || mSettings.getCurrent().isSymbolExcludedFromWordSeparators(primaryCode)) + && mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) && + !mConnection.isCursorTouchingWord(mSettings.getCurrent())) { // Reset entirely the composing state anyway, then start composing a new word unless // the character is a single quote. The idea here is, single quote is not a // separator and it should be treated as a normal character, except in the first @@ -1855,7 +1839,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction boolean didAutoCorrect = false; // Handle separator if (mWordComposer.isComposingWord()) { - if (mCurrentSettings.mCorrectionEnabled) { + if (mSettings.getCurrent().mCorrectionEnabled) { // TODO: maybe cache Strings in an <String> sparse array or something commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1)); didAutoCorrect = true; @@ -1868,13 +1852,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Constants.SUGGESTION_STRIP_COORDINATE == x); if (SPACE_STATE_PHANTOM == spaceState && - mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { + mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) { promotePhantomSpace(); } sendKeyCodePoint(primaryCode); if (Constants.CODE_SPACE == primaryCode) { - if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { + if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { if (maybeDoubleSpacePeriod()) { mSpaceState = SPACE_STATE_DOUBLE; } else if (!isShowingPunctuationList()) { @@ -1883,7 +1867,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mHandler.startDoubleSpacePeriodTimer(); - if (!mConnection.isCursorTouchingWord(mCurrentSettings)) { + if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) { mHandler.postUpdateSuggestionStrip(); } } else { @@ -1891,8 +1875,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction swapSwapperAndSpace(); mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; } else if (SPACE_STATE_PHANTOM == spaceState - && !mCurrentSettings.isWeakSpaceStripper(primaryCode) - && !mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { + && !mSettings.getCurrent().isWeakSpaceStripper(primaryCode) + && !mSettings.getCurrent().isPhantomSpacePromotingSymbol(primaryCode)) { // If we are in phantom space state, and the user presses a separator, we want to // stay in phantom space state so that the next keypress has a chance to add the // space. For example, if I type "Good dat", pick "day" from the suggestion strip @@ -1925,6 +1909,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } private void handleClose() { + // TODO: Verify that words are logged properly when IME is closed. commitTyped(LastComposedWord.NOT_A_SEPARATOR); requestHideSelf(0); final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); @@ -1938,7 +1923,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @UsedForTesting boolean isShowingPunctuationList() { if (mSuggestionStripView == null) return false; - return mCurrentSettings.mSuggestPuncList == mSuggestionStripView.getSuggestions(); + return mSettings.getCurrent().mSuggestPuncList == mSuggestionStripView.getSuggestions(); } private boolean isSuggestionsStripVisible() { @@ -1946,11 +1931,11 @@ public final class LatinIME extends InputMethodService implements KeyboardAction return false; if (mSuggestionStripView.isShowingAddToDictionaryHint()) return true; - if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation)) + if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation)) return false; - if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()) + if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return true; - return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation); + return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation); } private void clearSuggestionStrip() { @@ -1984,16 +1969,16 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mHandler.cancelUpdateSuggestionStrip(); // Check if we have a suggestion engine attached. - if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { + if (mSuggest == null + || !mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { if (mWordComposer.isComposingWord()) { Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " + "requested!"); - mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); } return; } - if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) { + if (!mWordComposer.isComposingWord() && !mSettings.getCurrent().mBigramPredictionEnabled) { setPunctuationSuggestions(); return; } @@ -2014,10 +1999,10 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // should just skip whitespace if any, so 1. // TODO: this is slow (2-way IPC) - we should probably cache this instead. final String prevWord = - mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, + mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, mWordComposer.isComposingWord() ? 2 : 1); final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, - prevWord, keyboard.getProximityInfo(), mCurrentSettings.mCorrectionEnabled, + prevWord, keyboard.getProximityInfo(), mSettings.getCurrent().mCorrectionEnabled, sessionId); return maybeRetrieveOlderSuggestions(typedWord, suggestedWords); } @@ -2042,7 +2027,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction private SuggestedWords getOlderSuggestions(final String typedWord) { SuggestedWords previousSuggestions = mSuggestionStripView.getSuggestions(); - if (previousSuggestions == mCurrentSettings.mSuggestPuncList) { + if (previousSuggestions == mSettings.getCurrent().mSuggestPuncList) { previousSuggestions = SuggestedWords.EMPTY; } if (typedWord == null) { @@ -2091,8 +2076,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction + "is empty? Impossible! I must commit suicide."); } if (ProductionFlag.IS_INTERNAL) { - Stats.onAutoCorrection( - typedWord, autoCorrection.toString(), separatorString, mWordComposer); + Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer); } if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, @@ -2124,7 +2108,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction if (suggestion.length() == 1 && isShowingPunctuationList()) { // Word separators are suggested before the user inputs something. // So, LatinImeLogger logs "" as a user's input. - LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); + LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords); // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. final int primaryCode = suggestion.charAt(0); onCodeInput(primaryCode, @@ -2141,13 +2125,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // the current batch input text and there is no need for a phantom space. && !mWordComposer.isBatchMode()) { int firstChar = Character.codePointAt(suggestion, 0); - if ((!mCurrentSettings.isWeakSpaceStripper(firstChar)) - && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) { + if ((!mSettings.getCurrent().isWeakSpaceStripper(firstChar)) + && (!mSettings.getCurrent().isWeakSpaceSwapper(firstChar))) { promotePhantomSpace(); } } - if (mCurrentSettings.isApplicationSpecifiedCompletionsOn() + if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn() && mApplicationSpecifiedCompletions != null && index >= 0 && index < mApplicationSpecifiedCompletions.length) { if (mSuggestionStripView != null) { @@ -2163,9 +2147,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // We need to log before we commit, because the word composer will store away the user // typed word. - final String replacedWord = mWordComposer.getTypedWord().toString(); - LatinImeLogger.logOnManualSuggestion(replacedWord, - suggestion.toString(), index, suggestedWords); + final String replacedWord = mWordComposer.getTypedWord(); + LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords); mExpectingUpdateSelection = true; commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); @@ -2193,7 +2176,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { mSuggestionStripView.showAddToDictionaryHint( - suggestion, mCurrentSettings.mHintToSaveText); + suggestion, mSettings.getCurrent().mHintToSaveText); } else { // If we're not showing the "Touch again to save", then update the suggestion strip. mHandler.postUpdateSuggestionStrip(); @@ -2214,15 +2197,15 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // what user typed. Note: currently this is done much later in // LastComposedWord#didCommitTypedWord by string equality of the remembered // strings. - mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), - separatorString, prevWord); + mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord, separatorString, + prevWord); } private void setPunctuationSuggestions() { - if (mCurrentSettings.mBigramPredictionEnabled) { + if (mSettings.getCurrent().mBigramPredictionEnabled) { clearSuggestionStrip(); } else { - setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); + setSuggestionStrip(mSettings.getCurrent().mSuggestPuncList, false); } setAutoCorrectionIndicator(false); setSuggestionStripShown(isSuggestionsStripVisible()); @@ -2235,12 +2218,12 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // If correction is not enabled, we don't add words to the user history dictionary. // That's to avoid unintended additions in some sensitive fields, or fields that // expect to receive non-words. - if (!mCurrentSettings.mCorrectionEnabled) return null; + if (!mSettings.getCurrent().mCorrectionEnabled) return null; final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; if (userHistoryDictionary != null) { - final CharSequence prevWord - = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2); + final String prevWord + = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2); final String secondWord; if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); @@ -2252,9 +2235,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final int maxFreq = AutoCorrection.getMaxFrequency( mSuggest.getUnigramDictionaries(), suggestion); if (maxFreq == 0) return null; - final String prevWordString = (null == prevWord) ? null : prevWord.toString(); - userHistoryDictionary.addToUserHistory(prevWordString, secondWord, maxFreq > 0); - return prevWordString; + userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0); + return prevWord; } return null; } @@ -2264,7 +2246,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction * word, else do nothing. */ private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() { - final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings); + final CharSequence word = + mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent()); if (null != word) { restartSuggestionsOnWordBeforeCursor(word); } @@ -2302,8 +2285,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } mConnection.deleteSurroundingText(deleteLength, 0); if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { - mUserHistoryDictionary.cancelAddingUserHistory( - previousWord.toString(), committedWord.toString()); + mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord); } mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1); if (ProductionFlag.IS_INTERNAL) { @@ -2311,7 +2293,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); } if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.latinIME_revertCommit(originallyTypedWord); + ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord); + ResearchLogger.getInstance().onWordComplete(originallyTypedWord, Long.MAX_VALUE); } // Don't restart suggestion yet. We'll restart if the user deletes the // separator. @@ -2322,14 +2305,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction // This essentially inserts a space, and that's it. public void promotePhantomSpace() { - if (mCurrentSettings.shouldInsertSpacesAutomatically()) { + if (mSettings.getCurrent().shouldInsertSpacesAutomatically()) { sendKeyCodePoint(Constants.CODE_SPACE); } } // Used by the RingCharBuffer public boolean isWordSeparator(final int code) { - return mCurrentSettings.isWordSeparator(code); + return mSettings.getCurrent().isWordSeparator(code); } // TODO: Make this private @@ -2342,7 +2325,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction loadSettings(); if (mKeyboardSwitcher.getMainKeyboardView() != null) { // Reload keyboard because the current language has been changed. - mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings); + mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent()); } // Since we just changed languages, we should re-evaluate suggestions with whatever word // we are currently composing. If we are not composing anything, we may want to display @@ -2399,7 +2382,6 @@ public final class LatinIME extends InputMethodService implements KeyboardAction @Override public boolean onKeyUp(final int keyCode, final KeyEvent event) { - if (mEventInterpreter.onHardwareKeyEvent(event)) return true; return super.onKeyUp(keyCode, event); } @@ -2504,7 +2486,7 @@ public final class LatinIME extends InputMethodService implements KeyboardAction .append("\nPackage : ").append(mTargetApplicationInfo.packageName) .append("\nTarget app sdk version : ") .append(mTargetApplicationInfo.targetSdkVersion) - .append("\nAttributes : ").append(mCurrentSettings.getInputAttributesDebugString()) + .append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes) .append("\nContext : ").append(context); throw new RuntimeException(s.toString()); } @@ -2518,13 +2500,14 @@ public final class LatinIME extends InputMethodService implements KeyboardAction final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; p.println(" Keyboard mode = " + keyboardMode); + final SettingsValues settingsValues = mSettings.getCurrent(); p.println(" mIsSuggestionsSuggestionsRequested = " - + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)); - p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled); + + settingsValues.isSuggestionsRequested(mDisplayOrientation)); + p.println(" mCorrectionEnabled=" + settingsValues.mCorrectionEnabled); p.println(" isComposingWord=" + mWordComposer.isComposingWord()); - p.println(" mSoundOn=" + mCurrentSettings.mSoundOn); - p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn); - p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn); - p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString()); + p.println(" mSoundOn=" + settingsValues.mSoundOn); + p.println(" mVibrateOn=" + settingsValues.mVibrateOn); + p.println(" mKeyPreviewPopupOn=" + settingsValues.mKeyPreviewPopupOn); + p.println(" inputAttributes=" + settingsValues.mInputAttributes); } } diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 394a9c7aa..e4e8b94b2 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -31,7 +31,7 @@ public final class LatinImeLogger implements SharedPreferences.OnSharedPreferenc public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } - public static void init(LatinIME context, SharedPreferences prefs) { + public static void init(LatinIME context) { } public static void commit() { diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java index 8a2d22256..1fd25636c 100644 --- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java +++ b/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java @@ -29,7 +29,7 @@ import android.view.inputmethod.EditorInfo; * the IME needs to take a note of what it has to replace and where it is. * This class encapsulates this data. */ -public class PositionalInfoForUserDictPendingAddition { +public final class PositionalInfoForUserDictPendingAddition { final private String mOriginalWord; final private int mCursorPos; // Position of the cursor after the word final private EditorInfo mEditorInfo; // On what binding this has been added diff --git a/java/src/com/android/inputmethod/latin/ResourceUtils.java b/java/src/com/android/inputmethod/latin/ResourceUtils.java index 5021ad384..b74b979b5 100644 --- a/java/src/com/android/inputmethod/latin/ResourceUtils.java +++ b/java/src/com/android/inputmethod/latin/ResourceUtils.java @@ -19,11 +19,15 @@ package com.android.inputmethod.latin; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Build; +import android.util.Log; import android.util.TypedValue; import java.util.HashMap; public final class ResourceUtils { + private static final String TAG = ResourceUtils.class.getSimpleName(); + private static final boolean DEBUG = false; + public static final float UNDEFINED_RATIO = -1.0f; public static final int UNDEFINED_DIMENSION = -1; @@ -31,24 +35,44 @@ public final class ResourceUtils { // This utility class is not publicly instantiable. } + private static final String DEFAULT_PREFIX = "DEFAULT,"; private static final String HARDWARE_PREFIX = Build.HARDWARE + ","; private static final HashMap<String, String> sDeviceOverrideValueMap = CollectionUtils.newHashMap(); - public static String getDeviceOverrideValue(Resources res, int overrideResId, String defValue) { + public static String getDeviceOverrideValue(final Resources res, final int overrideResId) { final int orientation = res.getConfiguration().orientation; final String key = overrideResId + "-" + orientation; - if (!sDeviceOverrideValueMap.containsKey(key)) { - String overrideValue = defValue; - for (final String element : res.getStringArray(overrideResId)) { - if (element.startsWith(HARDWARE_PREFIX)) { - overrideValue = element.substring(HARDWARE_PREFIX.length()); - break; - } + if (sDeviceOverrideValueMap.containsKey(key)) { + return sDeviceOverrideValueMap.get(key); + } + + final String[] overrideArray = res.getStringArray(overrideResId); + final String overrideValue = StringUtils.findPrefixedString(HARDWARE_PREFIX, overrideArray); + // The overrideValue might be an empty string. + if (overrideValue != null) { + if (DEBUG) { + Log.d(TAG, "Find override value:" + + " resource="+ res.getResourceEntryName(overrideResId) + + " Build.HARDWARE=" + Build.HARDWARE + " override=" + overrideValue); } sDeviceOverrideValueMap.put(key, overrideValue); + return overrideValue; + } + + final String defaultValue = StringUtils.findPrefixedString(DEFAULT_PREFIX, overrideArray); + // The defaultValue might be an empty string. + if (defaultValue == null) { + Log.w(TAG, "Couldn't find override value nor default value:" + + " resource="+ res.getResourceEntryName(overrideResId) + + " Build.HARDWARE=" + Build.HARDWARE); + } else if (DEBUG) { + Log.d(TAG, "Found default value:" + + " resource="+ res.getResourceEntryName(overrideResId) + + " Build.HARDWARE=" + Build.HARDWARE + " default=" + defaultValue); } - return sDeviceOverrideValueMap.get(key); + sDeviceOverrideValueMap.put(key, defaultValue); + return defaultValue; } public static boolean isValidFraction(final float fraction) { @@ -85,8 +109,8 @@ public final class ResourceUtils { return a.getDimensionPixelSize(index, ResourceUtils.UNDEFINED_DIMENSION); } - public static float getDimensionOrFraction(TypedArray a, int index, int base, - float defValue) { + public static float getDimensionOrFraction(final TypedArray a, final int index, final int base, + final float defValue) { final TypedValue value = a.peekValue(index); if (value == null) { return defValue; @@ -99,7 +123,7 @@ public final class ResourceUtils { return defValue; } - public static int getEnumValue(TypedArray a, int index, int defValue) { + public static int getEnumValue(final TypedArray a, final int index, final int defValue) { final TypedValue value = a.peekValue(index); if (value == null) { return defValue; @@ -110,19 +134,19 @@ public final class ResourceUtils { return defValue; } - public static boolean isFractionValue(TypedValue v) { + public static boolean isFractionValue(final TypedValue v) { return v.type == TypedValue.TYPE_FRACTION; } - public static boolean isDimensionValue(TypedValue v) { + public static boolean isDimensionValue(final TypedValue v) { return v.type == TypedValue.TYPE_DIMENSION; } - public static boolean isIntegerValue(TypedValue v) { + public static boolean isIntegerValue(final TypedValue v) { return v.type >= TypedValue.TYPE_FIRST_INT && v.type <= TypedValue.TYPE_LAST_INT; } - public static boolean isStringValue(TypedValue v) { + public static boolean isStringValue(final TypedValue v) { return v.type == TypedValue.TYPE_STRING; } } diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index e9c81dab0..9cb24b54e 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -178,9 +178,6 @@ public final class RichInputConnection { mComposingText.setLength(0); if (null != mIC) { mIC.commitText(text, i); - if (ProductionFlag.IS_EXPERIMENTAL) { - ResearchLogger.richInputConnection_commitText(text, i); - } } } @@ -287,40 +284,40 @@ public final class RichInputConnection { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) { if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); - // This method is only called for enter or backspace when speaking to old - // applications (target SDK <= 15), or for digits. + // This method is only called for enter or backspace when speaking to old applications + // (target SDK <= 15 (Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)), or for digits. // When talking to new applications we never use this method because it's inherently // racy and has unpredictable results, but for backward compatibility we continue // sending the key events for only Enter and Backspace because some applications // mistakenly catch them to do some stuff. switch (keyEvent.getKeyCode()) { - case KeyEvent.KEYCODE_ENTER: - mCommittedTextBeforeComposingText.append("\n"); - mCurrentCursorPosition += 1; - break; - case KeyEvent.KEYCODE_DEL: - if (0 == mComposingText.length()) { - if (mCommittedTextBeforeComposingText.length() > 0) { - mCommittedTextBeforeComposingText.delete( - mCommittedTextBeforeComposingText.length() - 1, - mCommittedTextBeforeComposingText.length()); - } - } else { - mComposingText.delete(mComposingText.length() - 1, mComposingText.length()); - } - if (mCurrentCursorPosition > 0) mCurrentCursorPosition -= 1; - break; - case KeyEvent.KEYCODE_UNKNOWN: - if (null != keyEvent.getCharacters()) { - mCommittedTextBeforeComposingText.append(keyEvent.getCharacters()); - mCurrentCursorPosition += keyEvent.getCharacters().length(); + case KeyEvent.KEYCODE_ENTER: + mCommittedTextBeforeComposingText.append("\n"); + mCurrentCursorPosition += 1; + break; + case KeyEvent.KEYCODE_DEL: + if (0 == mComposingText.length()) { + if (mCommittedTextBeforeComposingText.length() > 0) { + mCommittedTextBeforeComposingText.delete( + mCommittedTextBeforeComposingText.length() - 1, + mCommittedTextBeforeComposingText.length()); } - break; - default: - final String text = new String(new int[] { keyEvent.getUnicodeChar() }, 0, 1); - mCommittedTextBeforeComposingText.append(text); - mCurrentCursorPosition += text.length(); - break; + } else { + mComposingText.delete(mComposingText.length() - 1, mComposingText.length()); + } + if (mCurrentCursorPosition > 0) mCurrentCursorPosition -= 1; + break; + case KeyEvent.KEYCODE_UNKNOWN: + if (null != keyEvent.getCharacters()) { + mCommittedTextBeforeComposingText.append(keyEvent.getCharacters()); + mCurrentCursorPosition += keyEvent.getCharacters().length(); + } + break; + default: + final String text = new String(new int[] { keyEvent.getUnicodeChar() }, 0, 1); + mCommittedTextBeforeComposingText.append(text); + mCurrentCursorPosition += text.length(); + break; } } if (null != mIC) { @@ -537,17 +534,17 @@ public final class RichInputConnection { // Going backward, alternate skipping non-separators and separators until enough words // have been read. int count = additionalPrecedingWordsCount; - int start = before.length(); + int startIndexInBefore = before.length(); boolean isStoppingAtWhitespace = true; // toggles to indicate what to stop at while (true) { // see comments below for why this is guaranteed to halt - while (start > 0) { - final int codePoint = Character.codePointBefore(before, start); + while (startIndexInBefore > 0) { + final int codePoint = Character.codePointBefore(before, startIndexInBefore); if (isStoppingAtWhitespace == isSeparator(codePoint, sep)) { break; // inner loop } - --start; + --startIndexInBefore; if (Character.isSupplementaryCodePoint(codePoint)) { - --start; + --startIndexInBefore; } } // isStoppingAtWhitespace is true every other time through the loop, @@ -560,25 +557,20 @@ public final class RichInputConnection { } // Find last word separator after the cursor - int end = -1; - while (++end < after.length()) { - final int codePoint = Character.codePointAt(after, end); + int endIndexInAfter = -1; + while (++endIndexInAfter < after.length()) { + final int codePoint = Character.codePointAt(after, endIndexInAfter); if (isSeparator(codePoint, sep)) { break; } if (Character.isSupplementaryCodePoint(codePoint)) { - ++end; + ++endIndexInAfter; } } - final int cursor = getCursorPosition(); - if (start >= 0 && cursor + end <= after.length() + before.length()) { - String word = before.toString().substring(start, before.length()) - + after.toString().substring(0, end); - return new Range(before.length() - start, end, word); - } - - return null; + final String word = before.toString().substring(startIndexInBefore, before.length()) + + after.toString().substring(0, endIndexInAfter); + return new Range(before.length() - startIndexInBefore, endIndexInAfter, word); } public boolean isCursorTouchingWord(final SettingsValues settingsValues) { @@ -665,7 +657,11 @@ public final class RichInputConnection { return false; } deleteSurroundingText(2, 0); - commitText(" ", 1); + final String doubleSpace = " "; + commitText(doubleSpace, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(doubleSpace, Long.MAX_VALUE); + } return true; } @@ -686,7 +682,11 @@ public final class RichInputConnection { return false; } deleteSurroundingText(2, 0); - commitText(" " + textBeforeCursor.subSequence(0, 1), 1); + final String text = " " + textBeforeCursor.subSequence(0, 1); + commitText(text, 1); + if (ProductionFlag.IS_EXPERIMENTAL) { + ResearchLogger.getInstance().onWordComplete(text, Long.MAX_VALUE); + } return true; } diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index af0d61cc7..637916f76 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -21,6 +21,7 @@ import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; import android.content.Context; import android.content.SharedPreferences; import android.os.IBinder; +import android.preference.PreferenceManager; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; @@ -50,7 +51,8 @@ public final class RichInputMethodManager { return sInstance; } - public static void init(final Context context, final SharedPreferences prefs) { + public static void init(final Context context) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); sInstance.initInternal(context, prefs); } diff --git a/java/src/com/android/inputmethod/latin/SeekBarDialog.java b/java/src/com/android/inputmethod/latin/SeekBarDialog.java new file mode 100644 index 000000000..e576c0984 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SeekBarDialog.java @@ -0,0 +1,179 @@ +/* + * 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 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) { dialog.dismiss(); } + @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); + 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, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + mListener.onPositiveButtonClick(this); + return; + } + if (which == DialogInterface.BUTTON_NEGATIVE) { + mListener.onNegativeButtonClick(this); + return; + } + } + + @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 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 setMaxValue(final int max) { + mMaxValue = max; + return this; + } + + public Builder setValueFromat(final int resId) { + mValueFormatResId = resId; + return this; + } + + public Builder setValue(final int value) { + mValue = value; + 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/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 7a73cade3..1d9d85b47 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * 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 @@ -16,34 +16,16 @@ package com.android.inputmethod.latin; -import android.app.AlertDialog; -import android.app.backup.BackupManager; import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; -import android.media.AudioManager; -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.LayoutInflater; -import android.view.View; -import android.view.inputmethod.InputMethodSubtype; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; -import android.widget.TextView; +import android.preference.PreferenceManager; -import com.android.inputmethod.latin.define.ProductionFlag; -import com.android.inputmethodcommon.InputMethodSettingsFragment; +import com.android.inputmethod.latin.LocaleUtils.RunInLocale; -public final class Settings extends InputMethodSettingsFragment - implements SharedPreferences.OnSharedPreferenceChangeListener { +import java.util.Locale; +public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { // In the same order as xml/prefs.xml public static final String PREF_GENERAL_SETTINGS = "general_settings"; public static final String PREF_AUTO_CAP = "auto_cap"; @@ -84,387 +66,54 @@ public final class Settings extends InputMethodSettingsFragment public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; public static final String PREF_DEBUG_SETTINGS = "debug_settings"; - private PreferenceScreen mKeypressVibrationDurationSettingsPref; - private PreferenceScreen mKeypressSoundVolumeSettingsPref; - private ListPreference mVoicePreference; - private ListPreference mShowCorrectionSuggestionsPreference; - private ListPreference mAutoCorrectionThresholdPreference; - private ListPreference mKeyPreviewPopupDismissDelay; - // Use bigrams to predict the next word when there is no input for it yet - private CheckBoxPreference mBigramPrediction; - private Preference mDebugSettingsPreference; + private Resources mRes; + private SharedPreferences mPrefs; + private Locale mCurrentLocale; + private SettingsValues mSettingsValues; - private TextView mKeypressVibrationDurationSettingsTextView; - private TextView mKeypressSoundVolumeSettingsTextView; + private static final Settings sInstance = new Settings(); - private static void setPreferenceEnabled(final Preference preference, final boolean enabled) { - if (preference != null) { - preference.setEnabled(enabled); - } + public static Settings getInstance() { + return sInstance; } - private void ensureConsistencyOfAutoCorrectionSettings() { - final String autoCorrectionOff = getResources().getString( - R.string.auto_correction_threshold_mode_index_off); - final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); - setPreferenceEnabled(mBigramPrediction, !currentSetting.equals(autoCorrectionOff)); + public static void init(final Context context) { + sInstance.onCreate(context); } - @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); - setInputMethodSettingsCategoryTitle(R.string.language_selection_title); - setSubtypeEnablerTitle(R.string.select_language); - addPreferencesFromResource(R.xml.prefs); - - final Resources res = getResources(); - final Context context = getActivity(); - - // When we are called from the Settings application but we are not already running, the - // {@link SubtypeLocale} class may not have been initialized. It is safe to call - // {@link SubtypeLocale#init(Context)} multiple times. - SubtypeLocale.init(context); - mVoicePreference = (ListPreference) findPreference(PREF_VOICE_MODE); - mShowCorrectionSuggestionsPreference = - (ListPreference) findPreference(PREF_SHOW_SUGGESTIONS_SETTING); - SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - prefs.registerOnSharedPreferenceChangeListener(this); - - mAutoCorrectionThresholdPreference = - (ListPreference) findPreference(PREF_AUTO_CORRECTION_THRESHOLD); - mBigramPrediction = (CheckBoxPreference) findPreference(PREF_BIGRAM_PREDICTIONS); - ensureConsistencyOfAutoCorrectionSettings(); - - final PreferenceGroup generalSettings = - (PreferenceGroup) findPreference(PREF_GENERAL_SETTINGS); - final PreferenceGroup textCorrectionGroup = - (PreferenceGroup) findPreference(PREF_CORRECTION_SETTINGS); - final PreferenceGroup gestureTypingSettings = - (PreferenceGroup) findPreference(PREF_GESTURE_SETTINGS); - final PreferenceGroup miscSettings = - (PreferenceGroup) findPreference(PREF_MISC_SETTINGS); - - mDebugSettingsPreference = findPreference(PREF_DEBUG_SETTINGS); - if (mDebugSettingsPreference != null) { - if (ProductionFlag.IS_INTERNAL) { - final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); - debugSettingsIntent.setClassName( - context.getPackageName(), DebugSettingsActivity.class.getName()); - mDebugSettingsPreference.setIntent(debugSettingsIntent); - } else { - miscSettings.removePreference(mDebugSettingsPreference); - } - } - - final boolean showVoiceKeyOption = res.getBoolean( - R.bool.config_enable_show_voice_key_option); - if (!showVoiceKeyOption) { - generalSettings.removePreference(mVoicePreference); - } - - final PreferenceGroup advancedSettings = - (PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS); - if (!VibratorUtils.getInstance(context).hasVibrator()) { - generalSettings.removePreference(findPreference(PREF_VIBRATE_ON)); - if (null != advancedSettings) { // Theoretically advancedSettings cannot be null - advancedSettings.removePreference(findPreference(PREF_VIBRATION_DURATION_SETTINGS)); - } - } - - final boolean showKeyPreviewPopupOption = res.getBoolean( - R.bool.config_enable_show_popup_on_keypress_option); - mKeyPreviewPopupDismissDelay = - (ListPreference) findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); - if (!showKeyPreviewPopupOption) { - generalSettings.removePreference(findPreference(PREF_POPUP_ON)); - if (null != advancedSettings) { // Theoretically advancedSettings cannot be null - advancedSettings.removePreference(mKeyPreviewPopupDismissDelay); - } - } else { - final String[] entries = new String[] { - res.getString(R.string.key_preview_popup_dismiss_no_delay), - res.getString(R.string.key_preview_popup_dismiss_default_delay), - }; - final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( - R.integer.config_key_preview_linger_timeout)); - mKeyPreviewPopupDismissDelay.setEntries(entries); - mKeyPreviewPopupDismissDelay.setEntryValues( - new String[] { "0", popupDismissDelayDefaultValue }); - if (null == mKeyPreviewPopupDismissDelay.getValue()) { - mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); - } - setPreferenceEnabled(mKeyPreviewPopupDismissDelay, - SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); - } - - setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST), - SettingsValues.showsLanguageSwitchKey(prefs)); - - final PreferenceScreen dictionaryLink = - (PreferenceScreen) findPreference(PREF_CONFIGURE_DICTIONARIES_KEY); - final Intent intent = dictionaryLink.getIntent(); - - final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); - // TODO: The experimental version is not supported by the Dictionary Pack Service yet - if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) { - textCorrectionGroup.removePreference(dictionaryLink); - } - - final boolean gestureInputEnabledByBuildConfig = res.getBoolean( - R.bool.config_gesture_input_enabled_by_build_config); - if (!gestureInputEnabledByBuildConfig) { - getPreferenceScreen().removePreference(gestureTypingSettings); - } - - mKeypressVibrationDurationSettingsPref = - (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS); - if (mKeypressVibrationDurationSettingsPref != null) { - mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference arg0) { - showKeypressVibrationDurationSettingsDialog(); - return true; - } - }); - updateKeypressVibrationDurationSettingsSummary(prefs, res); - } - - mKeypressSoundVolumeSettingsPref = - (PreferenceScreen) findPreference(PREF_KEYPRESS_SOUND_VOLUME); - if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener( - new OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference arg0) { - showKeypressSoundVolumeSettingDialog(); - return true; - } - }); - updateKeypressSoundVolumeSummary(prefs, res); - } - refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); + private Settings() { + // Intentional empty constructor for singleton. } - @Override - public void onResume() { - super.onResume(); - final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - if (isShortcutImeEnabled) { - updateVoiceModeSummary(); - } else { - getPreferenceScreen().removePreference(mVoicePreference); - } - updateShowCorrectionSuggestionsSummary(); - updateKeyPreviewPopupDelaySummary(); - updateCustomInputStylesSummary(); + private void onCreate(final Context context) { + mRes = context.getResources(); + mPrefs = PreferenceManager.getDefaultSharedPreferences(context); + mPrefs.registerOnSharedPreferenceChangeListener(this); } - @Override public void onDestroy() { - getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( - this); - super.onDestroy(); + mPrefs.unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - (new BackupManager(getActivity())).dataChanged(); - if (key.equals(PREF_POPUP_ON)) { - setPreferenceEnabled(findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY), - prefs.getBoolean(PREF_POPUP_ON, true)); - } else if (key.equals(PREF_SHOW_LANGUAGE_SWITCH_KEY)) { - setPreferenceEnabled(findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST), - SettingsValues.showsLanguageSwitchKey(prefs)); - } else if (key.equals(PREF_GESTURE_INPUT)) { - final boolean gestureInputEnabledByConfig = getResources().getBoolean( - R.bool.config_gesture_input_enabled_by_build_config); - if (gestureInputEnabledByConfig) { - final boolean gestureInputEnabledByUser = prefs.getBoolean( - PREF_GESTURE_INPUT, true); - setPreferenceEnabled(findPreference(PREF_GESTURE_PREVIEW_TRAIL), - gestureInputEnabledByUser); - setPreferenceEnabled(findPreference(PREF_GESTURE_FLOATING_PREVIEW_TEXT), - gestureInputEnabledByUser); - } - } - ensureConsistencyOfAutoCorrectionSettings(); - updateVoiceModeSummary(); - updateShowCorrectionSuggestionsSummary(); - updateKeyPreviewPopupDelaySummary(); - refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); - } - - private void updateShowCorrectionSuggestionsSummary() { - mShowCorrectionSuggestionsPreference.setSummary( - getResources().getStringArray(R.array.prefs_suggestion_visibilities) - [mShowCorrectionSuggestionsPreference.findIndexOfValue( - mShowCorrectionSuggestionsPreference.getValue())]); - } - - private void updateCustomInputStylesSummary() { - final PreferenceScreen customInputStyles = - (PreferenceScreen)findPreference(PREF_CUSTOM_INPUT_STYLES); - final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); - final Resources res = getResources(); - final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res); - final InputMethodSubtype[] subtypes = - AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); - final StringBuilder styles = new StringBuilder(); - for (final InputMethodSubtype subtype : subtypes) { - if (styles.length() > 0) styles.append(", "); - styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res)); - } - customInputStyles.setSummary(styles); - } - - private void updateKeyPreviewPopupDelaySummary() { - final ListPreference lp = mKeyPreviewPopupDismissDelay; - final CharSequence[] entries = lp.getEntries(); - if (entries == null || entries.length <= 0) return; - lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]); - } - - private void updateVoiceModeSummary() { - mVoicePreference.setSummary( - getResources().getStringArray(R.array.voice_input_modes_summary) - [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); + loadSettings(mCurrentLocale, mSettingsValues.mInputAttributes); } - private void refreshEnablingsOfKeypressSoundAndVibrationSettings( - final SharedPreferences sp, final Resources res) { - if (mKeypressVibrationDurationSettingsPref != null) { - final boolean hasVibratorHardware = VibratorUtils.getInstance(getActivity()) - .hasVibrator(); - final boolean vibrateOnByUser = sp.getBoolean(Settings.PREF_VIBRATE_ON, - res.getBoolean(R.bool.config_default_vibration_enabled)); - setPreferenceEnabled(mKeypressVibrationDurationSettingsPref, - hasVibratorHardware && vibrateOnByUser); - } - - if (mKeypressSoundVolumeSettingsPref != null) { - final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, - res.getBoolean(R.bool.config_default_sound_enabled)); - setPreferenceEnabled(mKeypressSoundVolumeSettingsPref, soundOn); - } - } - - private void updateKeypressVibrationDurationSettingsSummary( - final SharedPreferences sp, final Resources res) { - if (mKeypressVibrationDurationSettingsPref != null) { - mKeypressVibrationDurationSettingsPref.setSummary( - SettingsValues.getCurrentVibrationDuration(sp, res) - + res.getString(R.string.settings_ms)); - } - } - - private void showKeypressVibrationDurationSettingsDialog() { - final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); - final Context context = getActivity(); - final Resources res = context.getResources(); - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.prefs_keypress_vibration_duration_settings); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - final int ms = Integer.valueOf( - mKeypressVibrationDurationSettingsTextView.getText().toString()); - sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); - updateKeypressVibrationDurationSettingsSummary(sp, res); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - } - }); - final View v = LayoutInflater.from(context).inflate( - R.layout.vibration_settings_dialog, null); - 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); - sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { - final int tempMs = arg1; - mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(tempMs)); - } - - @Override - public void onStartTrackingTouch(SeekBar arg0) { - } - + public void loadSettings(final Locale locale, final InputAttributes inputAttributes) { + mCurrentLocale = locale; + final SharedPreferences prefs = mPrefs; + final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { @Override - public void onStopTrackingTouch(SeekBar arg0) { - final int tempMs = arg0.getProgress(); - VibratorUtils.getInstance(context).vibrate(tempMs); + protected SettingsValues job(final Resources res) { + return new SettingsValues(prefs, res, inputAttributes); } - }); - sb.setProgress(currentMs); - mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(currentMs)); - builder.setView(v); - builder.create().show(); + }; + mSettingsValues = job.runInLocale(mRes, locale); } - private void updateKeypressSoundVolumeSummary(final SharedPreferences sp, final Resources res) { - if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( - (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100))); - } - } - - private void showKeypressSoundVolumeSettingDialog() { - final Context context = getActivity(); - final AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); - final Resources res = context.getResources(); - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.prefs_keypress_sound_volume_settings); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - final float volume = - ((float)Integer.valueOf( - mKeypressSoundVolumeSettingsTextView.getText().toString())) / 100; - sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply(); - updateKeypressSoundVolumeSummary(sp, res); - } - }); - builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - } - }); - final View v = LayoutInflater.from(context).inflate( - R.layout.sound_effect_volume_dialog, null); - 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); - sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { - final int tempVolume = arg1; - mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(tempVolume)); - } - - @Override - public void onStartTrackingTouch(SeekBar arg0) { - } - - @Override - public void onStopTrackingTouch(SeekBar arg0) { - final float tempVolume = ((float)arg0.getProgress()) / 100; - am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, tempVolume); - } - }); - sb.setProgress(currentVolumeInt); - mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(currentVolumeInt)); - builder.setView(v); - builder.create().show(); + // TODO: Remove this method and add proxy method to SettingsValues. + public SettingsValues getCurrent() { + return mSettingsValues; } } diff --git a/java/src/com/android/inputmethod/latin/SettingsActivity.java b/java/src/com/android/inputmethod/latin/SettingsActivity.java index 0d3c8ebb7..3aeb10113 100644 --- a/java/src/com/android/inputmethod/latin/SettingsActivity.java +++ b/java/src/com/android/inputmethod/latin/SettingsActivity.java @@ -20,7 +20,7 @@ import android.content.Intent; import android.preference.PreferenceActivity; public final class SettingsActivity extends PreferenceActivity { - private static final String DEFAULT_FRAGMENT = Settings.class.getName(); + private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName(); @Override public Intent getIntent() { diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java new file mode 100644 index 000000000..a2980bfa2 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java @@ -0,0 +1,375 @@ +/* + * 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 android.app.backup.BackupManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.media.AudioManager; +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; + +import com.android.inputmethod.latin.define.ProductionFlag; +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; + private ListPreference mKeyPreviewPopupDismissDelay; + // Use bigrams to predict the next word when there is no input for it yet + private CheckBoxPreference mBigramPrediction; + private Preference mDebugSettingsPreference; + + private void setPreferenceEnabled(final String preferenceKey, final boolean enabled) { + final Preference preference = findPreference(preferenceKey); + if (preference != null) { + preference.setEnabled(enabled); + } + } + + private void ensureConsistencyOfAutoCorrectionSettings() { + final String autoCorrectionOff = getResources().getString( + R.string.auto_correction_threshold_mode_index_off); + final String currentSetting = mAutoCorrectionThresholdPreference.getValue(); + mBigramPrediction.setEnabled(!currentSetting.equals(autoCorrectionOff)); + } + + @Override + public void onCreate(final Bundle icicle) { + super.onCreate(icicle); + setInputMethodSettingsCategoryTitle(R.string.language_selection_title); + setSubtypeEnablerTitle(R.string.select_language); + addPreferencesFromResource(R.xml.prefs); + + final Resources res = getResources(); + final Context context = getActivity(); + + // When we are called from the Settings application but we are not already running, the + // {@link SubtypeLocale} class may not have been initialized. It is safe to call + // {@link SubtypeLocale#init(Context)} multiple times. + SubtypeLocale.init(context); + mVoicePreference = (ListPreference) findPreference(Settings.PREF_VOICE_MODE); + mShowCorrectionSuggestionsPreference = + (ListPreference) findPreference(Settings.PREF_SHOW_SUGGESTIONS_SETTING); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + prefs.registerOnSharedPreferenceChangeListener(this); + + mAutoCorrectionThresholdPreference = + (ListPreference) findPreference(Settings.PREF_AUTO_CORRECTION_THRESHOLD); + mBigramPrediction = (CheckBoxPreference) findPreference(Settings.PREF_BIGRAM_PREDICTIONS); + ensureConsistencyOfAutoCorrectionSettings(); + + final PreferenceGroup generalSettings = + (PreferenceGroup) findPreference(Settings.PREF_GENERAL_SETTINGS); + final PreferenceGroup textCorrectionGroup = + (PreferenceGroup) findPreference(Settings.PREF_CORRECTION_SETTINGS); + final PreferenceGroup gestureTypingSettings = + (PreferenceGroup) findPreference(Settings.PREF_GESTURE_SETTINGS); + final PreferenceGroup miscSettings = + (PreferenceGroup) findPreference(Settings.PREF_MISC_SETTINGS); + + mDebugSettingsPreference = findPreference(Settings.PREF_DEBUG_SETTINGS); + if (mDebugSettingsPreference != null) { + if (ProductionFlag.IS_INTERNAL) { + final Intent debugSettingsIntent = new Intent(Intent.ACTION_MAIN); + debugSettingsIntent.setClassName( + context.getPackageName(), DebugSettingsActivity.class.getName()); + mDebugSettingsPreference.setIntent(debugSettingsIntent); + } else { + miscSettings.removePreference(mDebugSettingsPreference); + } + } + + final boolean showVoiceKeyOption = res.getBoolean( + R.bool.config_enable_show_voice_key_option); + if (!showVoiceKeyOption) { + generalSettings.removePreference(mVoicePreference); + } + + final PreferenceGroup advancedSettings = + (PreferenceGroup) findPreference(Settings.PREF_ADVANCED_SETTINGS); + if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { + generalSettings.removePreference(findPreference(Settings.PREF_VIBRATE_ON)); + if (null != advancedSettings) { // Theoretically advancedSettings cannot be null + advancedSettings.removePreference( + findPreference(Settings.PREF_VIBRATION_DURATION_SETTINGS)); + } + } + + final boolean showKeyPreviewPopupOption = res.getBoolean( + R.bool.config_enable_show_popup_on_keypress_option); + mKeyPreviewPopupDismissDelay = + (ListPreference) findPreference(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); + if (!showKeyPreviewPopupOption) { + generalSettings.removePreference(findPreference(Settings.PREF_POPUP_ON)); + if (null != advancedSettings) { // Theoretically advancedSettings cannot be null + advancedSettings.removePreference(mKeyPreviewPopupDismissDelay); + } + } else { + final String[] entries = new String[] { + res.getString(R.string.key_preview_popup_dismiss_no_delay), + res.getString(R.string.key_preview_popup_dismiss_default_delay), + }; + final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( + R.integer.config_key_preview_linger_timeout)); + mKeyPreviewPopupDismissDelay.setEntries(entries); + mKeyPreviewPopupDismissDelay.setEntryValues( + new String[] { "0", popupDismissDelayDefaultValue }); + if (null == mKeyPreviewPopupDismissDelay.getValue()) { + mKeyPreviewPopupDismissDelay.setValue(popupDismissDelayDefaultValue); + } + mKeyPreviewPopupDismissDelay.setEnabled( + SettingsValues.isKeyPreviewPopupEnabled(prefs, res)); + } + + setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, + SettingsValues.showsLanguageSwitchKey(prefs)); + + final PreferenceScreen dictionaryLink = + (PreferenceScreen) findPreference(Settings.PREF_CONFIGURE_DICTIONARIES_KEY); + final Intent intent = dictionaryLink.getIntent(); + + final int number = context.getPackageManager().queryIntentActivities(intent, 0).size(); + // TODO: The experimental version is not supported by the Dictionary Pack Service yet + if (ProductionFlag.IS_EXPERIMENTAL || 0 >= number) { + textCorrectionGroup.removePreference(dictionaryLink); + } + + final boolean gestureInputEnabledByBuildConfig = res.getBoolean( + R.bool.config_gesture_input_enabled_by_build_config); + if (!gestureInputEnabledByBuildConfig) { + 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, + SettingsValues.getCurrentVibrationDuration(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))); + } + refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); + } + + @Override + public void onResume() { + super.onResume(); + final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); + if (isShortcutImeEnabled) { + updateVoiceModeSummary(); + } else { + getPreferenceScreen().removePreference(mVoicePreference); + } + updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); + updateCustomInputStylesSummary(); + } + + @Override + public void onDestroy() { + getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( + this); + super.onDestroy(); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { + (new BackupManager(getActivity())).dataChanged(); + if (key.equals(Settings.PREF_POPUP_ON)) { + setPreferenceEnabled(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + prefs.getBoolean(Settings.PREF_POPUP_ON, true)); + } else if (key.equals(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY)) { + setPreferenceEnabled(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, + SettingsValues.showsLanguageSwitchKey(prefs)); + } else if (key.equals(Settings.PREF_GESTURE_INPUT)) { + final boolean gestureInputEnabledByConfig = getResources().getBoolean( + R.bool.config_gesture_input_enabled_by_build_config); + if (gestureInputEnabledByConfig) { + final boolean gestureInputEnabledByUser = prefs.getBoolean( + Settings.PREF_GESTURE_INPUT, true); + setPreferenceEnabled(Settings.PREF_GESTURE_PREVIEW_TRAIL, + gestureInputEnabledByUser); + setPreferenceEnabled(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, + gestureInputEnabledByUser); + } + } + ensureConsistencyOfAutoCorrectionSettings(); + updateVoiceModeSummary(); + updateShowCorrectionSuggestionsSummary(); + updateKeyPreviewPopupDelaySummary(); + refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); + } + + private void updateShowCorrectionSuggestionsSummary() { + mShowCorrectionSuggestionsPreference.setSummary( + getResources().getStringArray(R.array.prefs_suggestion_visibilities) + [mShowCorrectionSuggestionsPreference.findIndexOfValue( + mShowCorrectionSuggestionsPreference.getValue())]); + } + + private void updateCustomInputStylesSummary() { + final PreferenceScreen customInputStyles = + (PreferenceScreen)findPreference(Settings.PREF_CUSTOM_INPUT_STYLES); + final SharedPreferences prefs = getPreferenceManager().getSharedPreferences(); + final Resources res = getResources(); + final String prefSubtype = SettingsValues.getPrefAdditionalSubtypes(prefs, res); + final InputMethodSubtype[] subtypes = + AdditionalSubtype.createAdditionalSubtypesArray(prefSubtype); + final StringBuilder styles = new StringBuilder(); + for (final InputMethodSubtype subtype : subtypes) { + if (styles.length() > 0) styles.append(", "); + styles.append(SubtypeLocale.getSubtypeDisplayName(subtype, res)); + } + customInputStyles.setSummary(styles); + } + + private void updateKeyPreviewPopupDelaySummary() { + final ListPreference lp = mKeyPreviewPopupDismissDelay; + final CharSequence[] entries = lp.getEntries(); + if (entries == null || entries.length <= 0) return; + lp.setSummary(entries[lp.findIndexOfValue(lp.getValue())]); + } + + private void updateVoiceModeSummary() { + mVoicePreference.setSummary( + getResources().getStringArray(R.array.voice_input_modes_summary) + [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); + } + + 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); + } + } + + private void showKeypressVibrationDurationSettingsDialog() { + final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); + final Context context = getActivity(); + final PreferenceScreen settingsPref = mKeypressVibrationDurationSettingsPref; + final SeekBarDialog.Listener listener = new SeekBarDialog.Adapter() { + @Override + public void onPositiveButtonClick(final SeekBarDialog dialog) { + final int ms = dialog.getValue(); + sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); + if (settingsPref != null) { + settingsPref.setSummary(dialog.getValueText()); + } + } + + @Override + public void onStopTrackingTouch(final SeekBarDialog dialog) { + final int ms = dialog.getValue(); + AudioAndHapticFeedbackManager.getInstance().vibrate(ms); + } + }; + final int currentMs = SettingsValues.getCurrentVibrationDuration(sp, getResources()); + final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); + builder.setTitle(R.string.prefs_keypress_vibration_duration_settings) + .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)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * PERCENT_FLOAT); + } + + 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() { + @Override + public void onPositiveButtonClick(final SeekBarDialog dialog) { + final float volume = dialog.getValue() / PERCENT_FLOAT; + sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply(); + if (settingsPref != null) { + settingsPref.setSummary(dialog.getValueText()); + } + } + + @Override + public void onStopTrackingTouch(final SeekBarDialog dialog) { + final float volume = dialog.getValue() / PERCENT_FLOAT; + am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, volume); + } + }; + final SeekBarDialog.Builder builder = new SeekBarDialog.Builder(context); + final int currentVolumeInt = getCurrentKeyPressSoundVolumePercent(sp, getResources()); + builder.setTitle(R.string.prefs_keypress_sound_volume_settings) + .setListener(listener) + .setMaxValue(PERCENT_INT) + .setValue(currentVolumeInt) + .create() + .show(); + } +} diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index a23876722..39406621c 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; -import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; @@ -78,16 +77,12 @@ public final class SettingsValues { public final boolean mUseDoubleSpacePeriod; // Use bigrams to predict the next word when there is no input for it yet public final boolean mBigramPredictionEnabled; - @SuppressWarnings("unused") // TODO: Use this - private final int mVibrationDurationSettingsRawValue; - @SuppressWarnings("unused") // TODO: Use this - private final float mKeypressSoundVolumeRawValue; public final boolean mGestureInputEnabled; public final boolean mGesturePreviewTrailEnabled; public final boolean mGestureFloatingPreviewTextEnabled; // From the input box - private final InputAttributes mInputAttributes; + public final InputAttributes mInputAttributes; // Deduced settings public final int mKeypressVibrationDuration; @@ -100,10 +95,8 @@ public final class SettingsValues { private final boolean mVoiceKeyEnabled; private final boolean mVoiceKeyOnMain; - public SettingsValues(final SharedPreferences prefs, final InputAttributes inputAttributes, - final Context context) { - final Resources res = context.getResources(); - + public SettingsValues(final SharedPreferences prefs, final Resources res, + final InputAttributes inputAttributes) { // Get the resources mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions); mWeakSpaceStrippers = res.getString(R.string.weak_space_stripping_symbols); @@ -125,7 +118,7 @@ public final class SettingsValues { res.getString(R.string.symbols_excluded_from_word_separators); mWordSeparators = createWordSeparators(mWeakSpaceStrippers, mWeakSpaceSwappers, mSymbolsExcludedFromWordSeparators, res); - mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); + mHintToSaveText = res.getText(R.string.hint_add_to_dictionary); // Store the input attributes if (null == inputAttributes) { @@ -136,7 +129,7 @@ public final class SettingsValues { // Get the settings preferences mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true); - mVibrateOn = isVibrateOn(context, prefs, res); + mVibrateOn = isVibrateOn(prefs, res); mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, res.getBoolean(R.bool.config_default_sound_enabled)); mKeyPreviewPopupOn = isKeyPreviewPopupEnabled(prefs, res); @@ -158,9 +151,6 @@ public final class SettingsValues { mUseDoubleSpacePeriod = prefs.getBoolean(Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, true); mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); mBigramPredictionEnabled = isBigramPredictionEnabled(prefs, res); - 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); @@ -221,9 +211,8 @@ public final class SettingsValues { throw new RuntimeException("Bug: visibility string is not configured correctly"); } - private static boolean isVibrateOn(final Context context, final SharedPreferences prefs, - final Resources res) { - final boolean hasVibrator = VibratorUtils.getInstance(context).hasVibrator(); + private static boolean isVibrateOn(final SharedPreferences prefs, final Resources res) { + final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator(); return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, res.getBoolean(R.bool.config_default_vibration_enabled)); } @@ -280,6 +269,7 @@ public final class SettingsValues { return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } + // TODO: Clean up and move public helper methods to Settings class. // Public to access from KeyboardSwitcher. Should it have access to some // process-global instance instead? public static boolean isKeyPreviewPopupEnabled(final SharedPreferences prefs, @@ -383,27 +373,23 @@ public final class SettingsValues { // Accessed from the settings interface, hence public public static float getCurrentKeypressSoundVolume(final SharedPreferences prefs, final Resources res) { - // TODO: use mVibrationDurationSettingsRawValue instead of reading it again here final float volume = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); if (volume >= 0) { return volume; } - - return Float.parseFloat(ResourceUtils.getDeviceOverrideValue( - res, R.array.keypress_volumes, "-1.0f")); + return Float.parseFloat( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_volumes)); } // Likewise public static int getCurrentVibrationDuration(final SharedPreferences prefs, final Resources res) { - // TODO: use mKeypressVibrationDuration instead of reading it again here final int ms = prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); if (ms >= 0) { return ms; } - - return Integer.parseInt(ResourceUtils.getDeviceOverrideValue( - res, R.array.keypress_vibration_durations, "-1")); + return Integer.parseInt( + ResourceUtils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations)); } // Likewise @@ -434,9 +420,4 @@ public final class SettingsValues { public boolean isSameInputType(final EditorInfo editorInfo) { return mInputAttributes.isSameInputType(editorInfo); } - - // For debug. - public String getInputAttributesDebugString() { - return mInputAttributes.toString(); - } } diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java index 043043cef..ddaa5ff5b 100644 --- a/java/src/com/android/inputmethod/latin/StringUtils.java +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -62,6 +62,23 @@ public final class StringUtils { } /** + * Find a string that start with specified prefix from an array. + * + * @param prefix a prefix string to find. + * @param array an string array to be searched. + * @return the rest part of the string that starts with the prefix. + * Returns null if it couldn't be found. + */ + public static String findPrefixedString(final String prefix, final String[] array) { + for (final String element : array) { + if (element.startsWith(prefix)) { + return element.substring(prefix.length()); + } + } + return null; + } + + /** * Remove duplicates from an array of strings. * * This method will always keep the first occurrence of all strings at their position diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index 5d8c0b17d..370a6594b 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -130,7 +130,8 @@ public final class SubtypeLocale { } public static int getSubtypeNameId(String localeString, String keyboardLayoutName) { - if (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 && isExceptionalLocale(localeString)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN + && isExceptionalLocale(localeString)) { return sExceptionalLocaleToWithLayoutNameIdsMap.get(localeString); } final String key = localeString.equals(NO_LANGUAGE) @@ -166,8 +167,9 @@ public final class SubtypeLocale { // zz azerty T No language (AZERTY) in system locale public static String getSubtypeDisplayName(final InputMethodSubtype subtype, Resources res) { - final String replacementString = (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 - && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) + final String replacementString = + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN + && subtype.containsExtraValueKey(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME)) ? subtype.getExtraValueOf(UNTRANSLATABLE_STRING_IN_SUBTYPE_NAME) : getSubtypeLocaleDisplayName(subtype.getLocale()); final int nameResId = subtype.getNameResId(); diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 8f2e27549..fe2908428 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -20,7 +20,6 @@ import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.REQ_NET import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.net.ConnectivityManager; @@ -53,9 +52,6 @@ public final class SubtypeSwitcher { private InputMethodInfo mShortcutInputMethodInfo; private InputMethodSubtype mShortcutSubtype; private InputMethodSubtype mNoLanguageSubtype; - // Note: This variable is always non-null after {@link #initialize(LatinIME)}. - private InputMethodSubtype mCurrentSubtype; - private Locale mCurrentSystemLocale; /*-----------------------------------------------------------*/ private boolean mIsNetworkConnected; @@ -84,7 +80,6 @@ public final class SubtypeSwitcher { public static void init(final Context context) { SubtypeLocale.init(context); sInstance.initialize(context); - sInstance.updateAllParameters(); } private SubtypeSwitcher() { @@ -96,60 +91,28 @@ public final class SubtypeSwitcher { mRichImm = RichInputMethodManager.getInstance(); mConnectivityManager = (ConnectivityManager) service.getSystemService( Context.CONNECTIVITY_SERVICE); - mCurrentSystemLocale = mResources.getConfiguration().locale; mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet( SubtypeLocale.NO_LANGUAGE, SubtypeLocale.QWERTY); - mCurrentSubtype = mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype); if (mNoLanguageSubtype == null) { throw new RuntimeException("Can't find no lanugage with QWERTY subtype"); } final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); mIsNetworkConnected = (info != null && info.isConnected()); - } - - // Update all parameters stored in SubtypeSwitcher. - // Only configuration changed event is allowed to call this because this is heavy. - private void updateAllParameters() { - mCurrentSystemLocale = mResources.getConfiguration().locale; - updateSubtype(mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype)); - updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled(); - } - /** - * Update parameters which are changed outside LatinIME. This parameters affect UI so they - * should be updated every time onStartInputView. - * - * @return true if the current subtype is enabled. - */ - public boolean updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled() { - final boolean currentSubtypeEnabled = - updateEnabledSubtypesAndReturnIfEnabled(mCurrentSubtype); - updateShortcutIME(); - return currentSubtypeEnabled; + onSubtypeChanged(getCurrentSubtype()); + updateParametersOnStartInputView(); } /** - * Update enabled subtypes from the framework. - * - * @param subtype the subtype to be checked - * @return true if the {@code subtype} is enabled. + * Update parameters which are changed outside LatinIME. This parameters affect UI so that they + * should be updated every time onStartInputView is called. */ - private boolean updateEnabledSubtypesAndReturnIfEnabled(final InputMethodSubtype subtype) { + public void updateParametersOnStartInputView() { final List<InputMethodSubtype> enabledSubtypesOfThisIme = mRichImm.getInputMethodManager().getEnabledInputMethodSubtypeList(null, true); mNeedsToDisplayLanguage.updateEnabledSubtypeCount(enabledSubtypesOfThisIme.size()); - - for (final InputMethodSubtype ims : enabledSubtypesOfThisIme) { - if (ims.equals(subtype)) { - return true; - } - } - if (DBG) { - Log.w(TAG, "Subtype: " + subtype.getLocale() + "/" + subtype.getExtraValue() - + " was disabled"); - } - return false; + updateShortcutIME(); } private void updateShortcutIME() { @@ -185,25 +148,21 @@ public final class SubtypeSwitcher { } // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. - public void updateSubtype(InputMethodSubtype newSubtype) { + public void onSubtypeChanged(final InputMethodSubtype newSubtype) { if (DBG) { - Log.w(TAG, "onCurrentInputMethodSubtypeChanged: to: " - + newSubtype.getLocale() + "/" + newSubtype.getExtraValue() + ", from: " - + mCurrentSubtype.getLocale() + "/" + mCurrentSubtype.getExtraValue()); + Log.w(TAG, "onSubtypeChanged: " + SubtypeLocale.getSubtypeDisplayName( + newSubtype, mResources)); } final Locale newLocale = SubtypeLocale.getSubtypeLocale(newSubtype); - final boolean sameLocale = mCurrentSystemLocale.equals(newLocale); - final boolean sameLanguage = mCurrentSystemLocale.getLanguage().equals( - newLocale.getLanguage()); + final Locale systemLocale = mResources.getConfiguration().locale; + final boolean sameLocale = systemLocale.equals(newLocale); + final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage()); final boolean implicitlyEnabled = mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype); mNeedsToDisplayLanguage.updateIsSystemLanguageSameAsInputLanguage( sameLocale || (sameLanguage && implicitlyEnabled)); - if (newSubtype.equals(mCurrentSubtype)) return; - - mCurrentSubtype = newSubtype; updateShortcutIME(); } @@ -281,21 +240,11 @@ public final class SubtypeSwitcher { } public Locale getCurrentSubtypeLocale() { - return SubtypeLocale.getSubtypeLocale(mCurrentSubtype); - } - - public boolean onConfigurationChanged(final Configuration conf) { - final Locale systemLocale = conf.locale; - final boolean systemLocaleChanged = !systemLocale.equals(mCurrentSystemLocale); - // If system configuration was changed, update all parameters. - if (systemLocaleChanged) { - updateAllParameters(); - } - return systemLocaleChanged; + return SubtypeLocale.getSubtypeLocale(getCurrentSubtype()); } public InputMethodSubtype getCurrentSubtype() { - return mCurrentSubtype; + return mRichImm.getCurrentInputMethodSubtype(mNoLanguageSubtype); } public InputMethodSubtype getNoLanguageSubtype() { diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index ddae5ac48..a16784985 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -24,27 +24,28 @@ import android.content.Intent; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.provider.UserDictionary.Words; import android.text.TextUtils; import java.util.Arrays; /** - * An expandable dictionary that stores the words in the user unigram dictionary. - * - * Largely a copy of UserDictionary, will replace that class in the future. + * An expandable dictionary that stores the words in the user dictionary provider into a binary + * dictionary file to use it from native code. */ public class UserBinaryDictionary extends ExpandableBinaryDictionary { // The user dictionary provider uses an empty string to mean "all languages". private static final String USER_DICTIONARY_ALL_LANGUAGES = ""; + private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250; + private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160; // TODO: use Words.SHORTCUT when we target JellyBean or above final static String SHORTCUT = "shortcut"; private static final String[] PROJECTION_QUERY; static { - // 16 is JellyBean, but we want this to compile against ICS. - if (android.os.Build.VERSION.SDK_INT >= 16) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { PROJECTION_QUERY = new String[] { Words.WORD, SHORTCUT, @@ -90,13 +91,14 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { mObserver = new ContentObserver(null) { @Override public void onChange(final boolean self) { - // This hook is deprecated as of API level 16, but should still be supported for - // cases where the IME is running on an older version of the platform. + // This hook is deprecated as of API level 16 (Build.VERSION_CODES.JELLY_BEAN), + // but should still be supported for cases where the IME is running on an older + // version of the platform. onChange(self, null); } - // The following hook is only available as of API level 16, and as such it will only - // work on JellyBean+ devices. On older versions of the platform, the hook - // above will be called instead. + // The following hook is only available as of API level 16 + // (Build.VERSION_CODES.JELLY_BEAN), and as such it will only work on JellyBean+ + // devices. On older versions of the platform, the hook above will be called instead. @Override public void onChange(final boolean self, final Uri uri) { setRequiresReload(true); @@ -232,9 +234,21 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { mContext.startActivity(intent); } + private int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) { + // The default frequency for the user dictionary is 250 for historical reasons. + // Latin IME considers a good value for the default user dictionary frequency + // is about 160 considering the scale we use. So we are scaling down the values. + if (defaultFrequency > Integer.MAX_VALUE / LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) { + return (defaultFrequency / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY) + * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY; + } else { + return (defaultFrequency * LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY) + / HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY; + } + } + private void addWords(final Cursor cursor) { - // 16 is JellyBean, but we want this to compile against ICS. - final boolean hasShortcutColumn = android.os.Build.VERSION.SDK_INT >= 16; + final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; clearFusionDictionary(); if (cursor == null) return; if (cursor.moveToFirst()) { @@ -245,12 +259,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { final String word = cursor.getString(indexWord); final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null; final int frequency = cursor.getInt(indexFrequency); + final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency); // Safeguard against adding really long words. if (word.length() < MAX_WORD_LENGTH) { - super.addWord(word, null, frequency); + super.addWord(word, null, adjustedFrequency); } if (null != shortcut && shortcut.length() < MAX_WORD_LENGTH) { - super.addWord(shortcut, word, frequency); + super.addWord(shortcut, word, adjustedFrequency); } cursor.moveToNext(); } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java index 100e377f6..4fa3d7df8 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java @@ -48,6 +48,7 @@ public final class UserHistoryDictIOUtils { public void setBigram(final String word1, final String word2, final int frequency); } + @UsedForTesting public interface BigramDictionaryInterface { public int getFrequency(final String word1, final String word2); } @@ -214,4 +215,4 @@ public final class UserHistoryDictIOUtils { } } -}
\ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java index df44948f9..316f09603 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java @@ -18,6 +18,8 @@ package com.android.inputmethod.latin; import android.util.Log; +import com.android.inputmethod.annotations.UsedForTesting; + import java.util.HashMap; import java.util.Set; @@ -26,6 +28,7 @@ import java.util.Set; * All bigrams including stale ones in SQL DB should be stored in this class to avoid adding stale * bigrams when we write to the SQL DB. */ +@UsedForTesting public final class UserHistoryDictionaryBigramList { public static final byte FORGETTING_CURVE_INITIAL_VALUE = 0; private static final String TAG = UserHistoryDictionaryBigramList.class.getSimpleName(); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 3eac6a237..acfcd5354 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -61,7 +61,7 @@ public final class Utils { } } - /* package */ static class RingCharBuffer { + /* package */ static final class RingCharBuffer { private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; private static final int INVALID_COORDINATE = -2; @@ -203,7 +203,7 @@ public final class Utils { } // Initialization-on-demand holder - private static class OnDemandInitializationHolder { + private static final class OnDemandInitializationHolder { public static final UsabilityStudyLogUtils sInstance = new UsabilityStudyLogUtils(); } diff --git a/java/src/com/android/inputmethod/latin/VibratorUtils.java b/java/src/com/android/inputmethod/latin/VibratorUtils.java deleted file mode 100644 index b6696cec0..000000000 --- a/java/src/com/android/inputmethod/latin/VibratorUtils.java +++ /dev/null @@ -1,50 +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.content.Context; -import android.os.Vibrator; - -public final class VibratorUtils { - private static final VibratorUtils sInstance = new VibratorUtils(); - private Vibrator mVibrator; - - private VibratorUtils() { - // This utility class is not publicly instantiable. - } - - public static VibratorUtils getInstance(Context context) { - if (sInstance.mVibrator == null) { - sInstance.mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - } - return sInstance; - } - - public boolean hasVibrator() { - if (mVibrator == null) { - return false; - } - return mVibrator.hasVibrator(); - } - - public void vibrate(long milliseconds) { - if (mVibrator == null) { - return; - } - mVibrator.vibrate(milliseconds); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index f1a7e97e8..937d7ab34 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -56,6 +56,7 @@ public final class BinaryDictInputOutput { private static final int MAX_PASSES = 24; private static final int MAX_JUMPS = 12; + @UsedForTesting public interface FusionDictionaryBufferInterface { public int readUnsignedByte(); public int readUnsignedShort(); diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index f7cc69359..bfc275df5 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin.makedict; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Constants; import java.util.ArrayList; @@ -29,6 +30,7 @@ import java.util.LinkedList; /** * A dictionary that can fusion heads and tails of words for more compression. */ +@UsedForTesting public final class FusionDictionary implements Iterable<Word> { private static final boolean DBG = MakedictLog.DBG; |