234

I have a fragment in which I have recyclerview and setting data in this recyclerview using recyclerview adapter.

Now, I am having a button in the adapter's list item clicking on which I need to check the READ_EXTERNAL_STORAGE permission in android for new permission model in android.

I have created a new function in this adapter's fragment to check if permission is granted or not and request for permission if not granted already.

I have passed MyFragment.this as a parameter in the adapter and calling the fragment's method on the button click in the adapter.

I have used the below code to call requestPermission in fragment.

if(ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED){
       requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                ConstantVariables.READ_EXTERNAL_STORAGE);
    }

I have overridden the onRequestPermissionsResult method in fragment by using the below code:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case ConstantVariables.READ_EXTERNAL_STORAGE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, proceed to the normal flow.
                startImageUploading();
            } else {}

But it is not getting called, instead of this Activity's onRequestPermissionsResult method is getting called.

I have defined the same onRequestPermissionsResult method in fragment's parent activity also and it is getting called.

I can not remove the activity's onRequestPermissionsResult method but want to call fragment's onRequestPermissionsResult method when I request permission from fragment. How can I do this? Am I doing something wrong here, please help me if anyone have idea here.

Javid Sattar
  • 749
  • 8
  • 14
Prithniraj Nicyone
  • 5,021
  • 13
  • 52
  • 78
  • 1
    refer this link [run time permissions in fragment](http://stackoverflow.com/questions/34342816/android-6-0-multiple-permissions/38563687#38563687) This is the exact solution – Antony jackson Aug 12 '16 at 10:18

17 Answers17

458

Edited answer to cover broader issues

I think you are confusing the method for fragment and activity. Had a similar issue my project last month. Please check if you have finally the following:

  1. In AppCompatActivity use the method ActivityCompat.requestpermissions
  2. In v4 support fragment you should use requestpermissions
  3. Catch is if you call AppcompatActivity.requestpermissions in your fragment then callback will come to activity and not fragment
  4. Make sure to call super.onRequestPermissionsResult from the activity's onRequestPermissionsResult.

See if it helps .

justinvdk
  • 172
  • 2
  • 11
VarunJoshi129
  • 4,802
  • 1
  • 12
  • 10
  • 11
    Just to double check make sure you have super.onrequestpermissionresult set in your activity – VarunJoshi129 Mar 14 '16 at 20:06
  • 35
    Adding `super.onrequestpermissionresult` in activity's onrequestpermissionresult call the fragment's onrequestpermissionresult when I request permission using `requestpermissions`. This is working fine now, thank you so much.. :) – Prithniraj Nicyone Mar 15 '16 at 06:20
  • 2
    The super.onrequestpermissionresult was missing from the activity callback, leading to my fragment callback not getting called – sakis kaliakoudas Aug 08 '16 at 14:08
  • Number 3 and 4 were my issues. – Vahid Amiri Jan 12 '17 at 13:33
  • 4
    *requestPermissions()* requires API level 23. Is there another solution that is backwards compatible for API level 21? – AdamHurwitz Dec 22 '17 at 04:35
  • 1
    number 2 is my issue. I use ActivityCompat.requestPermissions instead of the one from v4 fragment. – zhaocong Feb 21 '18 at 07:03
  • 1
    I'm using API 26 and there is stil the same bug... my dialog ask for permission but the handler is caught in my main activity.... what should I do? – msc87 Feb 23 '18 at 13:48
  • 3
    @msc87 1. in onRequestPermissionsResult of activity and fragment , the first line should be : **super.onRequestPermissionsResult(requestCode, permissions, grantResults);** 2.in fragment where you are recognize the permission not granted just call requestPermission method like this : **requestPermissions(new String[]{Manifest.permission.CALL_PHONE}, MY_PERMISSIONS_REQUEST_CALL_PHONE);** – AREF Apr 07 '18 at 15:26
  • Solved my problem. We should find this details more often in the Official documentation! – AouledIssa Jul 02 '18 at 11:00
  • Number 4 is not actually propagates the call to fragment in the targetsdk 28. The SDK check and requestpermissions from fragment would work. – Raj kannan Iyyappan Sep 27 '18 at 02:58
  • Update: If you are using Jetpack Navigation in your project, then it not required to call super.onRequestPermissionsResult from the activity's onRequestPermissionsResult – Mehul Kanzariya Feb 20 '19 at 03:27
  • Once and for all, lets admin that Google screwed this up!. – JaydeepW May 21 '20 at 06:03
167

