带有SpeechRecognizer的Android自定义键盘

时间:2017-01-03 16:37:36

标签: android keyboard speech-to-text android-input-method startactivityforresult

我有一个功能齐全的自定义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));
            }
        }

此代码工作得很好。这里的转折是我想要一个类似的行为,当uset点击麦克风键时谷歌键盘上发生的事情:

enter image description here

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

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吗?看起来很乱

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

解决方案的简单实施:

// 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,只需关闭它,它就会回到之前的那个