Auto download offline speech recognition language on Android

隐身守侯 提交于 2019-12-04 00:19:56
brandall

This is not the answer you are hoping for, as at the time of writing, I don't believe there is a straight forward solution to this. I very much hope to be proved wrong.

I requested an enhancement to provide this information programmatically a long time ago - here

The enhancement suggested an additional parameter RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES:

It would surely be trivial for this to be added and used in the following way:

final Intent vrIntent = new Intent(RecognizerIntent.ACTION_GET_LANGUAGE_DETAILS);
getContext().sendOrderedBroadcast(vrIntent, null, new BroadcastReceiver() {

    @Override
    public void onReceive(final Context context, final Intent intent) {

        final ArrayList<String> vrStringLocales = intent.getExtras().getStringArrayList(
                RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);

        // This would be nice
        final ArrayList<String> vrStringOfflineLocales = intent.getExtras().getStringArrayList(
                RecognizerIntent.EXTRA_SUPPORTED_OFFLINE_LANGUAGES);
    }

}, null, 1234, null, null);

Alas, it has never happened.

You do have two other options to attempt to handle this gracefully.

In the unlikely event you application runs with root permissions, you can check the location of /data/data/com.google.android.googlequicksearchbox/app_g3_models/ which contains the offline files, labelled quite handily by their locale.

The second involves knowing when the user needs a prompt to install the missing offline files.

From my experience, the recognition error of SpeechRecognizer.ERROR_SERVER most often denotes this, but it is not foolproof.

@Override
public void onError(final int error) {

    switch (error) {

        case SpeechRecognizer.ERROR_SERVER:
            // TODO - prompt to install offline files
            break;
    }
}

When detected, you can guide the user to the correct installation screen.

public static final String PACKAGE_NAME_GOOGLE_NOW = "com.google.android.googlequicksearchbox";
public static final String ACTIVITY_INSTALL_OFFLINE_FILES = "com.google.android.voicesearch.greco3.languagepack.InstallActivity";

public static boolean showInstallOfflineVoiceFiles(@NonNull final Context ctx) {

    final Intent intent = new Intent();
    intent.setComponent(new ComponentName(PACKAGE_NAME_GOOGLE_NOW, ACTIVITY_INSTALL_OFFLINE_FILES));

    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

    try {
        ctx.startActivity(intent);
        return true;
    } catch (final ActivityNotFoundException e) {

    } catch (final Exception e) {

    }

    return false;
}

Using hard-coded values such as this, is of course not ideal, but neither is this situation!

Once you've messed around with all of the above and think you have a good interim solution - think again! Regardless of whether the user has correctly installed the missing offline files, it is highly likely it still won't work.....

My answer here describes the process I still have to guide my user's with. It's very frustrating.

Finally one more bug to throw into the mix - RecognitionListener.onError(int) can be thrown when there isn't an error. Check my gist from the answer here to use a BugRecognitionListener so you can check the callbacks are being sent in the correct order and ignore those that aren't. This remains a problem, despite my answer suggesting a fix in a previous release.

The above should keep you busy! Good luck....

To detect whether needed Language(German) is available, please follow below :

  • Iterate the Locale list and check whether Locale available for German language.

  • If you didn't get any Locale object in return, you can conclude that German language is not available offline. Then you can write code to download and do other stuff.

  • I did below implementation for my project. Hope below code helps you !!!

    private TextToSpeech t1;
    
    private void setForOtherLangAudio() {
    Locale[] locales = Locale.getAvailableLocales();
    Locale loc = null;
    for (Locale locale : locales) {
      // Replace XXX with your German codes
      if (locale.getDisplayCountry().equals("XXX") &&   locale.getDisplayLanguage().equals("XXX")) {
        loc = locale ;
        break;
    }
    }
    final Locale germanLocale = loc;
    t1 = new TextToSpeech(getContext(), new TextToSpeech.OnInitListener() {
        @Override
        public void onInit(int status) {
            if (status != TextToSpeech.ERROR) {
                t1.setLanguage(germanLocale);
            }
        }
    });
    

    }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!