Android M - vérifier l'autorisation d'exécution - comment déterminer si l'utilisateur a coché «Ne plus demander»?

307

Selon ceci: http://developer.android.com/preview/features/runtime-permissions.html#coding une application peut vérifier les autorisations d'exécution et demander des autorisations si elles n'ont pas déjà été accordées. La boîte de dialogue suivante s'affiche alors:

entrez la description de l'image ici

Dans le cas où l'utilisateur refuse une autorisation importante, imo une application doit afficher une explication de la raison pour laquelle l'autorisation est nécessaire et de l'impact de la baisse. Cette boîte de dialogue a deux options:

  1. réessayez (l'autorisation est à nouveau demandée)
  2. refuser (l'application fonctionnera sans cette autorisation).

Si l'utilisateur vérifie Never ask againcependant, la deuxième boîte de dialogue avec l'explication ne devrait pas être affichée, surtout si l'utilisateur a déjà refusé une fois auparavant. Maintenant, la question est: comment mon application sait-elle si l'utilisateur a vérifié le Never ask again? L'OMI onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)ne me donne pas cette information.

Une deuxième question serait: Google envisage-t-il d'intégrer un message personnalisé dans la boîte de dialogue d'autorisation qui expliquerait pourquoi l'application a besoin de l'autorisation? De cette façon, il n'y aurait jamais de deuxième dialogue qui ferait certainement une meilleure ux.

Emanuel Moecklin
la source
9
"Google prévoit-il d'incorporer un message personnalisé dans la boîte de dialogue d'autorisation qui expliquerait pourquoi l'application a besoin de l'autorisation?" - dans la présentation de Google I | O sur le système d'autorisation M, je me souviens que quelqu'un a demandé dans le Q & A, et la réponse était qu'ils y pensaient.
CommonsWare
1
Je ne l'ai pas testé moi-même, mais la documentation indique Activity.shouldShowRequestPermissionRationale (String): cette méthode renvoie true si l'application a déjà demandé cette autorisation et que l'utilisateur a refusé la demande. Cela indique que vous devez probablement expliquer à l'utilisateur pourquoi vous avez besoin de l'autorisation. Si l'utilisateur a refusé la demande d'autorisation dans le passé et choisi l'option Ne plus demander dans la boîte de dialogue système de demande d'autorisation, cette méthode renvoie false. La méthode renvoie également false si la stratégie de l'appareil interdit à l'application d'avoir cette autorisation.
Fraid
1
@Fraid: on dirait qu'ils ont ajouté cela avec l'aperçu # 2 d'Android M: developer.android.com/preview/support.html#preview2-notes et c'est probablement ce que je cherchais. Je ne peux pas le tester pour le moment mais le ferai la semaine prochaine. S'il fait ce que j'espère, vous pouvez le poster comme réponse et obtenir une certaine réputation. En attendant, cela pourrait aider les autres: youtube.com/watch?v=f17qe9vZ8RM
Emanuel Moecklin
exemple d'autorisations dangereuses et d'autorisations spéciales: github.com/henrychuangtw/AndroidRuntimePermission
HenryChuang
1
@Alex plus difficile pour les développeurs, c'est sûr, mais du point de vue de l'utilisateur, il est logique d'accorder ou de refuser des autorisations spécifiques. Le principal problème que je vois est que la granularité des autorisations est très incohérente et vous finissez par demander une autorisation qui pourrait n'avoir presque rien à voir avec ce que vous essayez de faire dans votre application (par exemple, l'autorisation des contacts lorsque je veux me connecter à Google Drive, car cela nécessite une liste des comptes d'appareils à des fins d'authentification et l'autorisation de compte fait partie du groupe d'autorisations de contact).
Emanuel Moecklin

Réponses:

341

Developer Preview 2 apporte quelques modifications à la façon dont les autorisations sont demandées par l'application (voir également http://developer.android.com/preview/support.html#preview2-notes ).

La première boîte de dialogue ressemble maintenant à ceci:

entrez la description de l'image ici

Il n'y a pas de case à cocher "Ne plus afficher" (contrairement à l'aperçu du développeur 1). Si l'utilisateur refuse l'autorisation et si l'autorisation est essentielle pour l'application, il pourrait présenter une autre boîte de dialogue pour expliquer la raison pour laquelle l'application demande cette autorisation, par exemple comme ceci:

entrez la description de l'image ici

Si l'utilisateur refuse à nouveau, l'application doit soit fermer si elle a absolument besoin de cette autorisation, soit continuer à fonctionner avec des fonctionnalités limitées. Si l'utilisateur reconsidère (et choisit de réessayer), l'autorisation est de nouveau demandée. Cette fois, l'invite ressemble à ceci:

entrez la description de l'image ici

La deuxième fois, la case à cocher "Ne plus demander" s'affiche. Si l'utilisateur refuse à nouveau et que la case est cochée, rien de plus ne devrait se produire. Le fait de cocher ou non la case à cocher peut être déterminé en utilisant Activity.shouldShowRequestPermissionRationale (String), par exemple comme ceci:

if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {...

C'est ce que dit la documentation Android ( https://developer.android.com/training/permissions/requesting.html ):

Pour vous aider à trouver les situations dans lesquelles vous devez fournir des explications supplémentaires, le système fournit la méthode Activity.shouldShowRequestPermissionRationale (String). Cette méthode renvoie true si l'application a déjà demandé cette autorisation et que l'utilisateur a refusé la demande. Cela indique que vous devez probablement expliquer à l'utilisateur pourquoi vous avez besoin de l'autorisation.

Si l'utilisateur a refusé la demande d'autorisation dans le passé et choisi l'option Ne plus demander dans la boîte de dialogue système de demande d'autorisation, cette méthode renvoie false. La méthode renvoie également false si la stratégie de l'appareil interdit à l'application d'avoir cette autorisation.

Pour savoir si l'utilisateur a refusé avec "ne plus jamais demander", vous pouvez vérifier à nouveau la méthode shouldShowRequestPermissionRationale dans votre onRequestPermissionsResult lorsque l'utilisateur n'a pas accordé l'autorisation.

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == REQUEST_PERMISSION) {
        // for each permission check if the user granted/denied them
        // you may want to group the rationale in a single dialog,
        // this is just an example
        for (int i = 0, len = permissions.length; i < len; i++) {
            String permission = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
            // user rejected the permission
                boolean showRationale = shouldShowRequestPermissionRationale( permission );
                if (! showRationale) {
                    // user also CHECKED "never ask again"
                    // you can either enable some fall back,
                    // disable features of your app
                    // or open another dialog explaining
                    // again the permission and directing to
                    // the app setting
                } else if (Manifest.permission.WRITE_CONTACTS.equals(permission)) {
                    showRationale(permission, R.string.permission_denied_contacts);
                    // user did NOT check "never ask again"
                    // this is a good place to explain the user
                    // why you need the permission and ask if he wants
                    // to accept it (the rationale)
                } else if ( /* possibly check more permissions...*/ ) {
                }
            }
        }
    }
}

