/**
   * Note: we enforce that this method is called on the UI thread, so we can call
   * nativeVoicesChanged directly.
   */
  private void initialize() {
    assert mNativeTtsPlatformImplAndroid != 0;

    // Note: Android supports multiple speech engines, but querying the
    // metadata about all of them is expensive. So we deliberately only
    // support the default speech engine, and expose the different
    // supported languages for the default engine as different voices.
    String defaultEngineName = mTextToSpeech.getDefaultEngine();
    String engineLabel = defaultEngineName;
    for (TextToSpeech.EngineInfo info : mTextToSpeech.getEngines()) {
      if (info.name.equals(defaultEngineName)) engineLabel = info.label;
    }
    Locale[] locales = Locale.getAvailableLocales();
    mVoices = new ArrayList<TtsVoice>();
    for (int i = 0; i < locales.length; ++i) {
      if (!locales[i].getVariant().isEmpty()) continue;
      if (mTextToSpeech.isLanguageAvailable(locales[i]) > 0) {
        String name = locales[i].getDisplayLanguage();
        if (!locales[i].getCountry().isEmpty()) {
          name += " " + locales[i].getDisplayCountry();
        }
        TtsVoice voice = new TtsVoice(name, locales[i].toString());
        mVoices.add(voice);
      }
    }

    mInitialized = true;
    nativeVoicesChanged(mNativeTtsPlatformImplAndroid);
  }
  protected void execute(Command cmd) {
    Log.i("TTS: " + cmd.getOriginalCommand());

    if (isMatchingCmd(cmd, "tts")) {
      if (mTtsAvailable) {
        mTts.speak(cmd.getAllArg1(), TextToSpeech.QUEUE_ADD, null);
      } else {
        send(R.string.chat_tts_installation);
        Intent intent = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        sContext.startActivity(intent);
      }
    } else if (isMatchingCmd(cmd, "tts-engine-list")) {
      if (Build.VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
        send(R.string.android_version_incompatible, "ICE CREAM SANDWICH");
      } else {
        StringBuilder sb = new StringBuilder(getString(R.string.chat_tts_engines));
        for (EngineInfo engine : mTts.getEngines()) {
          sb.append(engine.label).append(" - ").append(engine.name).append("\n");
        }
        send(sb.substring(0, Math.max(0, sb.length() - 1)));
      }
    } else if (isMatchingCmd(cmd, "tts-lang-list")) {
      StringBuilder sb = new StringBuilder(getString(R.string.chat_tts_languages));
      for (Locale locale : Locale.getAvailableLocales()) {
        switch (mTts.isLanguageAvailable(locale)) {
          case TextToSpeech.LANG_AVAILABLE:
            sb.append(locale.getDisplayLanguage());
            if (locale.getDisplayCountry() != null && locale.getDisplayCountry().length() > 0) {
              sb.append(" (").append(locale.getDisplayCountry()).append(")");
            }
            sb.append(" - ").append(locale.getLanguage());

            if (locale.getDisplayCountry() != null && locale.getDisplayCountry().length() > 0) {
              sb.append(":").append(locale.getCountry());
            }
            sb.append("\n");
            break;
        }
      }
      send(sb.substring(0, Math.max(0, sb.length() - 1)));
    } else if (isMatchingCmd(cmd, "tts-engine")) {
      if (Build.VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) {
        send(R.string.android_version_incompatible, "ICE CREAM SANDWICH");
      } else {
        mTts = new TextToSpeech(sContext, this, cmd.getAllArg1());
        send(getString(R.string.chat_tts_engine) + mTts.getDefaultEngine());
      }
    } else if (isMatchingCmd(cmd, "tts-lang")) {
      String arg1 = cmd.getArg1();
      String arg2 = cmd.getArg2();
      if (!arg1.equals("") && !arg2.equals("")) {
        mLocale = new Locale(arg1, arg2);
        mTts.setLanguage(mLocale);
      } else if (!arg1.equals("")) {
        mLocale = new Locale(arg1);
        mTts.setLanguage(mLocale);
      }
      send(getString(R.string.chat_tts_language) + mTts.getLanguage().getDisplayName());
    }
  }