I requested location permission from a fragment and in the fragment, I needed to change this:

            ActivityCompat.requestPermissions(getActivity(), new String[]{
                Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_REQ_CODE);

to this:

            requestPermissions(new String[]{
                Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_REQ_CODE);

then the onRequestPermissionsResult was called in the fragment.

fullmoon
  • 8,030
  • 5
  • 43
  • 58
42

This is a common mistake that people make when coding for marshmallow.

When in AppCompatActivity, you should use ActivityCompat.requestPermissions; When in android.support.v4.app.Fragment, you should use simply requestPermissions (this is an instance method of android.support.v4.app.Fragment) If you call ActivityCompat.requestPermissions in a fragment, the onRequestPermissionsResult callback is called on the activity and not the fragment.

requestPermissions(permissions, PERMISSIONS_CODE);

If you are calling this code from a fragment it has it’s own requestPermissions method.

So basic concept is, If you are in an Activity, then call

ActivityCompat.requestPermissions(this,
                            new String[]{Manifest.permission.CAMERA},
                            MY_PERMISSIONS_REQUEST_CAMERA);

and if in a Fragment, just call

requestPermissions(new String[]{Manifest.permission.CAMERA},
                            MY_PERMISSIONS_REQUEST_CAMERA);

For the reference, I have obtained the answer from this link https://www.coderzheaven.com/2016/10/12/onrequestpermissionsresult-not-called-on-fragments/

Kishan Viramgama
  • 893
  • 1
  • 11
  • 23
Farruh Habibullaev
  • 2,342
  • 1
  • 26
  • 33
19

change this :

ActivityCompat.requestPermissions(
    activity,
    arrayOf(Manifest.permission.READ_CONTACTS),
    PERMISSIONS_REQUEST_READ_CONTACTS
)

to this :

requestPermissions(
     arrayOf(Manifest.permission.READ_CONTACTS),
     PERMISSIONS_REQUEST_READ_CONTACTS
)
delayKg
  • 206
  • 3
  • 5
  • 1
    The lower one is for use in a fragment (onRequestPermissionsResult is called in fragment), the ActivityCompat version is for use when the onRequestPermissionsResult is sited in the Activity. – Roar Grønmo Jul 02 '20 at 09:19
10

In fragment you shouldn't use ActivityCompat for requestPermissions and you just use requestPermissions and pass two parameters in method.

  1. String for permission
  2. RequestCode.

for exp :

 requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
AlimItTech
  • 172
  • 1
  • 9
6

The method requestPermissions on Fragments requires API level 23 or higher.
If your app targets a lower version you can use

FragmentCompat.requestPermissions(this,
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            ConstantVariables.READ_EXTERNAL_STORAGE);

First you need to add the support-v13 dependency:

implementation "com.android.support:support-v13:$supportLibVersion"
Juan Cruz Soler
  • 8,172
  • 5
  • 41
  • 44
6

You must call the Fragment.requestPermission() if you want to get into the onPermissionResult of your Fragment.

476rick
  • 2,764
  • 4
  • 29
  • 49
3

when we requestPermission from fragment the android change our requestCode in

requestPermissionsFromFragment

This is code from FragmetActivity :

 void requestPermissionsFromFragment(@NonNull Fragment fragment, @NonNull String[] permissions,
        int requestCode) {
    if (requestCode == -1) {
        ActivityCompat.requestPermissions(this, permissions, requestCode);
        return;
    }
    checkForValidRequestCode(requestCode);
    try {
        mRequestedPermissionsFromFragment = true;
        int requestIndex = allocateRequestIndex(fragment);
        ActivityCompat.requestPermissions(this, permissions,
                ((requestIndex + 1) << 16) + (requestCode & 0xffff));
    } finally {
        mRequestedPermissionsFromFragment = false;
    }
}

You Can See (requestIndex + 1) << 16) + (requestCode & 0xffff) and when

onRequestPermissionsResult

android check the request code if it was send from fragment it pass the result to fragment Other wise it don't pass it to fragment This is Code from FragmentActivity:

enter code here@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    mFragments.noteStateNotSaved();
    int index = (requestCode >> 16) & 0xffff;
    if (index != 0) {
        index--;

        String who = mPendingFragmentActivityResults.get(index);
        mPendingFragmentActivityResults.remove(index);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        Fragment frag = mFragments.findFragmentByWho(who);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            frag.onRequestPermissionsResult(requestCode & 0xffff, permissions, grantResults);
        }
    }
}

Summary

So if you call activity.requestPermission() or ActivityCompat.requestPermission it pass the result to your Activity And if you call fragment.requestPermission() it pass the result to your Activity AND Fragment

2
private void showContacts() {
 if (getActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
         != PackageManager.PERMISSION_GRANTED) {
     requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
             PERMISSIONS_REQUEST_READ_STORAGE);
 } else {
     doShowContacts();
 }
}

 @Override
 public void onRequestPermissionsResult(int requestCode, String[] permissions,
     int[] grantResults) {
 if (requestCode == PERMISSIONS_REQUEST_READ_STORAGE
         && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
     doShowContacts();
 }
 }

change permission

bharatk
  • 4,202
  • 5
  • 16
  • 30
user2002721
  • 159
  • 3
  • 9
  • 2
    Hi user2002721; your code might be correct, but with some context it would make a better answer; for example, you could explain how and why this proposed change would resolve the questioner's problem, perhaps including a link to the relevant documentation. That would make it more useful to them, and also more useful to other site readers who are looking for solutions to similar problems. – Vince Bowdren Dec 05 '16 at 16:28
  • The program might throw an array out of bounds exception if you try and access index 0 of grantResults without checking the length first. It happened to my program. I separated the if statement for grantResults as an inner if statement to prevent that from happening, and it works fine now. – Peter Griffin Aug 30 '18 at 05:42
2

This accepted answer is not worked for me, so i found my own solution, explained below:

1.First i created a method, in fragment:

public static void MyOnRequestPermissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
        if (requestCode == 1 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.d(TAG, "Permission: true");
        } else {
            Log.d(TAG, "permission: false");
        }
}

2.And then called it from its underlying activity:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if(requestCode ==1){
        SignupFragment.MyOnRequestPermissionResult(requestCode, permissions, grantResults);
    }
}

And it is working ...

Biplob Das
  • 2,818
  • 21
  • 13
2

you can call the Fragment method below

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_CODE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted. Continue the action or workflow
                // in your app.
                doActionBecauseNowYouCanBro();
            } else {
                // Explain to the user that the feature is unavailable because
                // the features requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
                showWhyRequestPermissionsAndDontBlockUserItsCalledManners();
            }
            return;
    }
    // Other 'case' lines to check for other
    // permissions this app might request.

}
MFQ
  • 839
  • 8
  • 14
1

If you are working with Kotlin you should exectly specify that you are calling fragment method, not activity

 fragment.requestPermissions(permissions, PERMISSIONS_CODE);

Android M Permissions: onRequestPermissionsResult() not being called

Request runtime permissions from v4.Fragment and have callback go to Fragment?

Nurseyit Tursunkulov
  • 8,012
  • 12
  • 44
  • 78
0

Verify that both PERMISSION_REQUEST_CODE inonRequestPermissionsResult and inside yourFragment contains the same value.

dianakarenms
  • 2,609
  • 1
  • 22
  • 22
0

For the tragetSDK 28,The SDK check (>23) and requestpermissions from fragment would work. The ActivityCompat.requestPermissions is failing (if you set request code below 65536, the permission dialog would appear and if the user allows the permission, the permissions are provided, but no callback will happen. But if you set above 65536, ActivityCompat.requestPermissions will fail immediately. i don't know the reasoning behind this logic. may be a bug or intentional).

Working code:

  if (Build.VERSION.SDK_INT >= 23) {
                        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, LOCATION_ACCESS_REQUEST);
                    }
  • you don't need to do the version check. in versions below 23, it'll just return the 'permission granted' value. Developer's choice here: avoid the 'if' block for simplicity or avoid the request call when not needed – Psest328 Nov 09 '18 at 18:23
0

I had the same issue. Your fragment can be initialized from the activity layout. Like that:

main_activty.xml

<fragment
    android:id="@+id/fragment"
    android:name="com.exampe.SomeFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

This issue was solved for me when I used FragmentTransaction instead

thor
  • 21,418
  • 31
  • 87
  • 173
0

in APIs below 23 you can create an interface in the activity then implement it in the child fragment and when you get permission request result in the activity pass it to the implemented interface in fragment. Its this simple :)

A.sobhdel
  • 234
  • 4
  • 11
-5

This issue was actually being caused by NestedFragments. Basically most fragments we have extend a HostedFragment which in turn extends a CompatFragment. Having these nested fragments caused issues which eventually were solved by another developer on the project.

He was doing some low level stuff like bit switching to get this working so I'm not too sure of the actual final solution

Manikandan K
  • 911
  • 9
  • 21
  • 4
    Instead of copying an answer, you could just provide a link - https://stackoverflow.com/a/33081173/630833 – jayeffkay Mar 01 '18 at 17:20