带有 SpeechRecognizer 的 Android 自定义键盘

Posted

技术标签:

【中文标题】带有 SpeechRecognizer 的 Android 自定义键盘【英文标题】:Android Custom Keyboard with SpeechRecognizer 【发布时间】:2017-05-17 19:40:39 【问题描述】:

我有一个功能齐全的自定义 android 键盘,我必须在其中添加语音识别。这是我所拥有的实现的相关部分

public class CustomInputMethodService 
    extends InputMethodService
    implements <random stuff> 

    private SpeechRecognizer mSpeechRecognizer;
    private RecognitionListener mSpeechlistener;

    public void onCreate() 
        super.onCreate();
        mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        mSpeechlistener = new CustomRecognitionListener();
        mSpeechRecognizer.setRecognitionListener(mSpeechlistener);
    

    @Override
    public void onPress(int primaryCode) 
        if (primaryCode == KeyCodes.VOICE_INPUT) 
            mSpeechRecognizer.startListening(getSpeechIntent());
        else if(..)
            ...
        
    

    private Intent getSpeechIntent() 
        Intent speechIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        speechIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        speechIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, this.getPackageName());
        speechIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, false);
        return speechIntent;
    


CustomRecognitionListener的相关方法很简单:

        @Override
        public void onResults(Bundle results) 
            ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
            Log.d(TAG, "onResults: ----> " + matches.get(0));
            if(matches != null && matches.size() > 0) 
                writeText(matches.get(0));
            
        

这段代码运行良好。这里的转折是我想要一个类似于当用户点击麦克风键时在谷歌键盘上发生的行为:

理想情况下,这可以通过以下方式实现:

Intent voiceIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
try 
    startActivityForResult(voiceIntent, Constants.RESULT_SPEECH);
 catch (ActivityNotFoundException ex) 
    DebugLog.e(TAG, "Not found excpetion onKeyDown: " + ex);

但是,由于键侦听器已打开且 InputMethodService 我无法调用 startActivityForResult。 实现这一目标的理想方法是什么?我是否应该简单地开始一个没有布局的新活动并对 inputMethodService 进行回调?看起来很乱

【问题讨论】:

您查看过 Google 的 LatinIME 键盘以了解它是如何做到的吗?多年过去了,我不记得是怎么做了,但我们只是在为 Swype 做的时候复制了它。 谢谢。我检查了 LatinIME 并且我实际上使用了错误的方法。我会在一秒钟内发布答案。 【参考方案1】:

您的屏幕截图显示“Google 语音输入”,这是一种独立的 IME,当按下其麦克风按钮时由 Google 键盘调用。因此,您的 IME 也应该这样做:将自己替换为提供语音输入的 IME,并希望在语音输入完成后有一个指向您的 IME 的反向链接。

最简单的实现是Switching among IME Subtypes,但您可能希望拥有更多控制权,例如使用特定的输入参数等启动特定的 IME。我不确定实现这种额外控制的最佳/标准方法是什么。

有关语音输入 IME 的示例,您可以查看(我的应用程序)Kõnele。

【讨论】:

我正要发布完全相同的答案!是的,该方法正是将当前的输入法触发到谷歌语音。一旦我发现它的措辞完美无缺【参考方案2】:

解决方案的简单实现:

// on mic tap we call
public void startVoiceListening() 
    InputMethodManager imeManager = (InputMethodManager) getApplicationContext().getSystemService(INPUT_METHOD_SERVICE);
    String voiceExists = voiceExists(imeManager);
    if (voiceExists != null) 
        final IBinder token = getWindow().getWindow().getAttributes().token;
        imeManager.setInputMethod(token,voiceExists);
    


private String voiceExists(InputMethodManager imeManager) 
    List<InputMethodInfo> list = imeManager.getInputMethodList();
    for (InputMethodInfo el : list) 
        // do something to check whatever IME we want.
        // in this case "com.google.android.googlequicksearchbox"
    
    return null;

一旦我们不想再使用当前的 IME,只需将其关闭,它就会退回到前一个

【讨论】:

以上是关于带有 SpeechRecognizer 的 Android 自定义键盘的主要内容,如果未能解决你的问题,请参考以下文章

如何使 SpeechRecognizer 的哔声静音?

Android科大讯飞——语音识别 解决"SpeechRecognizer.createRecognizer()获取的SpeechRecognizer对象为null"问题

面向 Android 11 时 SpeechRecognizer 不可用

SpeechRecognizer.isRecognitionAvailable() 在 Android 11 中始终为 false

有没有办法将音频字节发送到 SpeechRecognizer

Android TV SearchFragment 错误 SpeechRecognizer