/** Runs the recognition loop. */
  private void recognizeThread() {
    if (mAlive) {
      return;
    }

    mAlive = true;

    if (Config.DEBUG) {
      Log.e(TAG, "Started recognition thread");
    }

    InputStream mic = null;
    boolean recognizerStarted = false;

    // Possible results...
    String error = null;
    TreeSet<GrammarResult> results = null;
    boolean failure = false;

    try {
      mic = new MicrophoneInputStream(SAMPLE_RATE, SAMPLE_RATE * 15);

      mSrec.start();
      recognizerStarted = true;

      while (mAlive) {
        if (Thread.interrupted()) {
          throw new InterruptedException();
        }

        int event = mSrec.advance();
        if (Config.DEBUG
            && event != Recognizer.EVENT_INCOMPLETE
            && event != Recognizer.EVENT_NEED_MORE_AUDIO) {
          Log.e(TAG, "event=" + event);
        }

        switch (event) {
          case Recognizer.EVENT_INCOMPLETE:
          case Recognizer.EVENT_STARTED:
          case Recognizer.EVENT_START_OF_VOICING:
          case Recognizer.EVENT_END_OF_VOICING:
            break;
          case Recognizer.EVENT_START_OF_UTTERANCE_TIMEOUT:
            if (Config.DEBUG) {
              Log.e(TAG, "Didn't hear anything, restarting");
            }
            mSrec.stop();
            mSrec.start();
            break;
          case Recognizer.EVENT_NO_MATCH:
            if (Config.DEBUG) {
              Log.e(TAG, "No match, return not recognized");
            }
            mAlive = false;
            failure = true;
            break;
          case Recognizer.EVENT_RECOGNITION_RESULT:
            if (Config.DEBUG) {
              Log.e(TAG, "Recognized something, return it");
            }
            mAlive = false;
            results = getRecognitionResults();
            break;
          case Recognizer.EVENT_NEED_MORE_AUDIO:
            mSrec.putAudio(mic);
            break;
          default:
            if (Config.DEBUG) {
              Log.e(TAG, "Received invalid event=" + event);
            }
            mAlive = false;
            error = Recognizer.eventToString(event);
            break;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();

      mListener.onRecognitionError(e.toString());
    } catch (InterruptedException e) {
      // do nothing
    } finally {
      if (mSrec != null && recognizerStarted) {
        mSrec.stop();
      }

      try {
        if (mic != null) {
          mic.close();
        }
      } catch (IOException ex) {
        ex.printStackTrace();
      } finally {
        mic = null;
      }

      // Wait until the very end to send results, otherwise we might
      // overlap and crash the AudioFlinger permanently!
      if (mListener != null) {
        if (error != null) {
          mListener.onRecognitionError(error);
        } else if (results != null) {
          mListener.onRecognitionSuccess(results);
        } else if (failure) {
          mListener.onRecognitionFailure();
        }
      }
    }
  }