Java 权限拒绝错误 - SpeechRecognizer 作为持续服务?(android.permission.INTERACT_ACROSS_USERS_FULL)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20562874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:49:43  来源:igfitidea点击:

Permission Denial Error - SpeechRecognizer as a continuous service? (android.permission.INTERACT_ACROSS_USERS_FULL)

javaandroidspeech-recognition

提问by Aki008

EDITED: I have changed my service code to implement as started service instead of IntentService as updated StreamService.java below Now, I am getting error regarding permission denial error as described in logcat messages after StreamService.java

编辑:我已经更改了我的服务代码以实现作为启动服务而不是 IntentService 作为下面更新的 StreamService.java 现在,我收到关于 StreamService.java 之后的 logcat 消息中描述的权限拒绝错误的错误

EDITED:

编辑:

As mentioned in Android Developer site that SpeechRecognizer API can only be used as Application Context. Is there any woraround with which I can get it working

I have implemented MainActivity class that has all the UI Components. Class is as below

我已经实现了包含所有 UI 组件的 MainActivity 类。类如下

CODE - MainActivity.java

代码 - MainActivity.java

package com.example.speechsensorservice;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {


    private static final String TAG = "SpeechSensor";

    private boolean headsetConnected = false;

    public TextView txtText;

    private BroadcastReceiver mReceiver;
    private ImageButton btnSpeak;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txtText = (TextView) findViewById(R.id.txtText);
        btnSpeak = (ImageButton) findViewById(R.id.btnSpeak);

        btnSpeak.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(),StreamService.class);
                startService(intent);
            }
        });
    }

    protected void onResume() {
        super.onResume();

        IntentFilter sIF = new IntentFilter();
        sIF.addAction(Intent.ACTION_HEADSET_PLUG);
        sIF.addAction("com.example.speechsensorservice.TEXT");
        mReceiver = new BroadcastReceiver() {

                @Override
            public void onReceive(Context arg0, Intent arg1) {
                // TODO Auto-generated method stub
                String act = arg1.getAction();
                Log.d(TAG, "Received Action = " + act);
                if ( Intent.ACTION_HEADSET_PLUG.equals(act) ) {
                    if ( arg1.hasExtra("state")) {
                        if ( !headsetConnected && arg1.getIntExtra("state", 0) == 1 ) {
                            headsetConnected = true;
                            txtText.setText("Headset Plugged in");
                            startNoiseProcessService();
                        }
                    }
                }
                else if ( act.equals("com.example.speechsensorservice.TEXT") ){
                    if ( arg1.hasExtra("Identity")) {
                        String s = arg1.getStringExtra("Identity");
                        if ( s.equals("NA") ) {
                            Toast t = Toast.makeText(getApplicationContext(), 
                                    "Your Device doesnot support Speech to Text", 
                                    Toast.LENGTH_SHORT);
                            t.show();
                        }
                        else txtText.setText(s);
                    }
                }
            }

        };  

        this.registerReceiver(mReceiver, sIF);      
    }

    public void onPause() {
        super.onPause();
        this.unregisterReceiver(this.mReceiver);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    public void startNoiseProcessService() {
        Intent intent = new Intent(this,StreamService.class);
        startService(intent);
    }


}

Another class that I have implemented to start Speech Recognition Service as a background task by inheriting IntentService class. The implementation is as below

我已经实现的另一个类通过继承 IntentService 类来启动语音识别服务作为后台任务。实现如下

Code - StreamService.java

代码 - StreamService.java

    package com.example.speechsensorservice;

import java.util.ArrayList;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.IBinder;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.util.Log;

public class StreamService extends Service {
     private static final String TAG = "SpeechSensor";
     private static final String ACTION = "com.example.speechsensorservice.TEXT";
    private SpeechRecognizer sr;

    private BroadcastReceiver sReceiver;

    private boolean headsetConnected = true;

