hasanghaforian
hasanghaforian

Reputation: 14022

"Text to Speech" in Android 9.0

I want to use TTS in an Android application. I followed introduction-to-text-to-speech-in. And this is the code of the Activity which creates TTS instance:

public class MainActivity extends Activity implements TextToSpeech.OnInitListener {

    private int MY_DATA_CHECK_CODE = 0;
    private TextToSpeech myTTS;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent checkTTSIntent = new Intent();
        checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE);
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == MY_DATA_CHECK_CODE) {
            if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
                myTTS = new TextToSpeech(this, this);
            }
            else {
                Intent installTTSIntent = new Intent();
                installTTSIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
                startActivity(installTTSIntent);
            }
        }
    }

    @Override
    public void onInit(int status) {

    }
}

As you can see it is straightforward and simple and also works up to Android 8.1-API 27; but in Android 9.0 I get ActivityNotFoundException:

Although with attention to documentation about ACTION_CHECK_TTS_DATA and ACTION_INSTALL_TTS_DATA, no one of them is deprecated. How I can solve above errors?

Upvotes: 1

Views: 1068

Answers (1)

Nerdy Bunz
Nerdy Bunz

Reputation: 7437

Sounds like it's probably a beta version of Android 9.0 emulator that is janky?

I don't think it's necessary these days to use the CHECK_TTS_DATA intent... as

1) most all devices (commercial phones, at least) have at least one TTS installed,

2) the myTTS object won't initialize unless that is true ( or, at least it will return an onError callback if you attempt a speak() ), and

3) devices can have multiple engines installed and thus will force the user to choose which engine to send the intent (from the example you used) to.

Instead, I would decide what exact engine/s you want to support, check for it/them specifically, and prompt to install it/them.

For example, if you decided to use/support the Google engine:

private boolean isGoogleTTSInstalled() {

        Intent ttsIntent = new Intent();
        ttsIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
        PackageManager pm = this.getPackageManager();
        List<ResolveInfo> listOfInstalledTTSInfo = pm.queryIntentActivities(ttsIntent, PackageManager.GET_META_DATA);
        for (ResolveInfo r : listOfInstalledTTSInfo) {
            String engineName = r.activityInfo.applicationInfo.packageName;
            if (engineName.equals("com.google.android.tts")) {
                return true;
            }
        }
        return false;

    }

private void installGoogleTTS() {

        Intent goToMarket = new Intent(Intent.ACTION_VIEW)
                .setData(Uri.parse("market://details?id=com.google.android.tts"));
        startActivity(goToMarket);

    }

And, if you intend to support a specific language, check for it using myTTS.isLanguageAvailable(Locale loc), and if not:

private void openTTSSettingsToInstallUnsupportedLanguage() {

        Intent intent = new Intent();
        intent.setAction("com.android.settings.TTS_SETTINGS");
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);

    }

Upvotes: 1

Related Questions