Vous pouvez ouvrir les paramètres de votre application avec ce code:

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);

Il n'y a aucun moyen d'envoyer directement l'utilisateur à la page d'autorisation.

Emanuel Moecklin
la source
30
J'ai vérifié la valeur de retour de la méthode shouldShowRequestPermissionRationale () sur false pour vérifier si l'utilisateur a sélectionné "Ne plus demander". Mais je reçois également sa valeur comme fausse pour la toute première fois lorsque je demande la permission. Je ne suis donc pas en mesure de différencier si l'utilisateur a coché la case "Ne plus demander" ou non. Veuillez suggérer??
Sagar Trehan
32
Selon ma compréhension, la méthode shouldShowRationalePermissionRationale () renvoie false dans trois cas: 1. Si nous appelons cette méthode la première fois avant de demander la permission. 2. Si l'utilisateur sélectionne "Ne plus demander" et refuse l'autorisation. 3. Si la politique de l'appareil interdit à l'application d'avoir cette autorisation
Sagar Trehan
24
Tout va bien ... mais nous, développeurs, avons vraiment besoin de savoir si l'utilisateur a dit "ne plus jamais demander" ou non. J'ai un joli bouton pour accéder à une fonctionnalité. La première fois que l'utilisateur clique: devrait demander une justification? Non, demandez la permission. L'utilisateur nie. L'utilisateur clique à nouveau sur le bouton: justification? oui! Montrez la justification, l'utilisateur dit Ok, puis niez et ne demandez plus jamais (ok, c'est un idiot, mais les utilisateurs le sont souvent). Utilisateur ultérieur, appuyez à nouveau sur le bouton, justification? Non, demandez la permission, rien ne se passe pour l'utilisateur. J'ai vraiment besoin d'un moyen, là-bas, de dire à l'utilisateur: hé mec, si vous voulez cette fonctionnalité, allez maintenant dans le réglage de l'application et donnez la permission.
Daniele Segato
4
Super @EmanuelMoecklin c'est mieux que la documentation Google maintenant: D
Daniele Segato
4
onRequestPermissionsResult ne sera pas appelé à moins que vous ne demandiez l'autorisation. Puisqu'il n'y a pas de case à cocher "Ne plus demander" la première fois que l'autorisation est demandée, shouldShowRequestPermissionRationale retournera True (autorisation demandée mais sans jamais demander à nouveau). Par conséquent, la justification est toujours affichée la première fois que l'utilisateur rejette l'autorisation, mais ensuite seulement si la case n'est pas cochée.
Emanuel Moecklin
95

Vous pouvez enregistrer shouldShowRequestPermissionRationale()votre onRequestPermissionsResult().

shouldShowRequestPermissionRationale https://youtu.be/C8lUdPVSzDk?t=2m23s

Vérifiez si l'autorisation a été accordée ou non onRequestPermissionsResult(). Si pas alors vérifier shouldShowRequestPermissionRationale().

  1. Si cette méthode revient, truemontrez une explication de la raison pour laquelle cette autorisation particulière est nécessaire. Ensuite, selon le choix de l'utilisateur à nouveau requestPermissions().
  2. S'il revient, falseaffichez un message d'erreur indiquant que l'autorisation n'a pas été accordée et que l'application ne peut pas continuer ou qu'une fonctionnalité particulière est désactivée.

Voici un exemple de code.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case STORAGE_PERMISSION_REQUEST:
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted :)
                downloadFile();
            } else {
                // permission was not granted
                if (getActivity() == null) {
                    return;
                }
                if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    showStoragePermissionRationale();
                } else {
                    Snackbar snackbar = Snackbar.make(getView(), getResources().getString(R.string.message_no_storage_permission_snackbar), Snackbar.LENGTH_LONG);
                    snackbar.setAction(getResources().getString(R.string.settings), new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (getActivity() == null) {
                                return;
                            }
                            Intent intent = new Intent();
                            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package", getActivity().getPackageName(), null);
                            intent.setData(uri);
                            OrderDetailFragment.this.startActivity(intent);
                        }
                    });
                    snackbar.show();
                }
            }
            break;
    }
}

Apparemment, Google Maps fait exactement cela pour l'autorisation de localisation.

Abhinav Chauhan
la source
Merci pour la photo et le lien Youtube. Cela correspond plus ou moins à ma propre réponse. Il convient de noter que la question a été posée lorsque seul l'aperçu du développeur 1 était disponible sans la méthode shouldShowRequestPermissionRationale.
Emanuel Moecklin
Je suis nouveau sur Android et je veux surfer sur cette méthode onRequestPermissionsResult (). mais je reçois une erreur qu'il doit implémenter une méthode de type super. pouvez-vous dire comment utiliser cela
Andrain
39

