web-dev-qa-db-fra.com

onRequestPermissionsResult n'étant pas appelé dans le fragment de dialogue

J'ai commencé à travailler sur les autorisations d'exécution d'Android M. Ici, je suis confronté au problème suivant: si requestPermissions est appelé depuis la classe Dialog Fragment, alors onRequestPermissionsResult ne sera pas appelé dans la même classe Dialog fragment. Mais si requestPermissions est appelé depuis la classe Activity ou la classe Fragment, la méthode onRequestPermissionsResult est appelée dans la même classe. 

Voici mon exemple de code:

public class ContactPickerDialog extends DialogFragment {
    private static final int READ_CONTACTS_REQUEST_CODE = 12;
    private Context mContext;

    private void loadContact() {
        if(hasPermission(mContext, Manifest.permission.READ_CONTACTS)){
            new ContactSyncTask().execute();
        } else {
            this.requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, READ_CONTACTS_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        Logger.d("TAG", "dialog onRequestPermissionsResult");
        switch (requestCode) {
            case READ_CONTACTS_REQUEST_CODE:
                // Check Permissions Granted or not
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    new ContactSyncTask().execute();
                } else {
                    // Permission Denied
                    Toast.makeText(getActivity(), "Read contact permission is denied", Toast.LENGTH_SHORT).show();
                }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    private static boolean hasPermission(Context context, String permission){
        return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
    }

} 

Ici, dans le code, j'appelle la méthode requestPermissions de la classe Dialog Fragment. Donc, je m'attends à obtenir un résultat dans la même classe.

Toute aide est appréciée. Merci d'avance!


EDIT: Ici, j'ajoute plus de détails pour que cela soit plus utile aux autres . Auparavant, j'avais utilisé getChildFragmentManager () pour afficher le DialogFragment.

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getChildFragmentManager(), "Contact Picker");

Mais comme @CommonWare m'a demandé d'utiliser l'activité pour afficher le DialogFragment. J'ai apporté les modifications suivantes et cela fonctionne.

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getActivity().getSupportFragmentManager(), "Contact Picker");
53
Dhaval Patel

Il semble y avoir un bogue dans Android , où les fragments imbriqués ne prennent pas en charge le rappel onRequestPermissionsResult(). Pour une DialogFragment, une solution de contournement semble être que le fragment veuille montrer à la boîte de dialogue appeler une méthode sur l'activité d'hébergement et que l'activité affiche la DialogFragment elle-même.

54
CommonsWare

Si vous êtes à l'intérieur d'une Fragment de la bibliothèque de support, appelez le requestPermissions() directement, et le onRequestPermissionsResult() de votre fragment sera rappelé.

Si vous appelez ActivityCompat.requestPermissions() , c'est la Activity ' onRequestPermissionsResult() qui sera rappelée.

105
minipif

Ce problème semble être résolu dans Android Support Library 23.3.0 et versions ultérieures.

Si vous utilisez des fragments de Support v4, les fragments imbriqués seront désormais recevoir des rappels à onRequestPermissionsResult ().

Edit: @AndrewS, voici comment vous pouvez mettre à jour.

Dans votre fichier build.gradle (app), modifiez la ligne suivante pour utiliser la dernière bibliothèque de support 24.0.0, qui est la dernière version:

dependencies {
    compile 'com.Android.support:appcompat-v7:24.0.0'
}
13

MODIFIER:

Je suggère d'utiliser une nouvelle version de Support Library 23.3.0, car Google a résolu le problème de ne pas appeler onRequestPermissionsResult , mais si, pour certaines raisons, vous devez utiliser une version plus ancienne, reportez-vous à la section Réponse d'origine ci-dessous.

RÉPONSE ORIGINALE:

J'utilise la solution suivante (avec easyPermissions library):

BaseFragment:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    /** child v4.fragments aren't receiving this due to bug. So forward to child fragments manually
     * https://code.google.com/p/Android/issues/detail?id=189121
     */
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    List<Fragment> fragments = getChildFragmentManager().getFragments();
    if (fragments != null) {
        // it is possible that fragment might be null in FragmentManager
        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
}

BaseActivity:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainer())
    if (fragment != null) {
        fragment.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
    }
}

Utilisation:

public class SomeFragment extends BaseFragment implements EasyPermissions.PermissionCallbacks {
    private static final int PICK_CONTACT = 1;
    private static final int READ_CONTACTS_PERM = 2;

    // some code

    @AfterPermissionGranted(READ_CONTACTS_PERM)
    private void pickContactWithPermissionsCheck() {
        if (EasyPermissions.hasPermissions(getContext(), Manifest.permission.READ_CONTACTS)) {
            // Have permission
            pickContactForResult();
        } else {
            // Request one permission
            EasyPermissions.requestPermissions(this, getString(R.string.read_contacts_permission_explanation),
                    READ_CONTACTS_PERM, Manifest.permission.READ_CONTACTS);
        }
    }

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

        // FIXME problem with incorrect requestCode coming to callback for Nested fragments
        // More information here - https://code.google.com/p/Android/issues/detail?id=189121
        if (isVisible() && Arrays.asList(permissions).contains(Manifest.permission.READ_CONTACTS)) {
            requestCode = READ_CONTACTS_PERM;
        }

