0

My app requires access to the storage - just to read some OBB data - due to the size of the data we're dealing with. By definition this is classed as a 'dangerous' permission by android, and rightly so, so as of Android 6.0 we need to request it at the app's start before we can do anything.

The issue is that the user can deny us that permission, when the app fundamentally requires it to do anything past the main menu.

What is the correct way to deal with the situation where a user refuses to grant 'dangerous' permission at runtime, and an app is practically featureless without it?

EDIT: To clarify I know the code i need to do this and the callbacks involved. Code samples are not required. I need to know what i should do if constant denial will cripple my app to the usefulness of a rock. Error then kill the app? Show main menu with a message when the user tries to do anything? It may also be worth noting that this is a native app, so the C++ is calling back to the java to do this.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Force Gaia
  • 514
  • 2
  • 8
  • 24
  • Just show a dialog explaining why your app needs this permission and say that you will not be able to use the app without it then just dont let them past the main menu without it – tyczj Jun 23 '17 at 15:12
  • explain your users that why you need this permission, and if he still denied then exit your application, here is some solution https://stackoverflow.com/questions/41999564/android-close-app-if-user-not-granting-write-external-storage-permission – dharmx Jun 23 '17 at 15:24
  • Can you elaborate why you need the permission? Usually, you can put the OBB files in your [external file directory](https://developer.android.com/reference/android/content/Context.html#getExternalFilesDir(java.lang.String)) without requiring extra permissions, and this is how Google Play handles the app extensions. – Alex Cohn Aug 12 '17 at 08:16
  • @AlexCohn extract from this link under the header "Storage Location", https://developer.android.com/google/play/expansion-files.html : However, in some implementations of Android 6.0 (API level 23), you may need to declare the READ_EXTERNAL_STORAGE permission in the app manifest and ask for permission at runtime – Force Gaia Aug 12 '17 at 08:25
  • Yes, I remember this text, but I have never encountered this corner case, so maybe you know what kind of *some implementations* cause such strange behavior? Is it some mainstream ROM? – Alex Cohn Aug 12 '17 at 09:14
  • @AlexCohn when I'm next in work I'll tell you the devices we test on, as it happened on at least one of them. Besides, even if it is an edge case, those are still devices that won't work correctly without the permission - so it should be accounted for. – Force Gaia Aug 12 '17 at 10:33
  • Agreed. The question was mainly to learn from your experience. Is this *in some implementations* a bug, or a feature? Can you build the app not to ask for the permission when the *implementation* of Android 6+ does not require it to access the OBB? – Alex Cohn Aug 12 '17 at 13:01
  • 1
    @AlexCohn well initially we weren't asking for the permission and weren't able to read files of some devices. Our initial solution was to ask for the permission on all devices, but we will be fixing it to see if we can avoid doing that on those devices without that kind of implementation. So I'll update you when we get to that task and let you know how we tackle it - but it'll likely be in the form of: attempt, if (error){ask for permission, attempt again} – Force Gaia Aug 12 '17 at 13:11

4 Answers4

2

The crucial bit not yet described in the other answers is after a user has declined to provide the permission, the recommended approach is to show a rationale dialog explaining why your permission is essential. There is a compatibility helper that tracks this internal state:

    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

        new AlertDialog.Builder(this)
                .setTitle(R.string.title_my_permission)
                .setMessage(R.string.text_my_permission)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //Prompt the user once explanation has been shown
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                MY_PERMISSIONS_REQUEST_TAG);
                    }
                })
                .create()
                .show();
    } else {
        // probably first time, request permission
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                MY_PERMISSIONS_REQUEST_TAG);
    }

You should note however that the user is always in control and may decide never to grant your app the permission it needs, so you need a good bit of text in as many locales as you can manage to convince them :-)

Worse, they can select "never ask again" in the original request dialog. In that case, ActivityCompat.shouldShowRequestPermissionRationale returns false also. If you really want to, you can warn the user using a third dialog. However, in that case, the user themselves must manually enable the permission inside the Android settings activity. You can help them find this activity using an intent but they must manually check the permission once they have selected "never ask again".

dr_g
  • 1,179
  • 7
  • 10
  • Please see edit, i may not have been clear enough that i knew the code, I'm asking about how to deal with a practically crippled app. But you covered that better than anyone else as i forgot you could intent to settings. – Force Gaia Jun 23 '17 at 16:30
  • 1
    Ok I see, well then I would use a dialog each time your app starts up (if the permission has not been granted) that shows the rationale for why the permission is necessary and explaining that it must be manually enabled if they had chosen earlier to "never ask again". On the OK click listener, send them to the settings page via an Intent to manually enable it. In nearly all cases users will be fine with that. I would probably implement this in some custom Activity with a suitable warning theme before you enter the Main activity so it is clear the app's functionality is all but disabled. – dr_g Jun 26 '17 at 11:29
0

You can ask for permission when it starts like this:

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

        } else {
            ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RC_WRITE_EXTERNAL_STORAGE);
        }
    }

and if permission is not granted a dialog will show to grant permission that you can get the result in :

  @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode ==  RC_WRITE_EXTERNAL_STORAGE && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        }
    }
Meikiem
  • 1,876
  • 2
  • 11
  • 19
  • that's not what i'm asking. I know how to ask for the permissions. The issue is that if they deny it, the app is crippled and can't do anyhting past the main menu. What is the way to handle not having those permissions? – Force Gaia Jun 23 '17 at 15:07
  • you can show up a dialog when user does not give permission to grant permission again or to explain anything to the user – Meikiem Jun 23 '17 at 15:09
  • Please see edit, i may not have been clear enough that i knew the code as you're not the only one that did this, I'm asking about how to deal with a practically crippled app in the event that i recieve 'denied' always due to a "don't ask again" response – Force Gaia Jun 23 '17 at 16:26
0

Hope this answer helps: https://stackoverflow.com/a/40142454/4819445

You can handle that inside onRequestPermissionsResult()

Leenah
  • 850
  • 3
  • 15
  • 36
  • Please see edit, i may not have been clear enough that i knew the code, I'm asking about how to deal with a practically crippled app. – Force Gaia Jun 23 '17 at 16:25
0

step 1 :- add this permission in manifiest file

 android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
 android.Manifest.permission.READ_EXTERNAL_STORAGE,

step 2 : ask runtime permission

String permission = android.Manifest.permission.READ_EXTERNAL_STORAGE;
        if (ActivityCompat.checkSelfPermission(MainActivity.this, permission)!= PackageManager.PERMISSION_GRANTED ) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]
                    {permission}, PERMISSION_CODE);

        }

step 3: handle permsiion result

 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                   @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_CODE) {
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {


        Toast.makeText(this, "permission_granted_msg", Toast.LENGTH_SHORT).show();

    } else {

        Toast.makeText(this, "permission_not_granted_msg", Toast.LENGTH_SHORT).show();
    }
}

}

AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • Please see edit, i may not have been clear enough that i knew the code, I'm asking about how to deal with a practically crippled app. – Force Gaia Jun 23 '17 at 16:24