Voici une méthode simple et agréable pour vérifier l'état actuel de l'autorisation:

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({GRANTED, DENIED, BLOCKED_OR_NEVER_ASKED })
    public @interface PermissionStatus {}

    public static final int GRANTED = 0;
    public static final int DENIED = 1;
    public static final int BLOCKED_OR_NEVER_ASKED = 2;

    @PermissionStatus 
    public static int getPermissionStatus(Activity activity, String androidPermissionName) {
        if(ContextCompat.checkSelfPermission(activity, androidPermissionName) != PackageManager.PERMISSION_GRANTED) {
            if(!ActivityCompat.shouldShowRequestPermissionRationale(activity, androidPermissionName)){
                return BLOCKED_OR_NEVER_ASKED;
            }
            return DENIED;
        }
        return GRANTED;
    }

Avertissement: renvoie BLOCKED_OR_NEVER_ASKED le premier démarrage de l'application, avant que l'utilisateur n'accepte / refuse l'autorisation via l'invite utilisateur (sur les appareils sdk 23+)

Mettre à jour:

La bibliothèque de support Android semble désormais également avoir une classe très similaire android.support.v4.content.PermissionCheckerqui contient un checkSelfPermission()qui renvoie:

public static final int PERMISSION_GRANTED = 0;
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_DENIED_APP_OP = -2;
Patrick Favre
la source
1
Pour le premier lancement, je stocke un booléen dans les préférences partagées.
Saeid Farivar
5
Cela revient toujours BLOCKED_OR_NEVER_ASKEDsi l'autorisation n'a pas encore été demandée.
Saket
6
oui, c'est la raison pour laquelle on l'appelle "BLOCKED_OR_NEVER_ASKED", voir aussi la dernière phrase
Patrick Favre
3
android.content.pmdéfinit déjà PERMISSION_GRANTED = 0et PERMISSION_DENIED = -1. Peut-être réglé BLOCKED_OR_NEVER_ASKED = PERMISSION_DENIED - 1ou quelque chose?
samis
Voir la réponse de mVck ci-dessous pour gérer la mise en garde.
samis
28

Une fois que l'utilisateur a coché «Ne plus demander», la question ne peut plus s'afficher. Mais il peut être expliqué à l'utilisateur qu'il a précédemment refusé l'autorisation et doit accorder l'autorisation dans les paramètres. Et référencez-le aux paramètres, avec le code suivant:

@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) {

    if (grantResults.length > 0
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // now, you have permission go ahead
        // TODO: something

    } else {

        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.READ_CALL_LOG)) {
            // now, user has denied permission (but not permanently!)

        } else {

            // now, user has denied permission permanently!

            Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), "You have previously declined this permission.\n" +
                "You must approve this permission in \"Permissions\" in the app settings on your device.", Snackbar.LENGTH_LONG).setAction("Settings", new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + BuildConfig.APPLICATION_ID)));

            }
        });
        View snackbarView = snackbar.getView();
        TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
        textView.setMaxLines(5);  //Or as much as you need
        snackbar.show();

        }

    }
    return;
}
רותם ריכטר
la source
dans la migration vers androidX, vous pouvez remplacer android.support.design.R par com.google.android.material.R
Ridha Rezzag
26

Peut être utile pour quelqu'un: -

Ce que j'ai remarqué, c'est que si nous vérifions l'indicateur shouldShowRequestPermissionRationale () dans la méthode de rappel onRequestPermissionsResult (), il n'affiche que deux états .

État 1: -Retournez true: - Chaque fois que l'utilisateur clique sur Refuser les autorisations (y compris la toute première fois).

Etat 2: -Retourne false: - si l'utilisateur sélectionne "ne demande plus".

Lien d'un exemple de travail détaillé

Nicks
la source
2
C'est la bonne façon de détecter si l'utilisateur a sélectionné l'option ne plus demander.
Muhammad Babar
Ah, la clé ici est que vous gérez cela dans le onRequestPermissionsResult, pas lorsque vous demandez réellement l'autorisation.
Joshua Pinter
26

Vous pouvez le déterminer en vérifiant si la justification de l' autorisation doit être affichée dans la onRequestPermissionsResult()méthode de rappel. Et si vous trouvez un ensemble d'autorisations à ne plus jamais demander , vous pouvez demander aux utilisateurs d'accorder des autorisations à partir des paramètres.

Ma mise en œuvre complète serait comme ci-dessous. Il fonctionne pour les demandes d'autorisations uniques ou multiples . Utilisez ce qui suit ou utilisez directement ma bibliothèque.

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(permissions.length == 0){
        return;
    }
    boolean allPermissionsGranted = true;
    if(grantResults.length>0){
        for(int grantResult: grantResults){
            if(grantResult != PackageManager.PERMISSION_GRANTED){
                allPermissionsGranted = false;
                break;
            }
        }
    }
    if(!allPermissionsGranted){
        boolean somePermissionsForeverDenied = false;
        for(String permission: permissions){
            if(ActivityCompat.shouldShowRequestPermissionRationale(this, permission)){
                //denied
                Log.e("denied", permission);
            }else{
                if(ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED){
                    //allowed
                    Log.e("allowed", permission);
                } else{
                    //set to never ask again
                    Log.e("set to never ask again", permission);
                    somePermissionsForeverDenied = true;
                }
            }
        }
        if(somePermissionsForeverDenied){
            final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
            alertDialogBuilder.setTitle("Permissions Required")
                    .setMessage("You have forcefully denied some of the required permissions " +
                            "for this action. Please open settings, go to permissions and allow them.")
                    .setPositiveButton("Settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                    Uri.fromParts("package", getPackageName(), null));
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                    })
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    })
                    .setCancelable(false)
                    .create()
                    .show();
        }
    } else {
        switch (requestCode) {
            //act according to the request code used while requesting the permission(s).
        }
    }
}
Nabin Bhandari
la source
hii @nabin mon exigence est lorsque je clique sur le bouton de téléchargement (qui télécharge le fichier pdf) que le temps de vérifier l'autorisation d'écriture est autorisé ou refusé, alors comment utiliser ce code! pouvez-vous me guider plz
Rucha Bhatt Joshi
bonjour @RuchaBhatt Jetez un oeil à ma bibliothèque. github.com/nabinbhandari/Android-Permissions
Nabin Bhandari
15