        // EasyPermissions handles the request result.
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }
}
5
Oleksandr

Si vous avez un problème avec le fragment imbriqué, vous pouvez demander l’autorisation du fragment parent.

getParentFragment().requestPermissions(new String[]{permission}, requestCode);

puis transférez le rappel vers le fragment enfant

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grants) {
    List<Fragment> fragments = getChildFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grants);
            }
        }
    }
}
4
Artem

Une chose qui m'a aidé était ceci. Lorsque vous demandez l’autorisation d’un fragment imbriqué, utilisez getParent comme suit

 fragment.getParentFragment().requestPermissions((new String[]
              {Manifest.permission.READ_CONTACTS}), requestCode);

puis substituez le fragment parent onRequestPermissionResult et recherchez le requestCode correspondant.

J'espère que cela vous aidera aussi.

4
udit

Si vous consultez la documentation de la méthode requestPermissions du fragment, vous constaterez qu'il vous reste à déclarer les autorisations dans votre manifeste:

 enter image description here

Si ce n'est pas le cas, la propre variable onRequestPermissionsResult du fragment ne sera pas appelée.

Au lieu de cela, la onRequestPermissionsResult de l'activité est appelée mais n'aura aucun effet.

Donc, râper une permission dans un fragment devrait être fait comme suit:

1. Déclarez la permission dans votre manifeste

<uses-permission Android:name="Android.permission.CAMERA"/>

Entrez ceci avant la balise d'application.

2. Recherchez la permission dans votre fragment

if (ActivityCompat.checkSelfPermission(context, permission) 
        != PackageManager.PERMISSION_GRANTED) {

    requestPermissions(
        arrayOf(Manifest.permission.CAMERA), 
        REQUEST_CODE_CAMERA_PERMISSION)
}

3. Attendez le résultat de la permission dans votre fragment

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    when (requestCode) {
        REQUEST_CODE_CAMERA_PERMISSION -> { 

        val granted = grantResults.isNotEmpty()
            && permissions.isNotEmpty()
            && grantResults[0] == PackageManager.PERMISSION_GRANTED
            && !ActivityCompat.shouldShowRequestPermissionRationale(activity, permissions[0])    

        when (granted) {
            true -> openCamera()
            else -> proceedWithoutPermission()
        }
    }
}

4. Assurez-vous de ne pas remplacer leonRequestPermissionsResult de l'activité

Remplacer onRequestPermissionsResult de l'activité empêchera celle du fragment de réagir.

1
Nino Handler

Je l'ai fait comme ça

public class DialogFragmentSMS extends DialogFragment implements View.OnClickListener {

public static DialogFragmentSMS frag;
private static View view;
private static ViewGroup parent;
private EditText editTextMensagem;
private String celular;

private final static int SMS_REQUEST = 20;

public DialogFragmentSMS() {

}
public static DialogFragmentSMS newInstance(String celular)
{

    Bundle args = new Bundle();
    args.putString("celular", celular);
    frag = new DialogFragmentSMS();
    frag.setArguments(args);
    return frag;
}

@Override
public void onCreate(Bundle saveInstaceState)
{
    super.onCreate(saveInstaceState);
}

    @Override
public void onClick(View v) {
    if (!PermissaoUtils.hasPermission(getActivity(), Manifest.permission.SEND_SMS)) {
        //PermissaoUtils.requestPermissions(getActivity(), new String[]{Manifest.permission.SEND_SMS}, SMS_REQUEST);
        frag.requestPermissions(new String[]{Manifest.permission.SEND_SMS}, SMS_REQUEST);
    }else{
        if (validaCampos()) {
            SmsManager smsManager = SmsManager.getDefault();
            smsManager.sendTextMessage("0" + celular, null, editTextMensagem.getText().toString(), null, null);
            Toast.makeText(getActivity(), R.string.sms_enviado, Toast.LENGTH_SHORT).show();
            getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
            frag.dismiss();
        }
    }
}

Ma permission de classe

public class PermissaoUtils
{
    public static boolean useRunTimePermissions() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.Lollipop_MR1;
    }

    public static boolean hasPermission(Activity activity, String permission) {
        if (useRunTimePermissions()) {
            return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
        }
        return true;
    }

    public static void requestPermissions(Activity activity, String[] permission, int requestCode) {
        if (useRunTimePermissions()) {
            activity.requestPermissions(permission, requestCode);
        }
    }
}
0
Leonardo Inhoqui

En plus de la partie finale de la réponse de Nino Handler et des personnes ayant toujours des problèmes avec cela, assurez-vous que si vous remplacez onRequestPermissionsResult dans l'activité/le fragment parent de votre fragment de boîte de dialogue, appelez super.onRequestPermissionsResult.

Je remplaçais onRequestPermissionsResult dans l'activité parente de mon fragment de dialogue, mais j'ai négligé d'appeler la super-méthode à cet endroit. Une fois que j'ai changé pour appeler la super-méthode, elle a été déléguée correctement au résultat onRequestPermissionsResult dans mon fragment de boîte de dialogue.

0
D.J.M. Francis