1

I'm working on a small app that requires READ_PHONE_STATE permission. I added the permission request on my manifest.xml as such

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mobile.stoq.stoqpay">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.INTERNET" />
    <application
    ...

However while reading on it I found I had to do an actual request to the user to acquire that permission, so I tried to do so with the following snippet

public class ValidationActivity extends AppCompatActivity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_validation);
        //TODO: Fix this permission request. It sort of works but not really
        int REQUEST_RPS = 0;
        if (ContextCompat.checkSelfPermission(ValidationActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(ValidationActivity.this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_RPS);
        }

        List<UserModel> listOfUser = StoneStart.init(this);

        if (listOfUser == null) {

            List<String> stoneCodeToActiveList = new ArrayList<>();
            String STONE_PRODUCTION_KEY = "846873720";
            stoneCodeToActiveList.add(STONE_PRODUCTION_KEY);

            ActiveApplicationProvider activeApplicationProvider = new ActiveApplicationProvider(this, stoneCodeToActiveList);
            activeApplicationProvider.setDialogMessage("Activating");
            activeApplicationProvider.setDialogTitle("Please wait");
            activeApplicationProvider.setWorkInBackground(false);
            activeApplicationProvider.setConnectionCallback(new StoneCallbackInterface() {
                public void onSuccess() {
                    Toast.makeText(getApplicationContext(), "Activation successful", Toast.LENGTH_SHORT).show();
                    continueApplication();
                }

                public void onError() {
                    Toast.makeText(getApplicationContext(), "Activation failed", Toast.LENGTH_SHORT).show();
                }
            });
            activeApplicationProvider.execute();
        } else {
            continueApplication();

        }
    }

    private void continueApplication() {

        int SPLASH_DISPLAY_LENGTH = 3500;
        new Handler().postDelayed(new Runnable() {
            public void run() {

                Intent mainIntent = new Intent(ValidationActivity.this, MainActivity.class);
                ValidationActivity.this.startActivity(mainIntent);
                ValidationActivity.this.finish();
            }
        }, SPLASH_DISPLAY_LENGTH);
    }
}

When my app runs though it will either crash or freeze, and after I restart it I have the correct permissions and it works nicely. This is what logcat shows me:

03-13 19:49:57.938 6682-6714/com.mobile.stoq.stoqpay W/System.err: java.lang.SecurityException: getDeviceId: Neither user 10068 nor current process has android.permission.READ_PHONE_STATE.
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at android.os.Parcel.readException(Parcel.java:1620)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at android.os.Parcel.readException(Parcel.java:1573)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId(ITelephony.java:4207)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java:706)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at stone.providers.ActiveApplicationProvider.doInBackground(ActiveApplicationProvider.java:102)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:295)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
03-13 19:49:57.954 6682-6714/com.mobile.stoq.stoqpay W/System.err:     at java.lang.Thread.run(Thread.java:818)

What am I doing wrong? How may I fix this?

Bernardo Meurer
  • 2,295
  • 5
  • 31
  • 52
  • "When my app runs though it will either crash or freeze" -- use LogCat to examine the Java stack trace associated with your crash: https://stackoverflow.com/questions/23353173/unfortunately-myapp-has-stopped-how-can-i-solve-this – CommonsWare Mar 13 '16 at 22:48
  • @CommonsWare Done, thanks for the tip. – Bernardo Meurer Mar 13 '16 at 22:53
  • Are you waiting until you actually *get* the `READ_PHONE_STATE` permission before executing the `AsyncTask`? – CommonsWare Mar 13 '16 at 22:56
  • @CommonsWare Which `AsyncTask`? But I'm not doing any waiting, after that snippet I posted my code just goes onward normally – Bernardo Meurer Mar 13 '16 at 22:58
  • I see you are calling the getDeviceId from an ASyncTask, when are you starting the ASyncTask? You may only call the method getDeviceId once the user has granted the permission. Check out the runtime permissions guide on http://developer.android.com/training/permissions/requesting.html – Remco Mar 13 '16 at 22:58
  • @CommonsWare, @Remco; I edited my post to include my complete code instead – Bernardo Meurer Mar 13 '16 at 23:00
  • Tried [this](https://gist.github.com/anonymous/117a6ca8e4e59a04d00a) so far with no success. – Bernardo Meurer Mar 13 '16 at 23:39

1 Answers1

2

ActivityCompat.requestPermissions() is asynchronous. It returns control to you immediately. You do not yet have the permission.

Move all that stuff that appears after the ActivityCompat.requestPermissions() call into a separate method (which I will call here foo()). Then:

  • If checkSelfPermission() shows that you have the permission, call foo()

  • If checkSelfPermission() shows that you do not have the permission, in your onRequestPermissionsResult() method, if you now have the permission, call foo()

  • If in onRequestPermissionsResult(), you still do not have the permission (e.g., the user denied your request), deal with it somehow

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Should I use `ContextCompat.checkSelfPermission()` or `ActivityCompat.checkSelfPermission()`? – Bernardo Meurer Mar 13 '16 at 23:08
  • 2
    @BernardMeurer: Either. `ActivityCompat` extends `ContextCompat`; it is literally the same method. – CommonsWare Mar 13 '16 at 23:13
  • My code didn't work out, could you make a short example if it's not too much trouble? I managed to make the request without crashing, but now the code no longer does anything afterwards. – Bernardo Meurer Mar 13 '16 at 23:18
  • @BernardMeurer: You did not follow the instructions in my answer. You did not implement `onRequestPermissionsResult()`, to see if you actually got the permission after showing the request dialog via `requestPermissions()`. You may wish to [read the documentation](http://developer.android.com/training/permissions/requesting.html). – CommonsWare Mar 13 '16 at 23:54