androidandroid-speech-api

Android is ignoring RECORD_AUDIO permission and Speech API implementation


I'm trying to get Speech Recognition working for my Android 2.3.3 app but something fundamental is missing.

First off, at the top of my AndroidManifest.xml file I have:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myuser.myapp">
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"

        ... remainder omitted for brevity

Which I believe should be prompting Android to ask the end user if they wish to grant my app permission to the microphone when it starts up (if not, please correct me!)...

Next, I have the Activity which houses the entire need for my app's speech recognition capabilities. Basically, I want the app to detect whenever someone says, out loud, "Go":

public class SpeechActivity extends AppCompatActivity implements RecognitionListener {
    private SpeechRecognizer speechRecognizer;

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

        int check = ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO);
        if(check != PackageManager.PERMISSION_GRANTED) {
            throw new RuntimeException("Ya can't do that now, ya here.");
        }

        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        speechRecognizer.setRecognitionListener(this);

        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, "voice.recognition.test");
        speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
        speechRecognizer.startListening(speechIntent);
        Log.i("SpeechActivity", "Speech Recognizer is listening");
    }

    @Override
    public void onReadyForSpeech(Bundle bundle) {

    }

    @Override
    public void onBeginningOfSpeech() {

    }

    @Override
    public void onRmsChanged(float v) {

    }

    @Override
    public void onBufferReceived(byte[] bytes) {

    }

    @Override
    public void onEndOfSpeech() {

    }

    @Override
    public void onError(int i) {

    }

    @Override
    public void onResults(Bundle bundle) {
        Log.i("SpeechActivity", "Speech was detected...");
        String spoken = "";
        ArrayList<String> data = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
        for (int i = 0; i < data.size(); i++) {
            spoken += data.get(i);
        }

        Log.i(this.getClass().getName(), String.format("The word \"%s\" was detected.", spoken));
        if(spoken.equalsIgnoreCase("go")) {
            doSomething();
        }
    }

    @Override
    public void onPartialResults(Bundle bundle) {

    }

    @Override
    public void onEvent(int i, Bundle bundle) {

    }
}

I run the app on my Samsung Galaxy S7 Edge by connecting my phone to my laptop (via USB), clicking the Run (app) button in Android Studio, and selecting my phone as the connected device.

When the app starts up on my phone, the first thing I notice is that it does not prompt me to accept/reject the app's permission to use the microphone. This is an early warning sign to me that something is awry.

But then, when I navigate to the SpeechActivity/activity_speech.xml screen, I get:

When this runs I get:

FATAL EXCEPTION: main
Process: com.example.myuser.myapp, PID: 9585
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myuser.myapp/com.example.myuser.myapp.SpeechActivity}: java.lang.RuntimeException: Ya can't do that now, ya here.
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2947)
   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008)
   at android.app.ActivityThread.-wrap14(ActivityThread.java)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6688)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.RuntimeException: Ya can't do that now, ya here.
   at com.example.myuser.myapp.SpeechActivity.onCreate(SpeechActivity.java:43)
   at android.app.Activity.performCreate(Activity.java:6912)
   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2900)

Is it possible I need to download and install a plugin or APK in order for speech recognition to work? Why is my app not asking permission to use my phone's mic? How is the speech recognizer started/listening, but then doesn't seem to pick up on any speech at all?


Solution

  • According to the documentation, it is a dangerous permission. You should request for it from user.

    RECORD_AUDIO : Allows an application to record audio.

    Protection level: dangerous

    Constant Value: "android.permission.RECORD_AUDIO"

    Simply, you can check if your app has this permission using

    int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.RECORD_AUDIO);
    
    if (permissionCheck == PERMISSION_GRANTED) {
        // you have the permission, proceed to record audio
    
        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        speechRecognizer.setRecognitionListener(this);
    
        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, "voice.recognition.test");
        speechIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
        speechRecognizer.startListening(speechIntent);
        Log.i("SpeechActivity", "Speech Recognizer is listening");
    
    } 
    else {
    
        // you don't have permission, try requesting for it
    
        ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.RECORD_AUDIO},
                MY_PERMISSION_REQUEST_RECORD_AUDIO);
    }
    

    Take your time, read Requesting Permissions guide at Android Guides.