    String text;


    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate() StreamService Method");
        super.onCreate();
        sReceiver = new BroadcastReceiver() {
            public void onReceive(Context arg0, Intent arg1) {
                // TODO Auto-generated method stub
                if ( Intent.ACTION_HEADSET_PLUG.equals(arg1.getAction()) ) {
                    if ( arg1.hasExtra("state")) {
                            if ( headsetConnected && arg1.getIntExtra("state", 0) == 0 ) {
                                headsetConnected = false;
                                stopStreaming(); 
                            } 
                    }
                }
            }

        };  
        this.registerReceiver(sReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); 
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"Inside onStartCommand()");
    //  Runnable r = new Runnable() {
    //      public void run() {
                startStreaming();
    //      }
    //  };

    //  Thread t = new Thread(r);
    //  t.start();

        return Service.START_STICKY;

    }

    @Override
    public  void onDestroy() {
        Log.d(TAG, "onDestroy() StreamService Method");
        super.onDestroy();
        this.unregisterReceiver(this.sReceiver);
    }


     public void startStreaming() {
         Log.d(TAG, "Inside startStreaming()");
            Intent intent;
            text = "";
            if ( !SpeechRecognizer.isRecognitionAvailable(this) ) {
                Log.d(TAG, "Not Applicable with your device");
                text = "NA";
                intent = new Intent(ACTION);
                intent.putExtra("Identity", text);
                sendBroadcast(intent);
            }
            else {
                Log.d(TAG, "started taking input");
                sr = SpeechRecognizer.createSpeechRecognizer(this.getApplicationContext());

                intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

                //intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "hi-IN");
                intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");//RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);//RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
             //   intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 3);

                sr.setRecognitionListener( new mylistener());
                sr.startListening(intent);
            }

     }

     public void stopStreaming() {
            if ( sr == null ) return;
            Log.d(TAG, "stopped taking input");
            sr.cancel();
            sr.destroy();
            sr = null;
            this.stopSelf();
     }

     public boolean isStreaming() {
            // TODO Auto-generated method stub
            Log.d(TAG,"isStreaming : YES");
            if ( sr != null ) return true;
            return false;
     }

     class mylistener implements RecognitionListener {

            @Override
            public void onBeginningOfSpeech() {
                // TODO Auto-generated method stub
                Log.d(TAG, "onBeginningOfSpeech");
            }

            @Override
            public void onBufferReceived(byte[] arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onEndOfSpeech() {
                // TODO Auto-generated method stub
                Log.d(TAG, "onEndOfSpeech");
            }

            @Override
            public void onError(int arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onEvent(int arg0, Bundle arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onPartialResults(Bundle arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onReadyForSpeech(Bundle arg0) {
                // TODO Auto-generated method stub
                Log.d(TAG, "onReadyForSpeech");
            }

            @Override
            public void onResults(Bundle arg0) {
                // TODO Auto-generated method stub


                Log.d(TAG, "Got Results");
                ArrayList<String> al = arg0.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
                text = al.get(0);
                for ( int i =0 ; i < al.size(); i++ ) {
                    Log.d(TAG,"result=" + al.get(i));
                }
                Intent intent = new Intent(ACTION);
                intent.putExtra("Identifier", text);
                sendBroadcast(intent);
              //  startStreaming();

            }

            @Override
            public void onRmsChanged(float arg0) {
                // TODO Auto-generated method stub

            }

        }

}

Here I am getting error java.lang.RuntimeException: SpeechRecognizer should be used only from the application's main thread

在这里我收到错误 java.lang.RuntimeException: SpeechRecognizer should be used only from the application's main thread

Code flow is like this:

代码流程是这样的:

ImageButton->onClick()->Fire the service Intent for StreamService.class->onCreate()->onHandleIntent()->calling startStreaming() -> getting error

ImageButton->onClick()->Fire the service Intent for StreamService.class->onCreate()->onHandleIntent()->calling startStreaming() -> 获取错误

LogCat Message:

LogCat 消息:

12-13 17:03:24.822   794  7381 E DatabaseUtils: Writing exception to parcel
12-13 17:03:24.822   794  7381 E DatabaseUtils: java.lang.SecurityException: Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at com.android.server.am.ActivityManagerService.handleIncomingUser(ActivityManagerService.java:12754)
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at android.app.ActivityManager.handleIncomingUser(ActivityManager.java:1998)
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at com.android.providers.settings.SettingsProvider.call(SettingsProvider.java:574)
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at android.content.ContentProvider$Transport.call(ContentProvider.java:256)
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:256)
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at android.os.Binder.execTransact(Binder.java:351)
12-13 17:03:24.822   794  7381 E DatabaseUtils:     at dalvik.system.NativeStart.run(Native Method)

回答by Khay

well the problem is self solution explaining , the first line in your logCat is giving you the solution that, the current thread does not have the permission for executing user task , so just add the following permission in manifest and see if it works out .

好吧,问题是自我解决方案的解释,您的 logCat 中的第一行为您提供了解决方案,即当前线程没有执行用户任务的权限,因此只需在清单中添加以下权限,看看它是否有效。

<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL">

lemme know if I had understood the problem correctly

让我知道我是否正确理解了问题

回答by Kevin Hunter

There are times when this particular error is actually misleading, and is caused by other runtime problems.

有时,此特定错误实际上具有误导性,并且是由其他运行时问题引起的。

I documented one such example here- a NullPointerException thrown down deep ended up being reported as this same error, even though it had nothing to do with cross-user permissions.

在这里记录了一个这样的例子——一个 NullPointerException 被抛出很深,最终被报告为同样的错误,即使它与跨用户权限无关。

In my particular case, ProGuard was stripping out a method that I needed, which caused a NullPointerException to be thrown. The stack trace looked like this:

在我的特殊情况下,ProGuard 剥离了我需要的方法,这导致抛出 NullPointerException。堆栈跟踪如下所示:

Permission Denial: get/set setting for user asks to run as user -2 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL
java.lang.NullPointerException
 at java.lang.Enum.create(Enum.java:43)
 at java.lang.Enum.create(Enum.java:35)
 at libcore.util.BasicLruCache.get(BasicLruCache.java:54)
 at java.lang.Enum.getSharedConstants(Enum.java:209)
 at java.lang.Enum.valueOf(Enum.java:189)
 at com.my.app.package.b.c.a(Unknown Source)
 at com.my.app.package.b.a.onCreate(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
 at android.support.v4.app.BackStackRecord.run(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.execPendingActions(Unknown Source)
 at android.support.v4.app.FragmentManagerImpl.run(Unknown Source)
 at android.os.Handler.handleCallback(Handler.java:730)
 at android.os.Handler.dispatchMessage(Handler.java:92)
 at android.os.Looper.loop(Looper.java:137)
 at android.app.ActivityThread.main(ActivityThread.java:5455)
 at java.lang.reflect.Method.invokeNative(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:525)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
 at dalvik.system.NativeStart.main(Native Method)

I haven't a clue in the world why Android turned the NullPointerException into the android.permission.INTERACT_ACROSS_USERS_FULL error, but the obvious solution was to tweak the ProGuard configuration so that the method wasn't being stripped.

我不知道为什么 Android 将 NullPointerException 转换为 android.permission.INTERACT_ACROSS_USERS_FULL 错误,但显而易见的解决方案是调整 ProGuard 配置,以便该方法不会被剥离。

The method I was calling that wasn't there was the "valueOf" method on an enum. It turns out that there's some interesting reflection involved under the hood (which I go into at the link above), but the solution for me was to add the following to my ProGuard configuration.

我调用的方法不存在枚举上的“valueOf”方法。事实证明,引擎盖下涉及一些有趣的反射(我在上面的链接中进行了介绍),但我的解决方案是将以下内容添加到我的 ProGuard 配置中。

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}