简体   繁体   中英

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

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

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

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

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

Code flow is like this:

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

LogCat Message:

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)

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.

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:

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$1.create(Enum.java:43)
 at java.lang.Enum$1.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$1.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.

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.

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

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 .

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

lemme know if I had understood the problem correctly

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM