onRequestPermissionsResult not being called in dialog fragment
Asked Answered
C

11

61

I have started to work on Android M runtime permission. Here I am facing the issue that if requestPermissions is called from Dialog Fragment class then onRequestPermissionsResult not getting called in the same Dialog fragment class. But if requestPermissions is called from Activity class or Fragment class then onRequestPermissionsResult method get called in the same class.

Here is my sample 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;
    }

} 

Here in the code I am calling requestPermissions method of Dialog Fragment class. So I am expecting to get result in same class.

Any help is appreciated. Thanks in advance!


EDIT: Here I am adding more detail, so that it will be more helpful to others. Previously I have used getChildFragmentManager() to show the DialogFragment.

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

But As @CommonWare asked me to use activity to show the DialogFragment. I have made following changes and it works.

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getActivity().getSupportFragmentManager(), "Contact Picker");
Cathepsin answered 16/10, 2015 at 11:32 Comment(6)
Is this DialogFragment being shown by another fragment (i.e., nested fragments, getChildFragmentManager()) or by an activity directly?Vargo
It is shown by another Dialog fragment using getChildFragmentManager().Cathepsin
If I had to guess, the problem is more with the nested fragments, more so than it being a DialogFragment. You might try having the existing fragment tell the activity to show the DialogFragment, to see if the problem goes away.Vargo
Are you using native Fragments or the Support lib ?Narra
@Narra Support lib.Cathepsin
@Vargo you are absolutely right. Many thanks for helping me out. :-)Cathepsin
V
57

There appears to be a bug in Android, where nested fragments do not support the onRequestPermissionsResult() callback. For a DialogFragment, a workaround appears to be to have the fragment wanting to show the dialog call a method on the hosting activity, and the activity shows the DialogFragment itself.

Vargo answered 16/10, 2015 at 12:27 Comment(5)
I used acitivity class and build in android 6.0 using eclipse IDE, i call requestPermission(),but onRequestPermissionsResult() is not execute.Mair
@Mair The issue has been fixed in support library 23.3.0. If you’re using Support v4 Fragments, nested fragments will now receive callbacks to onRequestPermissionsResult().Kus
it works fine for me.need to use FragmentActivity in place of Activity.Mair
If I'm using nested fragment, is there any way to make the request & result handling both inside fragment? It's weird to handle the result in activity if I requested in fragment.Bushido
@BakaWaii: I avoid nested fragments. The bug is marked as fixed, though there are some comments suggesting that it is not completely fixed. If you are still experiencing these symptoms, ensure that there is an open issue for it. Otherwise, though, because I avoid nested fragments, I do not know if there is a workaround, besides those listed in the now-closed bug.Vargo
V
119

If you're inside a Fragment from support library, call requestPermissions() directly, and your Fragment's onRequestPermissionsResult() will be called back.

If you call ActivityCompat.requestPermissions(), then it's the Activity's onRequestPermissionsResult() that will be called back.

Varitype answered 16/11, 2015 at 6:41 Comment(6)
you can see in my code, I have used DialogFrament's requestPermissions() but onRequestPermissionsResult() is not getting called. As CommonsWare reported, nested fragments do not support the onRequestPermissionsResult() callback.Cathepsin
Thanks for this. I sure wish developer.android.com/training/permissions/requesting.html would have mentioned that android.support.v4.app.Fragment#requestPermissions even existsDecapolis
@dexxtr Obviously, as run-time permission requesting starts from API 23.Varitype
I'm not seeing onRequestPermissionsResult() being triggered as a result of Fragment.requestPermissions()Fanchie
It turns out that even though I have FragmentCompat.OnRequestPermissionsResultCallback implemented in my Fragment, and I'm calling Fragment.requestPermissions(), it's actually the parent ACTIVITY that receives onRequestPermissionsResult(). I think that's totally nonsensical.Fanchie
Yeah what a broken api for ActivityCompat. It's like spaghetti code, enforced by the framework.Chemosh
V
57

There appears to be a bug in Android, where nested fragments do not support the onRequestPermissionsResult() callback. For a DialogFragment, a workaround appears to be to have the fragment wanting to show the dialog call a method on the hosting activity, and the activity shows the DialogFragment itself.

Vargo answered 16/10, 2015 at 12:27 Comment(5)
I used acitivity class and build in android 6.0 using eclipse IDE, i call requestPermission(),but onRequestPermissionsResult() is not execute.Mair
@Mair The issue has been fixed in support library 23.3.0. If you’re using Support v4 Fragments, nested fragments will now receive callbacks to onRequestPermissionsResult().Kus
it works fine for me.need to use FragmentActivity in place of Activity.Mair
If I'm using nested fragment, is there any way to make the request & result handling both inside fragment? It's weird to handle the result in activity if I requested in fragment.Bushido
@BakaWaii: I avoid nested fragments. The bug is marked as fixed, though there are some comments suggesting that it is not completely fixed. If you are still experiencing these symptoms, ensure that there is an open issue for it. Otherwise, though, because I avoid nested fragments, I do not know if there is a workaround, besides those listed in the now-closed bug.Vargo
T
13

This issue seems to be fixed in Android Support Library 23.3.0 and above versions.

If you’re using Support v4 Fragments, nested fragments will now receive callbacks to onRequestPermissionsResult().

Edit: @AndrewS, here's how you can update.

In your build.gradle(app) file, change the following line to use the latest support library 24.0.0 which is the latest version:

dependencies {
    compile 'com.android.support:appcompat-v7:24.0.0'
}
Tilt answered 8/4, 2016 at 9:0 Comment(2)
how to update this library to 23.3.0? My studio says - no updates and current version is 23.2.1Myrmidon
@Myrmidon I have updated the answer explaining how to update.Tilt
M
6

EDIT:

I suggest to use a new version of Support Library 23.3.0, because Google fixed issue with not calling onRequestPermissionsResult, but if for some reasons you need to use an older version, then see origin answer below.

ORIGINAL ANSWER:

I am using next workaround (together with 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);
    }
}

Usage:

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);
    }
}
Meridional answered 4/3, 2016 at 10:52 Comment(0)
T
5

I had this problem without nested fragments, where the activity was showing the dialog fragment and the result was not getting passed.

Adding
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
to the Activity's onRequestPermissionsResult() solved the issue.

Trajan answered 2/9, 2016 at 20:27 Comment(0)
M
4

One thing that helped me was this. When you request permission from a nested fragment use getParent like so

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

and then override the parent fragment onRequestPermissionResult and check for the corresponding requestCode.

Hope it helps you as well.

Mauchi answered 23/11, 2015 at 16:3 Comment(0)
F
4

If you have problem with nested fragment, you can request permission from parent fragment

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

and then forward callback to child fragment

@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);
            }
        }
    }
}
Funk answered 8/2, 2016 at 11:33 Comment(3)
getParentFragment() returns null in a DialogFragment created on a fragmentDichromaticism
Seems to work for nested fragment when getParentFragment() != null.Illsorted
In my case getParentFragment() == null and List<Fragment> fragments is empty.Interdenominational
F
2

In addition to the end portion of Nino Handler's answer and for anyone still having issues with this, make sure that if you do override onRequestPermissionsResult in the parent activity/fragment of your dialog fragment, that you call super.onRequestPermissionsResult there.

I was overriding onRequestPermissionsResult in the parent activity of my dialog fragment, but neglected to call the super method there. Once I changed it to call the super method, it properly delegated down to the onRequestPermissionsResult in my dialog fragment.

Fluorene answered 2/12, 2018 at 11:24 Comment(0)
L
1

I got it done like this

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();
        }
    }
}

My Class Permission

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);
        }
    }
}
Leptosome answered 2/4, 2017 at 7:48 Comment(0)
C
1

If you have a look at the documentation of the fragment's requestPermissions method you will find out that you still have to declare the permissions in your Manifest:

enter image description here

If this is not the case the fragment's own onRequestPermissionsResult won't be invoked.

Instead, the activity's onRequestPermissionsResult is called but won't have any effect.

So grating a permission from within a fragment should be done as follows:

1. Declare the permission in your manifest

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

Enter this before the application tag.

2. Check for the permission in your fragment

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

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

3. Wait for the permission result in your 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. Make sure you don't override the activity's onRequestPermissionsResult

Overriding the activity's onRequestPermissionsResult will cause the fragment's one not to react.

Coyle answered 24/10, 2018 at 19:34 Comment(0)
J
0

I added android:noHistory="true" android:excludeFromRecents="true" in Android Manifest, It's work for me, I don't how it affects other functionality.

Jim answered 30/10, 2020 at 2:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.