diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d624ae444..4989d8e3c 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.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.Debug; import android.os.Handler; +import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.os.Vibrator; @@ -48,6 +49,8 @@ import android.util.Printer; import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; @@ -458,7 +461,7 @@ public class LatinIME extends InputMethodService @Override public void onConfigurationChanged(Configuration conf) { mSubtypeSwitcher.onConfigurationChanged(conf); - onLanguageChanged(); + onKeyboardLanguageChanged(); updateAutoTextEnabled(); // If orientation changed while predicting, commit the change @@ -512,6 +515,7 @@ public class LatinIME extends InputMethodService public void onStartInputView(EditorInfo attribute, boolean restarting) { final KeyboardSwitcher switcher = mKeyboardSwitcher; LatinKeyboardView inputView = switcher.getInputView(); + // In landscape mode, this method gets called without the input view being created. if (inputView == null) { return; @@ -521,7 +525,7 @@ public class LatinIME extends InputMethodService if (mRefreshKeyboardRequired) { mRefreshKeyboardRequired = false; - onLanguageChanged(); + onKeyboardLanguageChanged(); } TextEntryState.newSession(this); @@ -629,6 +633,10 @@ public class LatinIME extends InputMethodService checkReCorrectionOnStart(); checkTutorial(attribute.privateImeOptions); inputView.setForeground(true); + + // TODO: Not to show keyboard if IME starts in Voice One shot mode. + mVoiceConnector.onStartInputView(); + if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } @@ -709,10 +717,8 @@ public class LatinIME extends InputMethodService // If the current selection in the text view changes, we should // clear whatever candidate text we have. if ((((mComposing.length() > 0 && mPredicting) - || mVoiceConnector.isVoiceInputHighlighted()) - && (newSelStart != candidatesEnd - || newSelEnd != candidatesEnd) - && mLastSelectionStart != newSelStart)) { + || mVoiceConnector.isVoiceInputHighlighted()) && (newSelStart != candidatesEnd + || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart)) { mComposing.setLength(0); mPredicting = false; mHandler.postUpdateSuggestions(); @@ -1418,8 +1424,17 @@ public class LatinIME extends InputMethodService public void switchToKeyboardView() { mHandler.post(new Runnable() { public void run() { - if (mKeyboardSwitcher.getInputView() != null) { - setInputView(mKeyboardSwitcher.getInputView()); + if (DEBUG) { + Log.d(TAG, "Switch to keyboard view."); + } + View v = mKeyboardSwitcher.getInputView(); + if (v != null) { + // Confirms that the keyboard view doesn't have parent view. + ViewParent p = v.getParent(); + if (p != null && p instanceof ViewGroup) { + ((ViewGroup)p).removeView(v); + } + setInputView(v); } setCandidatesViewShown(isCandidateStripVisible()); updateInputViewShown(); @@ -1844,7 +1859,7 @@ public class LatinIME extends InputMethodService // Notify that Language has been changed and toggleLanguage will update KeyboaredID according // to new Language. - private void onLanguageChanged() { + public void onKeyboardLanguageChanged() { toggleLanguage(true, true); } @@ -2226,6 +2241,5 @@ public class LatinIME extends InputMethodService @Override public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { SubtypeSwitcher.getInstance().updateSubtype(subtype); - onLanguageChanged(); } } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index fe629949c..df123c9f4 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -17,12 +17,12 @@ package com.android.inputmethod.latin; import com.android.inputmethod.voice.SettingsUtil; +import com.android.inputmethod.voice.VoiceInput; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; -import android.inputmethodservice.InputMethodService; import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Log; @@ -39,7 +39,7 @@ public class SubtypeSwitcher { // We may or may not draw the current language on space bar regardless of this flag. public static final boolean USE_SPACEBAR_LANGUAGE_SWITCHER = false; private static final boolean DBG = false; - private static final String TAG = "SubtypeSwitcher"; + private static final String TAG = "InputMethodSubtypeSwitcher"; private static final char LOCALE_SEPARATER = '_'; private static final String KEYBOARD_MODE = "keyboard"; @@ -48,7 +48,7 @@ public class SubtypeSwitcher { new TextUtils.SimpleStringSplitter(LOCALE_SEPARATER); private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); - private /* final */ InputMethodService mService; + private /* final */ LatinIME mService; private /* final */ InputMethodManager mImm; private /* final */ Resources mResources; private final ArrayList mEnabledKeyboardSubtypesOfCurrentInputMethod = @@ -62,6 +62,7 @@ public class SubtypeSwitcher { private String mInputLocaleStr; private String mMode; private List mAllEnabledSubtypesOfCurrentInputMethod; + private VoiceInput mVoiceInput; private boolean mNeedsToDisplayLanguage; private boolean mIsSystemLanguageSameAsInputLanguage; /*-----------------------------------------------------------*/ @@ -71,10 +72,7 @@ public class SubtypeSwitcher { } public static void init(LatinIME service) { - sInstance.mService = service; - sInstance.mResources = service.getResources(); - sInstance.mImm = (InputMethodManager) service.getSystemService( - Context.INPUT_METHOD_SERVICE); + sInstance.resetParams(service); if (USE_SPACEBAR_LANGUAGE_SWITCHER) { sInstance.initLanguageSwitcher(service); } @@ -85,6 +83,21 @@ public class SubtypeSwitcher { private SubtypeSwitcher() { } + private void resetParams(LatinIME service) { + mService = service; + mResources = service.getResources(); + mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE); + mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); + mEnabledLanguagesOfCurrentInputMethod.clear(); + mSystemLocale = null; + mInputLocale = null; + mInputLocaleStr = null; + mMode = null; + mAllEnabledSubtypesOfCurrentInputMethod = null; + // TODO: Voice input should be created here + mVoiceInput = null; + } + // Update all parameters stored in SubtypeSwitcher. // Only configuration changed event is allowed to call this because this is heavy. private void updateAllParameters() { @@ -126,17 +139,65 @@ public class SubtypeSwitcher { mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 && mIsSystemLanguageSameAsInputLanguage); if (foundCurrentSubtypeBecameDisabled) { + if (DBG) { + Log.w(TAG, "Last subtype was disabled. Update to the current one."); + } updateSubtype(mImm.getCurrentInputMethodSubtype()); } } // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. public void updateSubtype(InputMethodSubtype newSubtype) { - if (DBG) { - Log.w(TAG, "Update subtype to:" + newSubtype.getLocale() + "," + newSubtype.getMode()); + final String newLocale; + final String newMode; + if (newSubtype == null) { + // Normally, newSubtype shouldn't be null. But just in case if newSubtype was null, + // fallback to the default locale and mode. + Log.e(TAG, "Couldn't get the current subtype."); + newLocale = "en_US"; + newMode =KEYBOARD_MODE; + } else { + newLocale = newSubtype.getLocale(); + newMode = newSubtype.getMode(); + } + if (DBG) { + Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode + + ", from: " + mInputLocaleStr + ", " + mMode); + } + boolean languageChanged = false; + if (!newLocale.equals(mInputLocaleStr)) { + if (mInputLocaleStr != null) { + languageChanged = true; + } + updateInputLocale(newLocale); + } + boolean modeChanged = false; + String oldMode = mMode; + if (!newMode.equals(mMode)) { + if (mMode != null) { + modeChanged = true; + } + mMode = newMode; + } + if (isKeyboardMode()) { + if (modeChanged) { + if (VOICE_MODE.equals(oldMode) && mVoiceInput != null) { + mVoiceInput.cancel(); + } + } + if (languageChanged) { + mService.onKeyboardLanguageChanged(); + } + } else if (isVoiceMode()) { + if (languageChanged || modeChanged) { + if (mVoiceInput != null) { + // TODO: Call proper function to trigger VoiceIME + mService.onKey(LatinKeyboardView.KEYCODE_VOICE, null, 0, 0); + } + } + } else { + Log.w(TAG, "Unknown subtype mode: " + mMode); } - updateInputLocale(newSubtype.getLocale()); - mMode = newSubtype.getMode(); } // Update the current input locale from Locale string. @@ -269,6 +330,37 @@ public class SubtypeSwitcher { return oldLocale; } + public boolean isKeyboardMode() { + return KEYBOARD_MODE.equals(mMode); + } + + + /////////////////////////// + // Voice Input functions // + /////////////////////////// + + public boolean setVoiceInput(VoiceInput vi) { + if (mVoiceInput == null) { + // TODO: Remove requirements to construct KeyboardSwitcher + // when IME was enabled with Voice mode + mService.onKeyboardLanguageChanged(); + mVoiceInput = vi; + if (isVoiceMode() && mVoiceInput != null) { + if (DBG) { + Log.d(TAG, "Set and call voice input."); + } + // TODO: Call proper function to enable VoiceIME + mService.onKey(LatinKeyboardView.KEYCODE_VOICE, null, 0, 0); + return true; + } + } + return false; + } + + public boolean isVoiceMode() { + return VOICE_MODE.equals(mMode); + } + ////////////////////////////////////// // SpaceBar Language Switch support // ////////////////////////////////////// @@ -383,4 +475,4 @@ public class SubtypeSwitcher { mLanguageSwitcher.loadLocales(prefs); mLanguageSwitcher.setSystemLocale(conf.locale); } -} \ No newline at end of file +} diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java index 23b6752ef..629d4b45e 100644 --- a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java +++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java @@ -41,6 +41,7 @@ import android.view.WindowManager; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; import java.util.ArrayList; import java.util.HashMap; @@ -78,12 +79,14 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { private boolean mVoiceButtonOnPrimary; private boolean mVoiceInputHighlighted; + private InputMethodManager mImm; private LatinIME mContext; private AlertDialog mVoiceWarningDialog; private VoiceInput mVoiceInput; private final VoiceResults mVoiceResults = new VoiceResults(); private Hints mHints; private UIHandler mHandler; + private SubtypeSwitcher mSubtypeSwitcher; // For each word, a list of potential replacements, usually from voice. private final Map> mWordToSuggestions = new HashMap>(); @@ -96,6 +99,8 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { private void initInternal(LatinIME context, UIHandler h) { mContext = context; mHandler = h; + mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + mSubtypeSwitcher = SubtypeSwitcher.getInstance(); if (VOICE_INSTALLED) { mVoiceInput = new VoiceInput(context, this); mHints = new Hints(context, new Hints.Display() { @@ -376,7 +381,6 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { } } mContext.vibrate(); - mContext.switchToKeyboardView(); final List nBest = new ArrayList(); for (String c : mVoiceResults.candidates) { @@ -399,6 +403,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { mVoiceInputHighlighted = true; mWordToSuggestions.putAll(mVoiceResults.alternatives); + onCancelVoice(); } public void switchToRecognitionStatusView(final boolean configurationChanging) { @@ -410,7 +415,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { View v = mVoiceInput.getView(); ViewParent p = v.getParent(); if (p != null && p instanceof ViewGroup) { - ((ViewGroup)v.getParent()).removeView(v); + ((ViewGroup)p).removeView(v); } mContext.setInputView(v); mContext.updateInputViewShown(); @@ -499,6 +504,10 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { } } + public void onStartInputView() { + mSubtypeSwitcher.setVoiceInput(mVoiceInput); + } + public void onConfigurationChanged(boolean configurationChanging) { if (mRecognizing) { switchToRecognitionStatusView(configurationChanging); @@ -507,8 +516,21 @@ public class VoiceIMEConnector implements VoiceInput.UiListener { @Override public void onCancelVoice() { if (mRecognizing) { - mRecognizing = false; - mContext.switchToKeyboardView(); + if (mSubtypeSwitcher.isVoiceMode()) { + // If voice mode is being canceled within LatinIME (i.e. time-out or user + // cancellation etc.), onCancelVoice() will be called first. LatinIME thinks it's + // still in voice mode. LatinIME needs to call switchToLastInputMethod(). + // Note that onCancelVoice() will be called again from SubtypeSwitcher. + IBinder token = mContext.getWindow().getWindow().getAttributes().token; + mImm.switchToLastInputMethod(token); + } else if (mSubtypeSwitcher.isKeyboardMode()) { + // If voice mode is being canceled out of LatinIME (i.e. by user's IME switching or + // as a result of switchToLastInputMethod() etc.), + // onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know + // that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice(). + mRecognizing = false; + mContext.switchToKeyboardView(); + } } }