Si vous souhaitez détecter tous les "états" (refusés pour la première fois, simplement refusés, simplement refusés avec "Ne plus demander" ou refusés définitivement), vous pouvez procéder comme suit:

Créer 2 booléens

private boolean beforeClickPermissionRat;
private boolean afterClickPermissionRat;

Définissez le premier avant de demander la permission:

beforeClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Définissez le second dans votre méthode onRequestPermissionsResult:

afterClickPermissionRat = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);

Utilisez le "tableau" suivant pour faire tout ce dont vous avez besoin dans onRequestPermissionsResult () (après avoir vérifié que vous n'en avez toujours pas l'autorisation):

// before after
// FALSE  FALSE  =  Was denied permanently, still denied permanently --> App Settings
// FALSE  TRUE   =  First time deny, not denied permanently yet --> Nothing
// TRUE   FALSE  =  Just been permanently denied --> Changing my caption to "Go to app settings to edit permissions"
// TRUE   TRUE   =  Wasn't denied permanently, still not denied permanently --> Nothing
mVck
la source
Il est inutile de vérifier le shouldShowRequestPermissionRationale avant d'appeler requestPermissions à moins que vous ne vouliez montrer la justification avant de demander la permission. Cependant, montrer la justification uniquement après que l'utilisateur a refusé l'autorisation semble être la façon dont la plupart des applications la gèrent.
Emanuel Moecklin
2
@EmanuelMoecklin, pour autant que je sache, c'est le seul moyen de vérifier s'il a déjà été refusé (en le vérifiant avant et après, comme expliqué dans ma table de vérité) ou s'il s'agit d'un premier refus (dans mon cas, je redirige l'utilisateur vers les paramètres de l'application en cas de refus définitif)
mVck
1
// TRUE FALSEse produit également lorsque l'utilisateur autorise une autorisation après l'avoir préalablement refusée.
samis
11

J'ai eu le même problème et je l'ai compris. Pour vous simplifier la vie, j'ai écrit une classe util pour gérer les autorisations d'exécution.

public class PermissionUtil {
    /*
    * Check if version is marshmallow and above.
    * Used in deciding to ask runtime permission
    * */
    public static boolean shouldAskPermission() {
        return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
    }
private static boolean shouldAskPermission(Context context, String permission){
        if (shouldAskPermission()) {
            int permissionResult = ActivityCompat.checkSelfPermission(context, permission);
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true;
            }
        }
        return false;
    }
public static void checkPermission(Context context, String permission, PermissionAskListener listener){
/*
        * If permission is not granted
        * */
        if (shouldAskPermission(context, permission)){
/*
            * If permission denied previously
            * */
            if (((Activity)context).shouldShowRequestPermissionRationale(permission)) {
                listener.onPermissionPreviouslyDenied();
            } else {
                /*
                * Permission denied or first time requested
                * */
if (PreferencesUtil.isFirstTimeAskingPermission(context, permission)) {
                    PreferencesUtil.firstTimeAskingPermission(context, permission, false);
                    listener.onPermissionAsk();
                } else {
                    /*
                    * Handle the feature without permission or ask user to manually allow permission
                    * */
                    listener.onPermissionDisabled();
                }
            }
        } else {
            listener.onPermissionGranted();
        }
    }
/*
    * Callback on various cases on checking permission
    *
    * 1.  Below M, runtime permission not needed. In that case onPermissionGranted() would be called.
    *     If permission is already granted, onPermissionGranted() would be called.
    *
    * 2.  Above M, if the permission is being asked first time onPermissionAsk() would be called.
    *
    * 3.  Above M, if the permission is previously asked but not granted, onPermissionPreviouslyDenied()
    *     would be called.
    *
    * 4.  Above M, if the permission is disabled by device policy or the user checked "Never ask again"
    *     check box on previous request permission, onPermissionDisabled() would be called.
    * */
    public interface PermissionAskListener {
/*
        * Callback to ask permission
        * */
        void onPermissionAsk();
/*
        * Callback on permission denied
        * */
        void onPermissionPreviouslyDenied();
/*
        * Callback on permission "Never show again" checked and denied
        * */
        void onPermissionDisabled();
/*
        * Callback on permission granted
        * */
        void onPermissionGranted();
    }
}

Et les méthodes PreferenceUtil sont les suivantes.

public static void firstTimeAskingPermission(Context context, String permission, boolean isFirstTime){
SharedPreferences sharedPreference = context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE;
 sharedPreference.edit().putBoolean(permission, isFirstTime).apply();
 }
public static boolean isFirstTimeAskingPermission(Context context, String permission){
return context.getSharedPreferences(PREFS_FILE_NAME, MODE_PRIVATE).getBoolean(permission, true);
}

Maintenant, tout ce dont vous avez besoin est d'utiliser la méthode * checkPermission * avec les arguments appropriés.

Voici un exemple,

PermissionUtil.checkPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    new PermissionUtil.PermissionAskListener() {
                        @Override
                        public void onPermissionAsk() {
                            ActivityCompat.requestPermissions(
                                    thisActivity,
              new String[]{Manifest.permission.READ_CONTACTS},
                            REQUEST_EXTERNAL_STORAGE
                            );
                        }
@Override
                        public void onPermissionPreviouslyDenied() {
                       //show a dialog explaining permission and then request permission
                        }
@Override
                        public void onPermissionDisabled() {
Toast.makeText(context, "Permission Disabled.", Toast.LENGTH_SHORT).show();
                        }
@Override
                        public void onPermissionGranted() {
                            readContacts();
                        }
                    });

comment mon application sait-elle si l'utilisateur a coché la case "Ne plus demander"?

Si l'utilisateur a coché Ne plus demander , vous recevrez un rappel sur onPermissionDisabled .

Bon codage :)

