0

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?

Zoe
  • 27,060
  • 21
  • 118
  • 148
smeeb
  • 27,777
  • 57
  • 250
  • 447
  • Declaring permission in the manifest was the way to go before Mashmallow, since then you need to ask user permission by permission which will display a prompt on the screen. You should check this link : https://developer.android.com/training/permissions/requesting.html – vincenth Oct 09 '17 at 15:31
  • Samsung Galaxy S7 Edge with Android 2.3.3, really? – rupinderjeet Oct 09 '17 at 15:31
  • Yes @rupinderjeet why is 2.3.3 a problem with my particular device? – smeeb Oct 09 '17 at 15:38
  • What is 2.3.3 according to you, is it GINGER_BREAD? – rupinderjeet Oct 09 '17 at 15:49
  • That's just what it tells me when I go to **Android Studio >> About Android Studio**. It says: "*Android Studio 2.3.3 Build #AI-162.4069837, built on June 6, 2017.*" – smeeb Oct 09 '17 at 15:51
  • OMG! Android 2.3.3 means GingerBread version of Android that was launched on December 6, 2010. That one is Android Studio v2.3.3, the IDE itself. Anyway, my answer still stands correct. – rupinderjeet Oct 09 '17 at 15:53

1 Answers1

3

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.

Community
  • 1
  • 1
rupinderjeet
  • 2,984
  • 30
  • 54
  • Thanks @rupinderjeet (+1; also I redacted my previous comment as your revised answer is more inline with addressing my question!). Please see my edits, I added your suggested permission check and now my app dies when I navigate to the `SpeechActivity`, throwing the exception ("Ya can't do that..."). Furthermore, it's still not prompting me to grant permission to use the mic. Any ideas? – smeeb Oct 09 '17 at 15:37
  • It throws exception because you don't have permission. I edited my answer to tell you how to request for permissions. Also, pay attention to last line of my answer – rupinderjeet Oct 09 '17 at 15:44
  • Thanks @rupinderjeet (+1) - I added the stacktrace if it helps you. Why do you say I don't have permission? Shouldn't I be getting prompted for permission at some point? – smeeb Oct 09 '17 at 15:48
  • You don't get prompted if you don't request for permission. You should read that article linked at bottom of my answer. You declare a permission in manifest. You request for it when you need it. User decides to accept or reject it. Android, itself, doesn't help you. I wish it could, but no. – rupinderjeet Oct 09 '17 at 15:50
  • "*Dangerous permissions can give the app access to the user's confidential data. If your app lists a normal permission in its manifest, the system grants the permission automatically. If you list a dangerous permission, the user has to explicitly give approval to your app.*"... so what am I missing here?!?! **I am declaring the permission in my manifest. I am checking for permission in the code (see my changes above). Yet I am still not being asked to give explicit approval/permission when the ap runs.** – smeeb Oct 09 '17 at 15:54
  • Checking permission means you are checking if you have it. Requesting permission means you ask user to give it to you. That's when request dialog appears for user. For god's sake, write the code in else block from my answer in your code such that you execute Speech Recognition ONLY if you have the permission. – rupinderjeet Oct 09 '17 at 15:56
  • I think we're getting close to the root of my confusion, real quick, for sanity's sake, what should happen when `ContextCompat.checkSelfPermission` is called? – smeeb Oct 09 '17 at 15:59
  • It just asks System, "Do I have permission?", System replies "No". That's it for `ContextCompat.checkSelfPermission` – rupinderjeet Oct 09 '17 at 16:01
  • You will need to use `ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSION_REQUEST_RECORD_AUDIO);` to say "I need this permission.", System says "Let me ask the user first." – rupinderjeet Oct 09 '17 at 16:02
  • Your app doesn't. You checked `if (check != PERMISSION_GRANTED) {}`. and condition was true, that's why it threw exception – rupinderjeet Oct 09 '17 at 16:04
  • Ahhh OK, so after `ActivityCompat.requestPermissions`, the user (me) is asked for permission, I grant that permission, and then what line of code executes after that? Because in your example above, it looks like the whole block of code inside the `if(permissionCheck == PERMISSION_GRANTED)` condition would get skipped, no? – smeeb Oct 09 '17 at 16:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/156281/discussion-between-rupinderjeet-and-smeeb). – rupinderjeet Oct 09 '17 at 16:07