Android 带有 SpeechRecognizer 的自定义键盘

Android Custom Keyboard with SpeechRecognizer

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

此代码运行良好。这里的转折点是,当用户点击麦克风键时,我想要在 google 键盘上发生类似的行为:

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

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。 实现这一目标的理想方法是什么?我应该简单地开始一个没有布局的新 activity 并回调到 inputMethodService 吗?看起来很乱

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

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

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

解决方案的简单实现:

// 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,只需关闭它,它就会退回到之前的输入法