Android игнорирует разрешение RECORD_AUDIO и реализацию Speech API

Я пытаюсь заставить распознавание речи работать для моего приложения Android 2.3.3, но чего-то фундаментального не хватает.

Во-первых, в верхней части моего файла AndroidManifest.xml у меня есть:

<?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

Что, полагаю, должно побуждать Android спрашивать конечного пользователя, хотят ли они предоставить моему приложению разрешение на использование микрофона при его запуске (если нет, поправьте меня!) ...

Затем у меня есть Activity, который содержит все необходимые возможности распознавания речи моего приложения. По сути, я хочу, чтобы приложение обнаруживало, когда кто-то произносит вслух "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) {

    }
}

Я запускаю приложение на своем Samsung Galaxy S7 Edge, подключая телефон к ноутбуку (через USB), нажимая кнопку Запустить (приложение) в Android Studio и выбирая свой телефон в качестве подключенного устройства.

Когда приложение запускается на моем телефоне, первое, что я замечаю, это то, что оно не предлагает мне принять/отклонить разрешение приложения на использование микрофона. неправильно.

Но затем, когда я перехожу к экрану SpeechActivity/activity_speech.xml, я получаю:

Когда это запускается, я получаю:

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)

Возможно ли, что мне нужно загрузить и установить плагин или APK, чтобы распознавание речи работало? Почему мое приложение не запрашивает разрешение на использование микрофона моего телефона? Как распознаватель речи запускается/слушает, но потом вообще не улавливает речь?


person smeeb    schedule 09.10.2017    source источник
comment
Объявление разрешения в манифесте было способом сделать до Mashmallow, с тех пор вам нужно запрашивать разрешение пользователя с помощью разрешения, которое отобразит подсказку на экране. Вы должны проверить эту ссылку: developer.android.com/training/permissions/requesting.html< /а>   -  person vincenth    schedule 09.10.2017
comment
Samsung Galaxy S7 Edge с Android 2.3.3, правда?   -  person rupinderjeet    schedule 09.10.2017
comment
Да @rupinderjeet, почему 2.3.3 проблема с моим конкретным устройством?   -  person smeeb    schedule 09.10.2017
comment
Что такое 2.3.3 по-вашему, это GINGER_BREAD?   -  person rupinderjeet    schedule 09.10.2017
comment
Это именно то, что он говорит мне, когда я иду в Android Studio ›› About Android Studio. Там написано: Android Studio 2.3.3 Build #AI-162.4069837, сборка от 6 июня 2017 г.   -  person smeeb    schedule 09.10.2017
comment
МОЙ БОГ! Android 2.3.3 означает версию Android GingerBread, выпущенную 6 декабря 2010 года. Это Android Studio v2.3.3, сама IDE. В любом случае, мой ответ по-прежнему остается правильным.   -  person rupinderjeet    schedule 09.10.2017


Ответы (1)


Согласно документации, это опасное разрешение. Вы должны запросить его у пользователя.

RECORD_AUDIO: позволяет приложению записывать звук.

Уровень защиты: опасный

Постоянное значение: android.permission.RECORD_AUDIO

Просто вы можете проверить, есть ли у вашего приложения это разрешение, используя

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);
}

Не торопитесь, прочтите руководство по Запрос разрешений в Руководствах по Android.

person rupinderjeet    schedule 09.10.2017
comment
Спасибо @rupinderjeet (+1; также я отредактировал свой предыдущий комментарий, так как ваш пересмотренный ответ больше соответствует моему вопросу!). Пожалуйста, посмотрите мои правки, я добавил предложенную вами проверку разрешений, и теперь мое приложение умирает, когда я перехожу к SpeechActivity, выдавая исключение (я не могу этого сделать...). Кроме того, мне все еще не предлагается предоставить разрешение на использование микрофона. Любые идеи? - person smeeb; 09.10.2017
comment
Он выдает исключение, потому что у вас нет разрешения. Я отредактировал свой ответ, чтобы рассказать вам, как запрашивать разрешения. Также обратите внимание на последнюю строку моего ответа - person rupinderjeet; 09.10.2017
comment
Спасибо @rupinderjeet (+1) - я добавил трассировку стека, если она вам поможет. Почему ты говоришь, что у меня нет разрешения? Разве я не должен получать запрос на разрешение в какой-то момент? - person smeeb; 09.10.2017
comment
Вы не получите приглашение, если вы не запрашиваете разрешение. Вы должны прочитать эту статью, связанную внизу моего ответа. Вы объявляете разрешение в манифесте. Вы просите об этом, когда вам это нужно. Пользователь решает принять или отклонить его. Android сам по себе вам не поможет. Хотел бы я, но нет. - person rupinderjeet; 09.10.2017
comment
Опасные разрешения могут дать приложению доступ к конфиденциальным данным пользователя. Если ваше приложение перечисляет обычное разрешение в своем манифесте, система предоставляет разрешение автоматически. Если вы укажете опасное разрешение, пользователь должен явным образом одобрить ваше приложение.... так что же я здесь упускаю?!?! Я объявляю разрешение в своем манифесте. Я проверяю наличие разрешения в коде (см. мои изменения выше). Тем не менее, меня по-прежнему не просят дать явное одобрение/разрешение при запуске приложения. - person smeeb; 09.10.2017
comment
Проверка разрешения означает, что вы проверяете, есть ли оно у вас. Запрос разрешения означает, что вы просите пользователя предоставить его вам. Вот когда диалог запроса появляется для пользователя. Ради бога, напишите код в блоке else из моего ответа в своем коде, чтобы вы выполняли распознавание речи ТОЛЬКО, если у вас есть разрешение. - person rupinderjeet; 09.10.2017
comment
Я думаю, что мы приближаемся к корню моего замешательства, очень быстро, ради здравого смысла, что должно произойти, когда ContextCompat.checkSelfPermission вызывается? - person smeeb; 09.10.2017
comment
Он просто спрашивает систему, у меня есть разрешение?, система отвечает нет. Это все для ContextCompat.checkSelfPermission - person rupinderjeet; 09.10.2017
comment
Вам нужно будет использовать ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.RECORD_AUDIO}, MY_PERMISSION_REQUEST_RECORD_AUDIO);, чтобы сказать, что мне нужно это разрешение. Система говорит: «Позвольте мне сначала спросить пользователя». - person rupinderjeet; 09.10.2017
comment
Ваше приложение не поддерживает. Вы проверили if (check != PERMISSION_GRANTED) {}. и условие было истинным, поэтому было выдано исключение - person rupinderjeet; 09.10.2017
comment
Аааа, хорошо, после ActivityCompat.requestPermissions у пользователя (у меня) запрашивается разрешение, я даю это разрешение, а затем какая строка кода выполняется после этого? Потому что в приведенном выше примере похоже, что весь блок кода внутри условия if(permissionCheck == PERMISSION_GRANTED) будет пропущен, не так ли? - person smeeb; 09.10.2017
comment
Давайте продолжим это обсуждение в чате. - person rupinderjeet; 09.10.2017