muthuraj
la source
shouldShowRequestPermissionRationale J'ai une erreur ici, pouvez-vous m'aider.
Rucha Bhatt Joshi
je ne peux pas trouver cette méthode shouldShowRequestPermissionRationale peut être que je n'ai pas réussi à obtenir le contexte .. mais ça va, j'ai trouvé une autre solution alternative .. Merci de l'aide :)
Rucha Bhatt Joshi
1
Ma faute. shouldShowRequestPermissionRationale est disponible via Activity, pas dans le contexte. J'ai mis à jour ma réponse en convertissant le contexte en Activity avant d'appeler cette méthode. Allez voir :)
muthuraj
1
C'est le seul moyen de contourner la première fausse valeur renvoyée par shouldShowRequestPermissionRationale, en sauvegardant de préférence la requête envoyée à l'utilisateur. J'ai eu la même idée et trouvé votre réponse. Nice job man
MatPag
4

Explication complète pour chaque cas d'autorisation

/**
 *    Case 1: User doesn't have permission
 *    Case 2: User has permission
 *
 *    Case 3: User has never seen the permission Dialog
 *    Case 4: User has denied permission once but he din't clicked on "Never Show again" check box
 *    Case 5: User denied the permission and also clicked on the "Never Show again" check box.
 *    Case 6: User has allowed the permission
 *
 */
public void handlePermission() {
    if (ContextCompat.checkSelfPermission(MainActivity.this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        // This is Case 1. Now we need to check further if permission was shown before or not

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

            // This is Case 4.
        } else {
            // This is Case 3. Request for permission here
        }

    } else {
        // This is Case 2. You have permission now you can do anything related to it
    }
}

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        // This is Case 2 (Permission is now granted)
    } else {
        // This is Case 1 again as Permission is not granted by user

        //Now further we check if used denied permanently or not
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            // case 4 User has denied permission but not permanently

        } else {
            // case 5. Permission denied permanently.
            // You can open Permission setting's page from here now.
        }

    }
}
Saksham
la source
4

Une fonction utile pour déterminer si une autorisation arbitraire a été empêchée de demander (dans Kotlin):

private fun isPermissionBlockedFromAsking(activity: Activity, permission: String): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        return ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED
            && !activity.shouldShowRequestPermissionRationale(permission)
            && PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false)
    }
    return false
}

L'utilisation de cela nécessite de définir une préférence booléenne partagée avec le nom de votre autorisation souhaitée (par exemple android.Manifest.permission.READ_PHONE_STATE) truelorsque vous demandez une autorisation pour la première fois.


Explication:

Build.VERSION.SDK_INT >= Build.VERSION_CODES.M car une partie du code ne peut être exécutée qu'au niveau API 23+.

ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED pour vérifier nous n'avons pas déjà la permission.

!activity.shouldShowRequestPermissionRationale(permission)pour vérifier si l'utilisateur a de nouveau refusé l'application. En raison des particularités de cette fonction , la ligne suivante est également requise.

PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(permission, false) ceci est utilisé (avec la définition de la valeur true lors de la première demande d'autorisation) pour faire la distinction entre les états "Jamais demandé" et "Jamais demandé", car la ligne précédente ne renvoie pas ces informations.

JakeSteam
la source
4

La méthode shouldShowRequestPermissionRationale () peut être utilisée pour vérifier si l'utilisateur a sélectionné l'option «jamais demandé à nouveau» et a refusé l'autorisation. Il y a beaucoup d'exemples de code, donc je préfère expliquer comment l'utiliser à cette fin, car je pense que son nom et son implémentation rendent cela plus compliqué qu'il ne l'est réellement.

Comme expliqué dans Demande d'autorisations au moment de l'exécution , cette méthode renvoie true si l'option «ne plus demander» est visible, false sinon; il renvoie donc false la toute première fois qu'une boîte de dialogue est affichée, puis à partir de la deuxième fois, il renvoie true, et seulement si l'utilisateur refuse l'autorisation de sélectionner l'option, à ce stade, il renvoie à nouveau false.

Pour détecter un tel cas, vous pouvez soit détecter la séquence faux-vrai-faux, ou (plus simple) vous pouvez avoir un indicateur qui garde la trace de l'heure initiale d'affichage de la boîte de dialogue. Après cela, cette méthode renvoie true ou false, où false vous permettra de détecter lorsque l'option est sélectionnée.

Alessio
la source
3

Veuillez ne pas me jeter de pierres pour cette solution.

Cela fonctionne mais est un peu "hacky".

Lorsque vous appelez requestPermissions, enregistrez l'heure actuelle.

        mAskedPermissionTime = System.currentTimeMillis();

Puis dans onRequestPermissionsResult

si le résultat n'est pas accordé, vérifiez à nouveau l'heure.

 if (System.currentTimeMillis() - mAskedPermissionTime < 100)

Étant donné que l'utilisateur n'a pas pu cliquer si vite sur le bouton de refus, nous savons qu'il a sélectionné "ne plus jamais demander" car le rappel est instantané.

Utilisez à vos risques et périls.

Antzi
la source
que faire si nous voyons cette boîte de dialogue demandée pendant 5 minutes, puis la refuser?
saksham
Alors à quoi cela sert-il s'il ne peut pas satisfaire à l'exigence de base. Un code peut être un hack tel qu'il est accepté s'il remplit clairement toutes les exigences dans tous les autres cas.
saksham
Ouais c'est mauvais. Des testeurs automatiques comme celui-ci pourraient peut-être réussir à cliquer plus vite que cela: developer.android.com/training/testing/crawler
stackzebra
2

J'ai écrit un raccourci pour la demande d'autorisation dans Android M. Ce code gère également la rétrocompatibilité avec les anciennes versions d'Android.

Tout le code laid est extrait dans un fragment qui s'attache et se détache à l'activité demandant les autorisations.Vous pouvez utiliser PermissionRequestManagercomme suit:

new PermissionRequestManager()
        // We need a AppCompatActivity here, if you are not using support libraries you will have to slightly change 
        // the PermissionReuqestManager class
        .withActivity(this)

        // List all permissions you need
        .withPermissions(android.Manifest.permission.CALL_PHONE, android.Manifest.permission.READ_CALENDAR)

        // This Runnable is called whenever the request was successfull
        .withSuccessHandler(new Runnable() {
            @Override
            public void run() {
                // Do something with your permissions!
                // This is called after the user has granted all 
                // permissions, we are one a older platform where 
                // the user does not need to grant permissions 
                // manually, or all permissions are already granted

            }
        })

        // Optional, called when the user did not grant all permissions
        .withFailureHandler(new Runnable() {
            @Override
            public void run() {
                // This is called if the user has rejected one or all of the requested permissions
                L.e(this.getClass().getSimpleName(), "Unable to request permission");

            }
        })

        // After calling this, the user is prompted to grant the rights
        .request();

Jetez un œil: https://gist.github.com/crysxd/385b57d74045a8bd67c4110c34ab74aa

crysxd
la source
2
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case PERMISSIONS_REQUEST_EXTERNAL_STORAGE: {
            if (grantResults.length > 0) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                    // Denied
                } else {
                    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
                        // To what you want
                    } else {
                       // Bob never checked click
                    }
                }
            }
        }
    }
}
Vinod Ranga
la source
2

Essayez cette bibliothèque de permissions simple. Il gérera toutes les opérations liées à l'autorisation en 3 étapes faciles. Cela m'a fait gagner du temps. Vous pouvez terminer tous les travaux liés aux autorisations en 15 minutes .

Il peut gérer le refus, il peut gérer ne jamais demander à nouveau, il peut appeler les paramètres de l'application pour l'autorisation, il peut donner un message rationnel, il peut donner un message de refus, il peut donner une liste des autorisations acceptées, il peut donner une liste des refusés autorisations et etc.

https://github.com/ParkSangGwon/TedPermission

Étape 1: ajoutez votre dépendance

dependencies {
     compile 'gun0912.ted:tedpermission:2.1.1'
     //check the above link for latest libraries
}

Étape 2: demander des autorisations

TedPermission.with(this)
    .setPermissionListener(permissionlistener)
    .setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
    .setPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION)
    .check();

Étape 3: gérer la réponse d'autorisation

PermissionListener permissionlistener = new PermissionListener() {
    @Override
    public void onPermissionGranted() {
        Toast.makeText(MainActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onPermissionDenied(ArrayList<String> deniedPermissions) {
        Toast.makeText(MainActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
    }
};
Vignes
la source
Génial. Cela m'a fait gagner du temps
Vigneswaran A
Nice, easy to use
Uray Febri
2

vous pouvez écouter assez.

Auditeur

interface PermissionListener {
    fun onNeedPermission()
    fun onPermissionPreviouslyDenied(numberDenyPermission: Int)
    fun onPermissionDisabledPermanently(numberDenyPermission: Int)
    fun onPermissionGranted()
}

MainClass pour permission

class PermissionUtil {

    private val PREFS_FILENAME = "permission"
    private val TAG = "PermissionUtil"

    private fun shouldAskPermission(context: Context, permission: String): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val permissionResult = ActivityCompat.checkSelfPermission(context, permission)
            if (permissionResult != PackageManager.PERMISSION_GRANTED) {
                return true
            }
        }
        return false
    }

    fun checkPermission(context: Context, permission: String, listener: PermissionListener) {

        Log.i(TAG, "CheckPermission for $permission")

        if (shouldAskPermission(context, permission)) {

            // Load history permission
            val sharedPreference = context.getSharedPreferences(PREFS_FILENAME, 0)
            val numberShowPermissionDialog = sharedPreference.getInt(permission, 0)

            if (numberShowPermissionDialog == 0) {

                (context as? Activity)?.let {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(it, permission)) {
                        Log.e(TAG, "User has denied permission but not permanently")
                        listener.onPermissionPreviouslyDenied(numberShowPermissionDialog)
                    } else {
                        Log.e(TAG, "Permission denied permanently.")
                        listener.onPermissionDisabledPermanently(numberShowPermissionDialog)
                    }
                } ?: kotlin.run {
                    listener.onNeedPermission()
                }

            } else {
                // Is FirstTime
                listener.onNeedPermission()
            }


            // Save history permission
            sharedPreference.edit().putInt(permission, numberShowPermissionDialog + 1).apply()


        } else {
            listener.onPermissionGranted()
        }

    }
}

Utilisé de cette façon

      PermissionUtil().checkPermission(this, Manifest.permission.ACCESS_FINE_LOCATION,
                object : PermissionListener {
                    override fun onNeedPermission() {
                        log("---------------------->onNeedPermission")

//                            ActivityCompat.requestPermissions(this@SplashActivity,
//                                    Array(1) { Manifest.permission.ACCESS_FINE_LOCATION },
//                                    118)

                    }

                    override fun onPermissionPreviouslyDenied(numberDenyPermission: Int) {
                        log("---------------------->onPermissionPreviouslyDenied")
                    }

                    override fun onPermissionDisabledPermanently(numberDenyPermission: Int) {
                        log("---------------------->onPermissionDisabled")
                    }

                    override fun onPermissionGranted() {
                        log("---------------------->onPermissionGranted")
                    }

                })

remplacer onRequestPermissionsResult en activité ou fragmnet

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
 if (requestCode == 118) {
        if (permissions[0] == Manifest.permission.ACCESS_FINE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            getLastLocationInMap()
        }
        }
    }
Rasoul Miri
la source
1

Au lieu de cela, vous recevrez un rappel en onRequestPermissionsResult()tant que PERMISSION_DENIED lorsque vous demanderez à nouveau l'autorisation tout en tombant dans un état faux deshouldShowRequestPermissionRationale()

Depuis le document Android:

Lorsque le système demande à l'utilisateur d'accorder une autorisation, l'utilisateur a la possibilité de dire au système de ne plus demander cette autorisation. Dans ce cas, chaque fois qu'une application utilise requestPermissions()pour demander à nouveau cette autorisation, le système refuse immédiatement la demande. Le système appelle votre onRequestPermissionsResult()méthode de rappel et passe PERMISSION_DENIED, de la même manière que si l'utilisateur avait explicitement rejeté à nouveau votre demande. Cela signifie que lorsque vous appelez requestPermissions(), vous ne pouvez pas supposer qu'une interaction directe avec l'utilisateur a eu lieu.

Farhan
la source
1

Vous pouvez utiliser la if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)méthode pour détecter si jamais demander est coché ou non.

Pour plus de référence: vérifiez ceci

Pour vérifier plusieurs autorisations, utilisez:

  if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)
                                || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {
                            showDialogOK("Service Permissions are required for this app",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            switch (which) {
                                                case DialogInterface.BUTTON_POSITIVE:
                                                    checkAndRequestPermissions();
                                                    break;
                                                case DialogInterface.BUTTON_NEGATIVE:
                                                    // proceed with logic by disabling the related features or quit the app.
                                                    finish();
                                                    break;
                                            }
                                        }
                                    });
                        }
                        //permission is denied (and never ask again is  checked)
                        //shouldShowRequestPermissionRationale will return false
                        else {
                            explain("You need to give some mandatory permissions to continue. Do you want to go to app settings?");
                            //                            //proceed with logic by disabling the related features or quit the app.
                        }

expliquer () méthode

private void explain(String msg){
        final android.support.v7.app.AlertDialog.Builder dialog = new android.support.v7.app.AlertDialog.Builder(this);
        dialog.setMessage(msg)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        //  permissionsclass.requestPermission(type,code);
                        startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:com.exampledemo.parsaniahardik.marshmallowpermission")));
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                        finish();
                    }
                });
        dialog.show();
    }

Le code ci-dessus affichera également une boîte de dialogue, qui redirigera l'utilisateur vers l'écran des paramètres de l'application à partir duquel il peut donner l'autorisation s'il avait coché le bouton Ne plus demander

user6435056
la source
1

Vous pouvez utiliser

shouldShowRequestPermissionRationale()

à l'intérieur

onRequestPermissionsResult()

Voir l'exemple ci-dessous:

Vérifiez s'il a l'autorisation lorsque l'utilisateur clique sur le bouton:

@Override
public void onClick(View v) {
    if (v.getId() == R.id.appCompatBtn_changeProfileCoverPhoto) {
        if (Build.VERSION.SDK_INT < 23) { // API < 23 don't need to ask permission
            navigateTo(MainActivity.class); // Navigate to activity to change photos
        } else {
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    != PackageManager.PERMISSION_GRANTED) {
                // Permission is not granted yet. Ask for permission...
                requestWriteExternalPermission();
            } else {
                // Permission is already granted, good to go :)
                navigateTo(MainActivity.class);
            }
        } 
    }
}

Lorsque l'utilisateur répond à la boîte de dialogue d'autorisation, nous allons passer à onRequestPermissionResult:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == WRITE_EXTERNAL_PERMISSION_REQUEST_CODE) {
        // Case 1. Permission is granted.  
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  
            if (ContextCompat.checkSelfPermission(SettingsActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                // Before navigating, I still check one more time the permission for good practice.
                navigateTo(MainActivity.class);
            }
        } else { // Case 2. Permission was refused
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                // Case 2.1. shouldShowRequest... returns true because the
                // permission was denied before. If it is the first time the app is running we will 
                // end up in this part of the code. Because he need to deny at least once to get 
                // to onRequestPermissionsResult. 
                Snackbar snackbar = Snackbar.make(findViewById(R.id.relLayout_container), R.string.you_must_verify_permissions_to_send_media, Snackbar.LENGTH_LONG);
                snackbar.setAction("VERIFY", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        ActivityCompat.requestPermissions(SettingsActivity.this
                                , new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
                                , WRITE_EXTERNAL_PERMISSION_REQUEST_CODE);
                    }
                });
                snackbar.show();
            } else {
                // Case 2.2. Permission was already denied and the user checked "Never ask again". 
                // Navigate user to settings if he choose to allow this time.
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(R.string.instructions_to_turn_on_storage_permission)
                        .setPositiveButton(getString(R.string.settings), new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", getPackageName(), null);
                                settingsIntent.setData(uri);
                                startActivityForResult(settingsIntent, 7);
                            }
                        })
                        .setNegativeButton(getString(R.string.not_now), null);
                Dialog dialog = builder.create();
                dialog.show();
            }
        }
    }

}
Bientôt Santos
la source
0

Je souhaite également obtenir des informations, que l'utilisateur ait ou non sélectionné "ne plus jamais demander". J'ai atteint une «presque solution» avec un drapeau laid, mais avant de vous dire comment, je vais vous parler de ma motivation:

Je voudrais d'abord offrir la fonctionnalité de référence d'autorisation. Si l'utilisateur l'utilise et n'a aucun droit, il obtient soit la 1e boîte de dialogue par le haut, soit la 2e et la 3e. Lorsque l'utilisateur a choisi «Ne plus demander», je souhaite désactiver la fonctionnalité et l'afficher différemment. - Mon action est déclenchée par une entrée de texte spinner, je voudrais également ajouter «(Autorisation révoquée)» au texte de l'étiquette affiché. Cela montre à l'utilisateur: "Il y a des fonctionnalités mais je ne peux pas les utiliser, en raison de mes paramètres d'autorisation." Cependant, cela ne semble pas possible, car je ne peux pas vérifier si oui ou non "Ne plus demander" a été choisi.

Je suis arrivé à une solution avec laquelle je peux vivre en ayant toujours mes fonctionnalités activées avec une vérification d'autorisation active. J'affiche un message Toast dans onRequestPermissionsResult () en cas de réponse négative, mais uniquement si je n'ai pas affiché ma fenêtre contextuelle de justification personnalisée. Ainsi, si l'utilisateur a choisi "Ne plus jamais demander", il reçoit uniquement un message toast. Si l'utilisateur hésite à choisir `` ne plus jamais demander '', il n'obtient que la justification personnalisée et le popup de demande d'autorisation par le système d'exploitation, mais pas de toast, car trois notifications d'affilée seraient trop pénibles.

