Fix resetting the status of VoiceIME when the user is switching from one VoiceIME to another Voice IME

Change-Id: Ibbbe3ed6c4e2e7e3c1266daddf109742bd8d97b6
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 01e09fb..7a1ac2e 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -223,6 +223,9 @@
             }
             mMode = newMode;
         }
+
+        // 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) && mVoiceInput != null) {
@@ -233,17 +236,23 @@
                 updateShortcutIME();
                 mService.onRefreshKeyboard();
             }
-        } else if (isVoiceMode()) {
+        } else if (isVoiceMode() && mVoiceInput != null) {
+            if (VOICE_MODE.equals(oldMode)) {
+                mVoiceInput.reset();
+            }
             // If needsToShowWarningDialog is true, voice input need to show warning before
             // show recognition view.
             if (languageChanged || modeChanged
                     || VoiceIMEConnector.getInstance().needsToShowWarningDialog()) {
-                if (mVoiceInput != null) {
-                    triggerVoiceIME();
-                }
+                triggerVoiceIME();
             }
         } else {
             Log.w(TAG, "Unknown subtype mode: " + mMode);
+            if (VOICE_MODE.equals(oldMode) && mVoiceInput != 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.
+                mVoiceInput.reset();
+            }
         }
     }
 
diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/voice/VoiceInput.java
index 20211d4..2df9e85 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/voice/VoiceInput.java
@@ -130,19 +130,14 @@
 
     private int mState = DEFAULT;
     
-    private final static int MSG_CLOSE_ERROR_DIALOG = 1;
-
-    private final static int MSG_RESET = 2;
+    private final static int MSG_RESET = 1;
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            if (msg.what == MSG_RESET || msg.what == MSG_CLOSE_ERROR_DIALOG) {
+            if (msg.what == MSG_RESET) {
                 mState = DEFAULT;
                 mRecognitionView.finish();
-            }
-
-            if (msg.what == MSG_CLOSE_ERROR_DIALOG) {
                 mUiListener.onCancelVoice();
             }
         }
@@ -318,7 +313,14 @@
         if (DBG) {
             Log.d(TAG, "startListening: " + context);
         }
-        mState = DEFAULT;
+
+        if (mState != DEFAULT) {
+            Log.w(TAG, "startListening in the wrong status " + mState);
+        }
+
+        // If everything works ok, the voice input should be already in the correct state. As this
+        // class can be called by third-party, we call reset just to be on the safe side.
+        reset();
 
         Locale locale = Locale.getDefault();
         String localeString = locale.getLanguage() + "-" + locale.getCountry();
@@ -504,6 +506,21 @@
     }
 
     /**
+     * Reset the current voice recognition.
+     */
+    public void reset() {
+        if (mState != DEFAULT) {
+            mState = DEFAULT;
+
+            // Remove all pending tasks (e.g., timers to cancel voice input)
+            mHandler.removeMessages(MSG_RESET);
+
+            mSpeechRecognizer.cancel();
+            mRecognitionView.finish();
+        }
+    }
+
+    /**
      * Cancel in-progress speech recognition.
      */
     public void cancel() {
@@ -518,14 +535,9 @@
             mLogger.cancelDuringError();
             break;
         }
-        mState = DEFAULT;
 
-        // Remove all pending tasks (e.g., timers to cancel voice input)
-        mHandler.removeMessages(MSG_RESET);
-
-        mSpeechRecognizer.cancel();
+        reset();
         mUiListener.onCancelVoice();
-        mRecognitionView.finish();
     }
 
     private int getErrorStringId(int errorType, boolean endpointed) {
@@ -560,7 +572,7 @@
         mState = ERROR;
         mRecognitionView.showError(error);
         // Wait a couple seconds and then automatically dismiss message.
-        mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_CLOSE_ERROR_DIALOG), 2000);
+        mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_RESET), 2000);
     }
 
     private class ImeRecognitionListener implements RecognitionListener {