diff options
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
14 files changed, 247 insertions, 394 deletions
diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java index 9c5ccc76b..55664d411 100644 --- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java +++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java @@ -21,8 +21,8 @@ import android.media.AudioManager; import android.view.HapticFeedbackConstants; import android.view.View; -import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.latin.VibratorUtils; /** * This class gathers audio feedback and haptic feedback functions. @@ -33,13 +33,13 @@ import com.android.inputmethod.keyboard.Keyboard; public class AudioAndHapticFeedbackManager { final private SettingsValues mSettingsValues; final private AudioManager mAudioManager; - final private VibratorCompatWrapper mVibrator; + final private VibratorUtils mVibratorUtils; private boolean mSoundOn; public AudioAndHapticFeedbackManager(final LatinIME latinIme, final SettingsValues settingsValues) { mSettingsValues = settingsValues; - mVibrator = VibratorCompatWrapper.getInstance(latinIme); + mVibratorUtils = VibratorUtils.getInstance(latinIme); mAudioManager = (AudioManager) latinIme.getSystemService(Context.AUDIO_SERVICE); mSoundOn = reevaluateIfSoundIsOn(); } @@ -93,8 +93,8 @@ public class AudioAndHapticFeedbackManager { HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } - } else if (mVibrator != null) { - mVibrator.vibrate(mSettingsValues.mKeypressVibrationDuration); + } else if (mVibratorUtils != null) { + mVibratorUtils.vibrate(mSettingsValues.mKeypressVibrationDuration); } } diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index ef88f9906..38444a10c 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -16,6 +16,8 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + import android.text.TextUtils; import android.util.Log; @@ -30,8 +32,9 @@ public class AutoCorrection { // Purely static class: can't instantiate. } - public static CharSequence computeAutoCorrectionWord(HashMap<String, Dictionary> dictionaries, - WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] sortedScores, + public static CharSequence computeAutoCorrectionWord( + HashMap<String, Dictionary> dictionaries, + WordComposer wordComposer, ArrayList<SuggestedWordInfo> suggestions, CharSequence consideredWord, double autoCorrectionThreshold, CharSequence whitelistedWord) { if (hasAutoCorrectionForWhitelistedWord(whitelistedWord)) { @@ -40,8 +43,8 @@ public class AutoCorrection { dictionaries, wordComposer, suggestions, consideredWord)) { return consideredWord; } else if (hasAutoCorrectionForBinaryDictionary(wordComposer, suggestions, - sortedScores, consideredWord, autoCorrectionThreshold)) { - return suggestions.get(0); + consideredWord, autoCorrectionThreshold)) { + return suggestions.get(0).mWord; } return null; } @@ -89,22 +92,23 @@ public class AutoCorrection { private static boolean hasAutoCorrectionForConsideredWord( HashMap<String, Dictionary> dictionaries, WordComposer wordComposer, - ArrayList<CharSequence> suggestions, CharSequence consideredWord) { + ArrayList<SuggestedWordInfo> suggestions, CharSequence consideredWord) { if (TextUtils.isEmpty(consideredWord)) return false; return wordComposer.size() > 1 && suggestions.size() > 0 && !allowsToBeAutoCorrected(dictionaries, consideredWord, false); } private static boolean hasAutoCorrectionForBinaryDictionary(WordComposer wordComposer, - ArrayList<CharSequence> suggestions, int[] sortedScores, + ArrayList<SuggestedWordInfo> suggestions, CharSequence consideredWord, double autoCorrectionThreshold) { - if (wordComposer.size() > 1 && suggestions.size() > 0 && sortedScores.length > 0) { - final CharSequence autoCorrectionSuggestion = suggestions.get(0); - final int autoCorrectionSuggestionScore = sortedScores[0]; + if (wordComposer.size() > 1 && suggestions.size() > 0) { + final SuggestedWordInfo autoCorrectionSuggestion = suggestions.get(0); + //final int autoCorrectionSuggestionScore = sortedScores[0]; + final int autoCorrectionSuggestionScore = autoCorrectionSuggestion.mScore; // TODO: when the normalized score of the first suggestion is nearly equals to // the normalized score of the second suggestion, behave less aggressive. final double normalizedScore = BinaryDictionary.calcNormalizedScore( - consideredWord.toString(), autoCorrectionSuggestion.toString(), + consideredWord.toString(), autoCorrectionSuggestion.mWord.toString(), autoCorrectionSuggestionScore); if (DBG) { Log.d(TAG, "Normalized " + consideredWord + "," + autoCorrectionSuggestion + "," diff --git a/java/src/com/android/inputmethod/latin/EditingUtils.java b/java/src/com/android/inputmethod/latin/EditingUtils.java index 1e8ad1840..b3f613bae 100644 --- a/java/src/com/android/inputmethod/latin/EditingUtils.java +++ b/java/src/com/android/inputmethod/latin/EditingUtils.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2009 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 @@ -16,8 +16,6 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.compat.InputConnectionCompatUtils; - import android.text.TextUtils; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -246,7 +244,7 @@ public class EditingUtils { if (selStart == selEnd) { // There is just a cursor, so get the word at the cursor // getWordRangeAtCursor returns null if the connection is null - EditingUtils.Range range = getWordRangeAtCursor(ic, wordSeparators); + final EditingUtils.Range range = getWordRangeAtCursor(ic, wordSeparators); if (range != null && !TextUtils.isEmpty(range.mWord)) { return new SelectedWord(selStart - range.mCharsBefore, selEnd + range.mCharsAfter, range.mWord); @@ -254,20 +252,19 @@ public class EditingUtils { } else { if (null == ic) return null; // Is the previous character empty or a word separator? If not, return null. - CharSequence charsBefore = ic.getTextBeforeCursor(1, 0); + final CharSequence charsBefore = ic.getTextBeforeCursor(1, 0); if (!isWordBoundary(charsBefore, wordSeparators)) { return null; } // Is the next character empty or a word separator? If not, return null. - CharSequence charsAfter = ic.getTextAfterCursor(1, 0); + final CharSequence charsAfter = ic.getTextAfterCursor(1, 0); if (!isWordBoundary(charsAfter, wordSeparators)) { return null; } // Extract the selection alone - CharSequence touching = InputConnectionCompatUtils.getSelectedText( - ic, selStart, selEnd); + final CharSequence touching = ic.getSelectedText(0); if (TextUtils.isEmpty(touching)) return null; // Is any part of the selection a separator? If so, return null. final int length = touching.length(); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 098913bef..46d11fa37 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.content.Context; +import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.ProximityInfo; @@ -209,13 +210,19 @@ public class ExpandableDictionary extends Dictionary { @SuppressWarnings("unused") final ProximityInfo proximityInfo) { mInputLength = codes.size(); if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; + final int[] xCoordinates = codes.getXCoordinates(); + final int[] yCoordinates = codes.getYCoordinates(); // Cache the codes so that we don't have to lookup an array list for (int i = 0; i < mInputLength; i++) { // TODO: Calculate proximity info here. if (mCodes[i] == null || mCodes[i].length < 1) { - mCodes[i] = new int[1]; + mCodes[i] = new int[ProximityInfo.MAX_PROXIMITY_CHARS_SIZE]; } - mCodes[i][0] = codes.getCodeAt(i); + final int x = xCoordinates != null && i < xCoordinates.length ? + xCoordinates[i] : WordComposer.NOT_A_COORDINATE; + final int y = xCoordinates != null && i < yCoordinates.length ? + yCoordinates[i] : WordComposer.NOT_A_COORDINATE; + proximityInfo.fillArrayWithNearestKeyCodes(x, y, codes.getCodeAt(i), mCodes[i]); } mMaxDepth = mInputLength * 3; getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, callback); @@ -328,7 +335,7 @@ public class ExpandableDictionary extends Dictionary { for (int j = 0; j < alternativesSize; j++) { final int addedAttenuation = (j > 0 ? 1 : 2); final int currentChar = currentChars[j]; - if (currentChar == -1) { + if (currentChar == KeyDetector.NOT_A_CODE) { break; } if (currentChar == lowerC || currentChar == c) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index e6094d9e1..69780d0fd 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -46,22 +46,18 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewParent; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.ExtractedText; import android.view.inputmethod.InputConnection; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; import com.android.inputmethod.compat.CompatUtils; import com.android.inputmethod.compat.EditorInfoCompatUtils; -import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; -import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.SuggestionSpanUtils; -import com.android.inputmethod.deprecated.LanguageSwitcherProxy; -import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardId; @@ -193,7 +189,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private SharedPreferences mPrefs; /* package for tests */ final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; - private VoiceProxy mVoiceProxy; private boolean mShouldSwitchToLastSubtype = true; private UserDictionary mUserDictionary; @@ -234,7 +229,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { private static final int MSG_UPDATE_SHIFT_STATE = 1; - private static final int MSG_VOICE_RESULTS = 2; private static final int MSG_SPACE_TYPED = 4; private static final int MSG_SET_BIGRAM_PREDICTIONS = 5; private static final int MSG_PENDING_IMS_CALLBACK = 6; @@ -272,11 +266,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case MSG_SET_BIGRAM_PREDICTIONS: latinIme.updateBigramPredictions(); break; - case MSG_VOICE_RESULTS: - final Keyboard keyboard = switcher.getKeyboard(); - latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization() - || (keyboard != null && keyboard.isShiftedOrShiftLocked())); - break; } } @@ -311,10 +300,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar removeMessages(MSG_SET_BIGRAM_PREDICTIONS); } - public void updateVoiceResults() { - sendMessage(obtainMessage(MSG_VOICE_RESULTS)); - } - public void startDoubleSpacesTimer() { removeMessages(MSG_SPACE_TYPED); sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout); @@ -436,7 +421,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.init(this, prefs); } - LanguageSwitcherProxy.init(this, prefs); InputMethodManagerCompatWrapper.init(this); SubtypeSwitcher.init(this); KeyboardSwitcher.init(this, prefs); @@ -476,7 +460,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); registerReceiver(mReceiver, filter); - mVoiceProxy = VoiceProxy.init(this, prefs, mHandler); final IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); @@ -577,7 +560,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } unregisterReceiver(mReceiver); unregisterReceiver(mDictionaryPackInstallReceiver); - mVoiceProxy.destroy(); LatinImeLogger.commit(); LatinImeLogger.onDestroy(); super.onDestroy(); @@ -596,14 +578,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isShowingOptionDialog()) mOptionsDialog.dismiss(); } - - mVoiceProxy.startChangingConfiguration(); super.onConfigurationChanged(conf); - mVoiceProxy.onConfigurationChanged(conf); - mVoiceProxy.finishChangingConfiguration(); - - // This will work only when the subtype is not supported. - LanguageSwitcherProxy.onConfigurationChanged(conf); } @Override @@ -698,13 +673,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mSubtypeSwitcher.updateParametersOnStartInputView(); - // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to - // know now whether this is a password text field, because we need to know now whether we - // want to enable the voice button. - final int inputType = editorInfo.inputType; - mVoiceProxy.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType) - || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)); - // The EditorInfo might have a flag that affects fullscreen mode. // Note: This call should be done by InputMethodService? updateFullscreenMode(); @@ -726,9 +694,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) { mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); } - mVoiceProxy.loadSettings(editorInfo, mPrefs); - // This will work only when the subtype is not supported. - LanguageSwitcherProxy.loadSettings(); if (mSubtypeSwitcher.isKeyboardMode()) { switcher.loadKeyboard(editorInfo, mSettingsValues); @@ -746,8 +711,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mSettingsValues.mKeyPreviewPopupDismissDelay); inputView.setProximityCorrectionEnabled(true); - mVoiceProxy.onStartInputView(inputView.getWindowToken()); - if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } @@ -763,8 +726,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.commit(); - mVoiceProxy.flushVoiceInputLogs(); - KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.closing(); if (mUserHistoryDictionary != null) mUserHistoryDictionary.flushPendingWrites(); @@ -780,18 +741,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } @Override - public void onUpdateExtractedText(int token, ExtractedText text) { - super.onUpdateExtractedText(token, text); - mVoiceProxy.showPunctuationHintIfNecessary(); - } - - @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int composingSpanStart, int composingSpanEnd) { super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, composingSpanEnd); + if (ProductionFlag.IS_EXPERIMENTAL) { + if (ResearchLogger.UnsLogGroup.ON_UPDATE_SELECTION.isEnabled) { + final String s = "onUpdateSelection: oss=" + oldSelStart + + ", ose=" + oldSelEnd + + ", lss=" + mLastSelectionStart + + ", lse=" + mLastSelectionEnd + + ", nss=" + newSelStart + + ", nse=" + newSelEnd + + ", cs=" + composingSpanStart + + ", ce=" + composingSpanEnd; + ResearchLogger.logUnstructured(ResearchLogger.UnsLogGroup.ON_UPDATE_SELECTION, s); + } + } if (DEBUG) { Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart + ", ose=" + oldSelEnd @@ -803,8 +771,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar + ", ce=" + composingSpanEnd); } - mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart); - // TODO: refactor the following code to be less contrived. // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means // that the cursor is not at the end of the composing span, or there is a selection. @@ -892,7 +858,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mOptionsDialog.dismiss(); mOptionsDialog = null; } - mVoiceProxy.hideVoiceWindow(); super.hideWindow(); } @@ -1081,7 +1046,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic != null) { ic.finishComposingText(); } - mVoiceProxy.setVoiceInputHighlighted(false); } private void resetComposingState(final boolean alsoResetLastComposedWord) { @@ -1171,14 +1135,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void onSettingsKeyPressed() { if (isShowingOptionDialog()) return; - if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { - showSubtypeSelectorAndSettings(); - } else if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes( - false /* exclude aux subtypes */)) { - showOptionsMenu(); - } else { - launchSettings(); - } + showSubtypeSelectorAndSettings(); } // Virtual codes representing custom requests. These are used in onCustomRequest() below. @@ -1338,7 +1295,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onTextInput(CharSequence text) { - mVoiceProxy.commitVoiceInput(); final InputConnection ic = getCurrentInputConnection(); if (ic == null) return; ic.beginBatchEdit(); @@ -1383,7 +1339,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void handleBackspace(final int spaceState) { - if (mVoiceProxy.logAndRevertVoiceInput()) return; final InputConnection ic = getCurrentInputConnection(); if (ic == null) return; ic.beginBatchEdit(); @@ -1393,8 +1348,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" may not be null. private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) { - mVoiceProxy.handleBackspace(); - // In many cases, we may have to put the keyboard in auto-shift state again. mHandler.postUpdateShiftState(); @@ -1493,7 +1446,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void handleCharacter(final int primaryCode, final int x, final int y, final int spaceState) { - mVoiceProxy.handleCharacter(); final InputConnection ic = getCurrentInputConnection(); if (null != ic) ic.beginBatchEdit(); // TODO: if ic is null, does it make any sense to call this? @@ -1569,8 +1521,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Returns true if we did an autocorrection, false otherwise. private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { - mVoiceProxy.handleSeparator(); - // Should dismiss the "Touch again to save" message when handling separator if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { mHandler.cancelUpdateBigramPredictions(); @@ -1656,7 +1606,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void handleClose() { commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR); - mVoiceProxy.handleClose(); requestHideSelf(0); LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) @@ -1736,8 +1685,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void updateSuggestions() { // Check if we have a suggestion engine attached. - if ((mSuggest == null || !isSuggestionsRequested()) - && !mVoiceProxy.isVoiceInputHighlighted()) { + if ((mSuggest == null || !isSuggestionsRequested())) { if (mWordComposer.isComposingWord()) { Log.w(TAG, "Called updateSuggestions but suggestions were not requested!"); mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); @@ -1837,8 +1785,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!typedWord.equals(autoCorrection) && null != ic) { // This will make the correction flash for a short while as a visual clue // to the user that auto-correction happened. - InputConnectionCompatUtils.commitCorrection(ic, - mLastSelectionEnd - typedWord.length(), typedWord, autoCorrection); + ic.commitCorrection(new CorrectionInfo(mLastSelectionEnd - typedWord.length(), + typedWord, autoCorrection)); } } } @@ -1846,8 +1794,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void pickSuggestionManually(final int index, final CharSequence suggestion) { final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); - mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, - mSettingsValues.mWordSeparators); if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) { int firstChar = Character.codePointAt(suggestion, 0); @@ -1940,7 +1886,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final int separatorCode) { final InputConnection ic = getCurrentInputConnection(); if (ic != null) { - mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); if (mSettingsValues.mEnableSuggestionSpanInsertion) { final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( @@ -2193,11 +2138,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Notify that language or mode have been changed and toggleLanguage will update KeyboardID // according to new language or mode. public void onRefreshKeyboard() { - if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { - // Before Honeycomb, Voice IME is in LatinIME and it changes the current input view, - // so that we need to re-create the keyboard input view here. - setInputView(mKeyboardSwitcher.onCreateInputView()); - } // When the device locale is changed in SetupWizard etc., this method may get called via // onConfigurationChanged before SoftInputWindow is shown. if (mKeyboardSwitcher.getKeyboardView() != null) { @@ -2256,11 +2196,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } }; - // TODO: remove this method when VoiceProxy has been removed - public void vibrate() { - mFeedbackManager.vibrate(mKeyboardSwitcher.getKeyboardView()); - } - private void updateCorrectionMode() { // TODO: cleanup messy flags final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled @@ -2328,32 +2263,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar showOptionDialogInternal(builder.create()); } - private void showOptionsMenu() { - final CharSequence title = getString(R.string.english_ime_input_options); - final CharSequence[] items = new CharSequence[] { - getString(R.string.selectInputMethod), - getString(R.string.english_ime_settings), - }; - final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface di, int position) { - di.dismiss(); - switch (position) { - case 0: - mImm.showInputMethodPicker(); - break; - case 1: - launchSettings(); - break; - } - } - }; - final AlertDialog.Builder builder = new AlertDialog.Builder(this) - .setItems(items, listener) - .setTitle(title); - showOptionDialogInternal(builder.create()); - } - @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { super.dump(fd, fout, args); diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index 570333cb7..c5fb61f78 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -259,20 +259,33 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang write(LogGroup.STATE_CHANGE, subgroup + "\t" + details); } + public static enum UnsLogGroup { + // TODO: expand to include one flag per log point + // TODO: support selective enabling of flags + ON_UPDATE_SELECTION; + + public boolean isEnabled = true; + } + + public static void logUnstructured(UnsLogGroup logGroup, String details) { + } + private void write(final LogGroup logGroup, final String log) { + // TODO: rewrite in native for better performance mLoggingHandler.post(new Runnable() { @Override public void run() { final long currentTime = System.currentTimeMillis(); - mDate.setTime(currentTime); final long upTime = SystemClock.uptimeMillis(); - - final String printString = String.format("%s\t%d\t%s\t%s\n", - mDateFormat.format(mDate), upTime, logGroup.mLogString, log); + final StringBuilder builder = new StringBuilder(); + builder.append(currentTime); + builder.append('\t'); builder.append(upTime); + builder.append('\t'); builder.append(logGroup.mLogString); + builder.append('\t'); builder.append(log); if (LatinImeLogger.sDBG) { Log.d(TAG, "Write: " + '[' + logGroup.mLogString + ']' + log); } - if (mLogFileManager.append(printString)) { + if (mLogFileManager.append(builder.toString())) { // success } else { if (LatinImeLogger.sDBG) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 110264892..fd61292df 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -44,16 +44,14 @@ import android.widget.TextView; import com.android.inputmethod.compat.CompatUtils; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; -import com.android.inputmethod.compat.VibratorCompatWrapper; -import com.android.inputmethod.deprecated.VoiceProxy; +import com.android.inputmethod.latin.VibratorUtils; import com.android.inputmethod.latin.define.ProductionFlag; import com.android.inputmethodcommon.InputMethodSettingsActivity; import java.util.Locale; public class Settings extends InputMethodSettingsActivity - implements SharedPreferences.OnSharedPreferenceChangeListener, - DialogInterface.OnDismissListener, OnPreferenceClickListener { + implements SharedPreferences.OnSharedPreferenceChangeListener, OnPreferenceClickListener { private static final String TAG = Settings.class.getSimpleName(); public static final boolean ENABLE_EXPERIMENTAL_SETTINGS = false; @@ -92,9 +90,6 @@ public class Settings extends InputMethodSettingsActivity public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; public static final String PREF_DEBUG_SETTINGS = "debug_settings"; - // Dialog ids - private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; - private PreferenceScreen mInputLanguageSelection; private PreferenceScreen mKeypressVibrationDurationSettingsPref; private PreferenceScreen mKeypressSoundVolumeSettingsPref; @@ -113,7 +108,6 @@ public class Settings extends InputMethodSettingsActivity private TextView mKeypressVibrationDurationSettingsTextView; private TextView mKeypressSoundVolumeSettingsTextView; - private boolean mOkClicked = false; private String mVoiceModeOff; private void ensureConsistencyOfAutoCorrectionSettings() { @@ -185,7 +179,7 @@ public class Settings extends InputMethodSettingsActivity generalSettings.removePreference(mVoicePreference); } - if (!VibratorCompatWrapper.getInstance(context).hasVibrator()) { + if (!VibratorUtils.getInstance(context).hasVibrator()) { generalSettings.removePreference(findPreference(PREF_VIBRATE_ON)); } @@ -291,9 +285,7 @@ public class Settings extends InputMethodSettingsActivity public void onResume() { super.onResume(); final boolean isShortcutImeEnabled = SubtypeSwitcher.getInstance().isShortcutImeEnabled(); - if (isShortcutImeEnabled - || (VoiceProxy.VOICE_INSTALLED - && VoiceProxy.isRecognitionAvailable(getActivityInternal()))) { + if (isShortcutImeEnabled) { updateVoiceModeSummary(); } else { getPreferenceScreen().removePreference(mVoicePreference); @@ -312,13 +304,7 @@ public class Settings extends InputMethodSettingsActivity @Override public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { (new BackupManager(getActivityInternal())).dataChanged(); - // If turning on voice input, show dialog - if (key.equals(PREF_VOICE_MODE) && !mVoiceOn) { - if (!prefs.getString(PREF_VOICE_MODE, mVoiceModeOff) - .equals(mVoiceModeOff)) { - showVoiceConfirmation(); - } - } else if (key.equals(PREF_POPUP_ON)) { + if (key.equals(PREF_POPUP_ON)) { final ListPreference popupDismissDelay = (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); if (null != popupDismissDelay) { @@ -363,84 +349,16 @@ public class Settings extends InputMethodSettingsActivity lp.setSummary(lp.getEntries()[lp.findIndexOfValue(lp.getValue())]); } - private void showVoiceConfirmation() { - mOkClicked = false; - getActivityInternal().showDialog(VOICE_INPUT_CONFIRM_DIALOG); - // Make URL in the dialog message clickable - if (mDialog != null) { - TextView textView = (TextView) mDialog.findViewById(android.R.id.message); - if (textView != null) { - textView.setMovementMethod(LinkMovementMethod.getInstance()); - } - } - } - private void updateVoiceModeSummary() { mVoicePreference.setSummary( getResources().getStringArray(R.array.voice_input_modes_summary) [mVoicePreference.findIndexOfValue(mVoicePreference.getValue())]); } - @Override - protected Dialog onCreateDialog(int id) { - switch (id) { - case VOICE_INPUT_CONFIRM_DIALOG: - DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - if (whichButton == DialogInterface.BUTTON_NEGATIVE) { - mVoicePreference.setValue(mVoiceModeOff); - } else if (whichButton == DialogInterface.BUTTON_POSITIVE) { - mOkClicked = true; - } - } - }; - AlertDialog.Builder builder = new AlertDialog.Builder(getActivityInternal()) - .setTitle(R.string.voice_warning_title) - .setPositiveButton(android.R.string.ok, listener) - .setNegativeButton(android.R.string.cancel, listener); - - // Get the current list of supported locales and check the current locale against - // that list, to decide whether to put a warning that voice input will not work in - // the current language as part of the pop-up confirmation dialog. - boolean localeSupported = SubtypeSwitcher.isVoiceSupported( - this, Locale.getDefault().toString()); - - final CharSequence message; - if (localeSupported) { - message = TextUtils.concat( - getText(R.string.voice_warning_may_not_understand), "\n\n", - getText(R.string.voice_hint_dialog_message)); - } else { - message = TextUtils.concat( - getText(R.string.voice_warning_locale_not_supported), "\n\n", - getText(R.string.voice_warning_may_not_understand), "\n\n", - getText(R.string.voice_hint_dialog_message)); - } - builder.setMessage(message); - AlertDialog dialog = builder.create(); - mDialog = dialog; - dialog.setOnDismissListener(this); - return dialog; - default: - Log.e(TAG, "unknown dialog " + id); - return null; - } - } - - @Override - public void onDismiss(DialogInterface dialog) { - if (!mOkClicked) { - // This assumes that onPreferenceClick gets called first, and this if the user - // agreed after the warning, we set the mOkClicked value to true. - mVoicePreference.setValue(mVoiceModeOff); - } - } - private void refreshEnablingsOfKeypressSoundAndVibrationSettings( SharedPreferences sp, Resources res) { if (mKeypressVibrationDurationSettingsPref != null) { - final boolean hasVibrator = VibratorCompatWrapper.getInstance(this).hasVibrator(); + final boolean hasVibrator = VibratorUtils.getInstance(this).hasVibrator(); final boolean vibrateOn = hasVibrator && sp.getBoolean(Settings.PREF_VIBRATE_ON, res.getBoolean(R.bool.config_default_vibration_enabled)); mKeypressVibrationDurationSettingsPref.setEnabled(vibrateOn); @@ -503,7 +421,7 @@ public class Settings extends InputMethodSettingsActivity @Override public void onStopTrackingTouch(SeekBar arg0) { final int tempMs = arg0.getProgress(); - VibratorCompatWrapper.getInstance(context).vibrate(tempMs); + VibratorUtils.getInstance(context).vibrate(tempMs); } }); sb.setProgress(currentMs); diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index c1335fdfe..f76cc7e44 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -23,8 +23,9 @@ import android.util.Log; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.InputTypeCompatUtils; -import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.internal.KeySpecParser; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.VibratorUtils; import java.util.ArrayList; import java.util.Arrays; @@ -162,7 +163,7 @@ public class SettingsValues { if (puncs != null) { for (final String puncSpec : puncs) { puncList.add(new SuggestedWords.SuggestedWordInfo( - KeySpecParser.getLabel(puncSpec))); + KeySpecParser.getLabel(puncSpec), SuggestedWordInfo.MAX_SCORE)); } } return new SuggestedWords(puncList, @@ -187,7 +188,7 @@ public class SettingsValues { private static boolean isVibrateOn(final Context context, final SharedPreferences prefs, final Resources res) { - final boolean hasVibrator = VibratorCompatWrapper.getInstance(context).hasVibrator(); + final boolean hasVibrator = VibratorUtils.getInstance(context).hasVibrator(); return hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, res.getBoolean(R.bool.config_default_vibration_enabled)); } diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java index 917521c40..66c13bd2e 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java +++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java @@ -36,10 +36,16 @@ public class SubtypeLocale { } public static String getFullDisplayName(Locale locale) { - String localeCode = locale.toString(); + final String localeCode = locale.toString(); for (int index = 0; index < sExceptionKeys.length; index++) { - if (sExceptionKeys[index].equals(localeCode)) - return sExceptionValues[index]; + if (sExceptionKeys[index].equals(localeCode)) { + final String value = sExceptionValues[index]; + if (value.indexOf("%s") >= 0) { + final String languageName = locale.getDisplayLanguage(locale); + return String.format(value, languageName); + } + return value; + } } return locale.getDisplayName(locale); } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 3524c72f6..de2e8be3d 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -33,7 +33,6 @@ import android.util.Log; import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; -import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.KeyboardSwitcher; import java.util.ArrayList; @@ -76,7 +75,6 @@ public class SubtypeSwitcher { private Locale mSystemLocale; private Locale mInputLocale; private String mInputLocaleStr; - private VoiceProxy.VoiceInputWrapper mVoiceInputWrapper; /*-----------------------------------------------------------*/ private boolean mIsNetworkConnected; @@ -108,7 +106,6 @@ public class SubtypeSwitcher { mInputLocaleStr = null; mCurrentSubtype = null; mAllEnabledSubtypesOfCurrentInputMethod = null; - mVoiceInputWrapper = null; final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); mIsNetworkConnected = (info != null && info.isConnected()); @@ -234,34 +231,12 @@ public class SubtypeSwitcher { } mCurrentSubtype = newSubtype; - // If the old mode is voice input, we need to reset or cancel its status. - // We cancel its status when we change mode, while we reset otherwise. if (isKeyboardMode()) { - if (modeChanged) { - if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) { - mVoiceInputWrapper.cancel(); - } - } if (modeChanged || languageChanged) { updateShortcutIME(); mService.onRefreshKeyboard(); } - } else if (isVoiceMode() && mVoiceInputWrapper != null) { - if (VOICE_MODE.equals(oldMode)) { - mVoiceInputWrapper.reset(); - } - // If needsToShowWarningDialog is true, voice input need to show warning before - // show recognition view. - if (languageChanged || modeChanged - || VoiceProxy.getInstance().needsToShowWarningDialog()) { - triggerVoiceIME(); - } } else { - if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) { - // We need to reset the voice input to release the resources and to reset its status - // as it is not the current input mode. - mVoiceInputWrapper.reset(); - } final String packageName = mService.getPackageName(); int version = -1; try { @@ -270,7 +245,7 @@ public class SubtypeSwitcher { } catch (NameNotFoundException e) { } Log.w(TAG, "Unknown subtype mode: " + newMode + "," + version + ", " + packageName - + ", " + mVoiceInputWrapper + ". IME is already changed to other IME."); + + ". IME is already changed to other IME."); if (newSubtype != null) { Log.w(TAG, "Subtype mode:" + newSubtype.getMode()); Log.w(TAG, "Subtype locale:" + newSubtype.getLocale()); @@ -477,40 +452,6 @@ public class SubtypeSwitcher { return KEYBOARD_MODE.equals(getCurrentSubtypeMode()); } - - /////////////////////////// - // Voice Input functions // - /////////////////////////// - - public boolean setVoiceInputWrapper(VoiceProxy.VoiceInputWrapper vi) { - if (mVoiceInputWrapper == null && vi != null) { - mVoiceInputWrapper = vi; - if (isVoiceMode()) { - if (DBG) { - Log.d(TAG, "Set and call voice input.: " + getInputLocaleStr()); - } - triggerVoiceIME(); - return true; - } - } - return false; - } - - public boolean isVoiceMode() { - return null == mCurrentSubtype ? false : VOICE_MODE.equals(getCurrentSubtypeMode()); - } - - public boolean isDummyVoiceMode() { - return mCurrentSubtype != null && mCurrentSubtype.getOriginalObject() == null - && VOICE_MODE.equals(getCurrentSubtypeMode()); - } - - private void triggerVoiceIME() { - if (!mService.isInputViewShown()) return; - VoiceProxy.getInstance().startListening(false, - KeyboardSwitcher.getInstance().getKeyboardView().getWindowToken()); - } - public String getInputLanguageName() { return StringUtils.getDisplayLanguage(getInputLocale()); } @@ -537,18 +478,4 @@ public class SubtypeSwitcher { public String getCurrentSubtypeMode() { return null != mCurrentSubtype ? mCurrentSubtype.getMode() : KEYBOARD_MODE; } - - - public static boolean isVoiceSupported(Context context, String locale) { - // Get the current list of supported locales and check the current locale against that - // list. We cache this value so as not to check it every time the user starts a voice - // input. Because this method is called by onStartInputView, this should mean that as - // long as the locale doesn't change while the user is keeping the IME open, the - // value should never be stale. - String supportedLocalesString = VoiceProxy.getSupportedLocalesString( - context.getContentResolver()); - List<String> voiceInputSupportedLocales = Arrays.asList( - supportedLocalesString.split("\\s+")); - return voiceInputSupportedLocales.contains(locale); - } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 9ae2506f4..b31f3019c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -26,7 +26,6 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; @@ -93,11 +92,9 @@ public class Suggest implements Dictionary.WordCallback { private static final int PREF_MAX_BIGRAMS = 60; private double mAutoCorrectionThreshold; - private int[] mScores = new int[mPrefMaxSuggestions]; - private int[] mBigramScores = new int[PREF_MAX_BIGRAMS]; - private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>(); - private ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>(); + private ArrayList<SuggestedWordInfo> mSuggestions = new ArrayList<SuggestedWordInfo>(); + private ArrayList<SuggestedWordInfo> mBigramSuggestions = new ArrayList<SuggestedWordInfo>(); private CharSequence mConsideredWord; // TODO: Remove these member variables by passing more context to addWord() callback method @@ -230,10 +227,8 @@ public class Suggest implements Dictionary.WordCallback { return sb; } - protected void addBigramToSuggestions(CharSequence bigram) { - final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); - sb.append(bigram); - mSuggestions.add(sb); + protected void addBigramToSuggestions(SuggestedWordInfo bigram) { + mSuggestions.add(bigram); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -242,15 +237,13 @@ public class Suggest implements Dictionary.WordCallback { mIsFirstCharCapitalized = false; mIsAllUpperCase = false; mTrailingSingleQuotesCount = 0; - mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions); - Arrays.fill(mScores, 0); + mSuggestions = new ArrayList<SuggestedWordInfo>(mPrefMaxSuggestions); // Treating USER_TYPED as UNIGRAM suggestion for logging now. LatinImeLogger.onAddSuggestedWord("", Suggest.DIC_USER_TYPED, Dictionary.UNIGRAM); mConsideredWord = ""; - Arrays.fill(mBigramScores, 0); - mBigramSuggestions = new ArrayList<CharSequence>(PREF_MAX_BIGRAMS); + mBigramSuggestions = new ArrayList<SuggestedWordInfo>(PREF_MAX_BIGRAMS); CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); if (mMainDict != null && mMainDict.isValidWord(lowerPrevWord)) { @@ -265,9 +258,9 @@ public class Suggest implements Dictionary.WordCallback { addBigramToSuggestions(mBigramSuggestions.get(i)); } - StringUtils.removeDupes(mSuggestions); + SuggestedWordInfo.removeDups(mSuggestions); - return new SuggestedWords(SuggestedWords.getFromCharSequenceList(mSuggestions), + return new SuggestedWords(mSuggestions, false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, false /* allowsToBeAutoCorrected */, @@ -283,8 +276,7 @@ public class Suggest implements Dictionary.WordCallback { mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized(); mIsAllUpperCase = wordComposer.isAllUpperCase(); mTrailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); - mSuggestions = new ArrayList<CharSequence>(mPrefMaxSuggestions); - Arrays.fill(mScores, 0); + mSuggestions = new ArrayList<SuggestedWordInfo>(mPrefMaxSuggestions); final String typedWord = wordComposer.getTypedWord(); final String consideredWord = mTrailingSingleQuotesCount > 0 @@ -296,8 +288,7 @@ public class Suggest implements Dictionary.WordCallback { if (wordComposer.size() <= 1 && (correctionMode == CORRECTION_FULL_BIGRAM)) { // At first character typed, search only the bigrams - Arrays.fill(mBigramScores, 0); - mBigramSuggestions = new ArrayList<CharSequence>(PREF_MAX_BIGRAMS); + mBigramSuggestions = new ArrayList<SuggestedWordInfo>(PREF_MAX_BIGRAMS); if (!TextUtils.isEmpty(prevWordForBigram)) { CharSequence lowerPrevWord = prevWordForBigram.toString().toLowerCase(); @@ -317,12 +308,14 @@ public class Suggest implements Dictionary.WordCallback { // Word entered: return only bigrams that match the first char of the typed word final char currentChar = consideredWord.charAt(0); // TODO: Must pay attention to locale when changing case. + // TODO: Use codepoint instead of char final char currentCharUpper = Character.toUpperCase(currentChar); int count = 0; final int bigramSuggestionSize = mBigramSuggestions.size(); for (int i = 0; i < bigramSuggestionSize; i++) { - final CharSequence bigramSuggestion = mBigramSuggestions.get(i); - final char bigramSuggestionFirstChar = bigramSuggestion.charAt(0); + final SuggestedWordInfo bigramSuggestion = mBigramSuggestions.get(i); + final char bigramSuggestionFirstChar = + (char)bigramSuggestion.codePointAt(0); if (bigramSuggestionFirstChar == currentChar || bigramSuggestionFirstChar == currentCharUpper) { addBigramToSuggestions(bigramSuggestion); @@ -359,7 +352,7 @@ public class Suggest implements Dictionary.WordCallback { if (CORRECTION_FULL == correctionMode || CORRECTION_FULL_BIGRAM == correctionMode) { final CharSequence autoCorrection = AutoCorrection.computeAutoCorrectionWord(mUnigramDictionaries, wordComposer, - mSuggestions, mScores, consideredWord, mAutoCorrectionThreshold, + mSuggestions, consideredWord, mAutoCorrectionThreshold, whitelistedWord); hasAutoCorrection = (null != autoCorrection); } else { @@ -372,20 +365,22 @@ public class Suggest implements Dictionary.WordCallback { for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); } - mSuggestions.add(0, sb.toString()); + mSuggestions.add(0, new SuggestedWordInfo( + sb.toString(), SuggestedWordInfo.MAX_SCORE)); } else { - mSuggestions.add(0, whitelistedWord); + mSuggestions.add(0, new SuggestedWordInfo( + whitelistedWord, SuggestedWordInfo.MAX_SCORE)); } } - mSuggestions.add(0, typedWord); - StringUtils.removeDupes(mSuggestions); + mSuggestions.add(0, new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE)); + SuggestedWordInfo.removeDups(mSuggestions); final ArrayList<SuggestedWordInfo> suggestionsList; if (DBG) { - suggestionsList = getSuggestionsInfoListWithDebugInfo(typedWord, mSuggestions, mScores); + suggestionsList = getSuggestionsInfoListWithDebugInfo(typedWord, mSuggestions); } else { - suggestionsList = SuggestedWords.getFromCharSequenceList(mSuggestions); + suggestionsList = mSuggestions; } // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" @@ -415,50 +410,45 @@ public class Suggest implements Dictionary.WordCallback { false /* isObsoleteSuggestions */); } - // This assumes the scores[] array is at least as long as suggestions.size() - 1. private static ArrayList<SuggestedWordInfo> getSuggestionsInfoListWithDebugInfo( - final String typedWord, final ArrayList<CharSequence> suggestions, final int[] scores) { - // TODO: this doesn't take into account the fact that removing dupes from mSuggestions - // may have made mScores[] and mSuggestions out of sync. - final CharSequence autoCorrectionSuggestion = suggestions.get(0); + final String typedWord, final ArrayList<SuggestedWordInfo> suggestions) { + final SuggestedWordInfo typedWordInfo = suggestions.get(0); + typedWordInfo.setDebugString("+"); double normalizedScore = BinaryDictionary.calcNormalizedScore( - typedWord, autoCorrectionSuggestion.toString(), scores[0]); + typedWord, typedWordInfo.toString(), typedWordInfo.mScore); final int suggestionsSize = suggestions.size(); final ArrayList<SuggestedWordInfo> suggestionsList = new ArrayList<SuggestedWordInfo>(suggestionsSize); - suggestionsList.add(new SuggestedWordInfo(autoCorrectionSuggestion, "+")); + suggestionsList.add(typedWordInfo); // Note: i here is the index in mScores[], but the index in mSuggestions is one more // than i because we added the typed word to mSuggestions without touching mScores. - for (int i = 0; i < scores.length && i < suggestionsSize - 1; ++i) { + for (int i = 0; i < suggestionsSize - 1; ++i) { + final SuggestedWordInfo cur = suggestions.get(i + 1); final String scoreInfoString; if (normalizedScore > 0) { - scoreInfoString = String.format("%d (%4.2f)", scores[i], normalizedScore); + scoreInfoString = String.format("%d (%4.2f)", cur.mScore, normalizedScore); normalizedScore = 0.0; } else { - scoreInfoString = Integer.toString(scores[i]); + scoreInfoString = Integer.toString(cur.mScore); } - suggestionsList.add(new SuggestedWordInfo(suggestions.get(i + 1), scoreInfoString)); - } - for (int i = scores.length; i < suggestionsSize; ++i) { - suggestionsList.add(new SuggestedWordInfo(suggestions.get(i), "--")); + cur.setDebugString(scoreInfoString); + suggestionsList.add(cur); } return suggestionsList; } + // TODO: Use codepoint instead of char @Override public boolean addWord(final char[] word, final int offset, final int length, int score, final int dicTypeId, final int dataType) { int dataTypeForLog = dataType; - final ArrayList<CharSequence> suggestions; - final int[] sortedScores; + final ArrayList<SuggestedWordInfo> suggestions; final int prefMaxSuggestions; if (dataType == Dictionary.BIGRAM) { suggestions = mBigramSuggestions; - sortedScores = mBigramScores; prefMaxSuggestions = PREF_MAX_BIGRAMS; } else { suggestions = mSuggestions; - sortedScores = mScores; prefMaxSuggestions = mPrefMaxSuggestions; } @@ -469,13 +459,13 @@ public class Suggest implements Dictionary.WordCallback { // TODO: remove this surrounding if clause and move this logic to // getSuggestedWordBuilder. if (suggestions.size() > 0) { - final String currentHighestWord = suggestions.get(0).toString(); + final SuggestedWordInfo currentHighestWord = suggestions.get(0); // If the current highest word is also equal to typed word, we need to compare // frequency to determine the insertion position. This does not ensure strictly // correct ordering, but ensures the top score is on top which is enough for // removing duplicates correctly. - if (StringUtils.equalsIgnoreCase(currentHighestWord, word, offset, length) - && score <= sortedScores[0]) { + if (StringUtils.equalsIgnoreCase(currentHighestWord.mWord, word, offset, length) + && score <= currentHighestWord.mScore) { pos = 1; } } @@ -486,7 +476,7 @@ public class Suggest implements Dictionary.WordCallback { if(bigramSuggestion >= 0) { dataTypeForLog = Dictionary.BIGRAM; // turn freq from bigram into multiplier specified above - double multiplier = (((double) mBigramScores[bigramSuggestion]) + double multiplier = (((double) mBigramSuggestions.get(bigramSuggestion).mScore) / MAXIMUM_BIGRAM_FREQUENCY) * (BIGRAM_MULTIPLIER_MAX - BIGRAM_MULTIPLIER_MIN) + BIGRAM_MULTIPLIER_MIN; @@ -500,10 +490,12 @@ public class Suggest implements Dictionary.WordCallback { } // Check the last one's score and bail - if (sortedScores[prefMaxSuggestions - 1] >= score) return true; - while (pos < prefMaxSuggestions) { - if (sortedScores[pos] < score - || (sortedScores[pos] == score && length < suggestions.get(pos).length())) { + if (suggestions.size() >= prefMaxSuggestions + && suggestions.get(prefMaxSuggestions - 1).mScore >= score) return true; + while (pos < suggestions.size()) { + final int curScore = suggestions.get(pos).mScore; + if (curScore < score + || (curScore == score && length < suggestions.get(pos).codePointCount())) { break; } pos++; @@ -513,8 +505,6 @@ public class Suggest implements Dictionary.WordCallback { return true; } - System.arraycopy(sortedScores, pos, sortedScores, pos + 1, prefMaxSuggestions - pos - 1); - sortedScores[pos] = score; final StringBuilder sb = new StringBuilder(getApproxMaxWordLength()); // TODO: Must pay attention to locale when changing case. if (mIsAllUpperCase) { @@ -530,7 +520,7 @@ public class Suggest implements Dictionary.WordCallback { for (int i = mTrailingSingleQuotesCount - 1; i >= 0; --i) { sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE); } - suggestions.add(pos, sb); + suggestions.add(pos, new SuggestedWordInfo(sb, score)); if (suggestions.size() > prefMaxSuggestions) { suggestions.remove(prefMaxSuggestions); } else { @@ -539,15 +529,16 @@ public class Suggest implements Dictionary.WordCallback { return true; } + // TODO: Use codepoint instead of char private int searchBigramSuggestion(final char[] word, final int offset, final int length) { // TODO This is almost O(n^2). Might need fix. // search whether the word appeared in bigram data int bigramSuggestSize = mBigramSuggestions.size(); for (int i = 0; i < bigramSuggestSize; i++) { - if (mBigramSuggestions.get(i).length() == length) { + if (mBigramSuggestions.get(i).codePointCount() == length) { boolean chk = true; for (int j = 0; j < length; j++) { - if (mBigramSuggestions.get(i).charAt(j) != word[offset+j]) { + if (mBigramSuggestions.get(i).codePointAt(j) != word[offset+j]) { chk = false; break; } diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index ef8e58e0c..0c0ce182f 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -56,6 +56,10 @@ public class SuggestedWords { return mSuggestedWordInfoList.get(pos).mWord; } + public SuggestedWordInfo getWordInfo(int pos) { + return mSuggestedWordInfoList.get(pos); + } + public SuggestedWordInfo getInfo(int pos) { return mSuggestedWordInfoList.get(pos); } @@ -79,20 +83,12 @@ public class SuggestedWords { + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray()); } - public static ArrayList<SuggestedWordInfo> getFromCharSequenceList( - final ArrayList<CharSequence> wordList) { - final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); - for (CharSequence word : wordList) { - if (null != word) result.add(new SuggestedWordInfo(word)); - } - return result; - } - public static ArrayList<SuggestedWordInfo> getFromApplicationSpecifiedCompletions( final CompletionInfo[] infos) { final ArrayList<SuggestedWordInfo> result = new ArrayList<SuggestedWordInfo>(); for (CompletionInfo info : infos) { - if (null != info) result.add(new SuggestedWordInfo(info.getText())); + if (null != info) result.add(new SuggestedWordInfo(info.getText(), + SuggestedWordInfo.MAX_SCORE)); } return result; } @@ -103,14 +99,15 @@ public class SuggestedWords { final CharSequence typedWord, final SuggestedWords previousSuggestions) { final ArrayList<SuggestedWordInfo> suggestionsList = new ArrayList<SuggestedWordInfo>(); final HashSet<String> alreadySeen = new HashSet<String>(); - suggestionsList.add(new SuggestedWordInfo(typedWord)); + suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE)); alreadySeen.add(typedWord.toString()); final int previousSize = previousSuggestions.size(); for (int pos = 1; pos < previousSize; pos++) { - final String prevWord = previousSuggestions.getWord(pos).toString(); + final SuggestedWordInfo prevWordInfo = previousSuggestions.getWordInfo(pos); + final String prevWord = prevWordInfo.mWord.toString(); // Filter out duplicate suggestion. if (!alreadySeen.contains(prevWord)) { - suggestionsList.add(new SuggestedWordInfo(prevWord)); + suggestionsList.add(prevWordInfo); alreadySeen.add(prevWord); } } @@ -118,30 +115,64 @@ public class SuggestedWords { } public static class SuggestedWordInfo { + public static final int MAX_SCORE = Integer.MAX_VALUE; + private final String mWordStr; public final CharSequence mWord; - private final String mDebugString; + public final int mScore; + public final int mCodePointCount; + private String mDebugString = ""; - public SuggestedWordInfo(final CharSequence word) { + public SuggestedWordInfo(final CharSequence word, final int score) { + mWordStr = word.toString(); mWord = word; - mDebugString = ""; + mScore = score; + mCodePointCount = mWordStr.codePointCount(0, mWordStr.length()); } - public SuggestedWordInfo(final CharSequence word, final String debugString) { - mWord = word; - if (null == debugString) throw new NullPointerException(""); - mDebugString = debugString; + + public void setDebugString(String str) { + if (null == str) throw new NullPointerException("Debug info is null"); + mDebugString = str; } public String getDebugString() { return mDebugString; } + public int codePointCount() { + return mCodePointCount; + } + + public int codePointAt(int i) { + return mWordStr.codePointAt(i); + } + @Override public String toString() { if (TextUtils.isEmpty(mDebugString)) { - return mWord.toString(); + return mWordStr; } else { - return mWord.toString() + " (" + mDebugString.toString() + ")"; + return mWordStr + " (" + mDebugString.toString() + ")"; + } + } + + // TODO: Consolidate this method and StringUtils.removeDupes() in the future. + public static void removeDups(ArrayList<SuggestedWordInfo> candidates) { + if (candidates.size() <= 1) { + return; + } + int i = 1; + while(i < candidates.size()) { + final SuggestedWordInfo cur = candidates.get(i); + for (int j = 0; j < i; ++j) { + final SuggestedWordInfo previous = candidates.get(j); + if (TextUtils.equals(cur.mWord, previous.mWord)) { + candidates.remove(cur.mScore < previous.mScore ? i : j); + --i; + break; + } + } + ++i; } } } diff --git a/java/src/com/android/inputmethod/latin/VibratorUtils.java b/java/src/com/android/inputmethod/latin/VibratorUtils.java new file mode 100644 index 000000000..33ffdd9c9 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/VibratorUtils.java @@ -0,0 +1,50 @@ +/* + * 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 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/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 5a173857e..7b13e40c2 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -26,7 +26,6 @@ import android.util.Log; import android.view.textservice.SuggestionsInfo; import android.view.textservice.TextInfo; -import com.android.inputmethod.compat.ArraysCompatUtils; import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.BinaryDictionary; @@ -237,7 +236,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService @Override synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, int dicTypeId, int dataType) { - final int positionIndex = ArraysCompatUtils.binarySearch(mScores, 0, mLength, score); + final int positionIndex = Arrays.binarySearch(mScores, 0, mLength, score); // binarySearch returns the index if the element exists, and -<insertion index> - 1 // if it doesn't. See documentation for binarySearch. final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1; |