ChristianKoelle
la source
0

Je dois implémenter une autorisation dynamique pour la caméra. Où 3 cas possibles se produisent: 1. Autoriser, 2. Refusé, 3. Ne plus demander.

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    for (String permission : permissions) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission)) {
            //denied
            Log.e("denied", permission);
        } else {
            if (ActivityCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED) {
                //allowed
                Log.e("allowed", permission);
            } else {
                //set to never ask again
                Log.e("set to never ask again", permission);
                //do something here.
            }
        }
    }
    if (requestCode != MaterialBarcodeScanner.RC_HANDLE_CAMERA_PERM) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        return;
    }
    if (grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
        return;
    } else {
        //set to never ask again
        Log.e("set to never ask again", permissions[0]);
    }
    DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
        }
    };
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    builder.setTitle("Error")
            .setMessage(R.string.no_camera_permission)
            .setPositiveButton(android.R.string.ok, listener)
            .show();


}

private void insertDummyContactWrapper() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.CAMERA);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.CAMERA},
                    REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }
        mScannerView.setResultHandler(this);
        mScannerView.startCamera(mCameraId);
        mScannerView.setFlash(mFlash);
        mScannerView.setAutoFocus(mAutoFocus);
    }

private int checkSelfPermission(String camera) {
    if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) {
        return REQUEST_CODE_ASK_PERMISSIONS;
    } else {
        return REQUEST_NOT_CODE_ASK_PERMISSIONS;
    }
}
hitesh141
la source
0

Expansion sur mVck la réponse de ci-dessus, la logique suivante détermine si "Ne plus demander" a été vérifié pour une demande d'autorisation donnée:

bool bStorage = grantResults[0] == Permission.Granted;
bool bNeverAskForStorage =
    !bStorage && (
        _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
        _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
    );

qui est extrait d'en bas (pour l'exemple complet, voir cette réponse )

private bool _bStorageRationaleBefore;
private bool _bStorageRationaleAfter;        
private const int ANDROID_PERMISSION_REQUEST_CODE__SDCARD = 2;
//private const int ANDROID_PERMISSION_REQUEST_CODE__CAMERA = 1;
private const int ANDROID_PERMISSION_REQUEST_CODE__NONE = 0;

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode)
    {
        case ANDROID_PERMISSION_REQUEST_CODE__SDCARD:               
            _bStorageRationaleAfter = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
            bool bStorage = grantResults[0] == Permission.Granted;
            bool bNeverAskForStorage =
                !bStorage && (
                    _bStorageRationaleBefore == true  && _bStorageRationaleAfter == false ||
                    _bStorageRationaleBefore == false && _bStorageRationaleAfter == false
                );      
            break;                
    }
}

private List<string> GetRequiredPermissions(out int requestCode)
{
    // Android v6 requires explicit permission granting from user at runtime for security reasons            
    requestCode = ANDROID_PERMISSION_REQUEST_CODE__NONE; // 0
    List<string> requiredPermissions = new List<string>();

    _bStorageRationaleBefore = ShouldShowRequestPermissionRationale(Android.Manifest.Permission.WriteExternalStorage);
    Permission writeExternalStoragePerm = ApplicationContext.CheckSelfPermission(Android.Manifest.Permission.WriteExternalStorage);
    //if(extStoragePerm == Permission.Denied)
    if (writeExternalStoragePerm != Permission.Granted)
    {
        requestCode |= ANDROID_PERMISSION_REQUEST_CODE__SDCARD;
        requiredPermissions.Add(Android.Manifest.Permission.WriteExternalStorage);
    }

    return requiredPermissions;
}

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);

        // Android v6 requires explicit permission granting from user at runtime for security reasons
        int requestCode;
        List<string> requiredPermissions = GetRequiredPermissions(out requestCode);
        if (requiredPermissions != null && requiredPermissions.Count > 0)
        {
            if (requestCode >= ANDROID_PERMISSION_REQUEST_CODE__SDCARD)                    
            {
                _savedInstanceState = savedInstanceState;
                RequestPermissions(requiredPermissions.ToArray(), requestCode);
                return;
            }
        }
    }            

    OnCreate2(savedInstanceState);
}
Sam est
la source
0

Pour répondre précisément à la question, que se passe-t-il lorsque l'utilisateur appuie sur "Ne plus demander"?

La méthode / fonction remplacée

onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)

Le tableau grantResult se révèle être vide, vous pouvez donc y faire quelque chose? Mais pas la meilleure pratique.

Comment gérer "Ne plus demander"?

Je travaille avec Fragment, qui nécessitait l'autorisation READ_EXTERNAL_STORAGE.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        when {
            isReadPermissionsGranted() -> {

                /**
                 * Permissions has been Granted
                 */

                getDirectories()
            }

            isPermissionDeniedBefore() -> {

                /**
                 * User has denied before, explain why we need the permission and ask again
                 */

                updateUIForDeniedPermissions()
                checkIfPermissionIsGrantedNow()

            }
            else -> {

                /**
                 * Need to ask For Permissions, First Time
                 */

                checkIfPermissionIsGrantedNow()

                /**
                 * If user selects, "Dont Ask Again" it will never ask again! so just update the UI for Denied Permissions
                 */

                updateUIForDeniedPermissions()

            }
        }
    }

Les autres fonctions sont triviales.

// Is Read Write Permissions Granted
fun isReadWritePermissionGranted(context: Context): Boolean {
    return (ContextCompat.checkSelfPermission(
        context as Activity,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ) == PackageManager.PERMISSION_GRANTED) and
            (ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED)
}

fun isReadPermissionDenied(context: Context) : Boolean {
    return ActivityCompat.shouldShowRequestPermissionRationale(
        context as Activity,
        PermissionsUtils.READ_EXTERNAL_STORAGE_PERMISSIONS)
}
devDeejay
la source