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");
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.
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.
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'
}
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);
}
}
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);
}
}
}
}
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.
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:
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.
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);
}
}
}
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.