onRequestPermissionsResult not being called in fragment if defined in both fragment and activity
Asked Answered
C

17

237

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.

Christianism answered 14/3, 2016 at 13:47 Comment(1)
refer this link run time permissions in fragment This is the exact solutionSung
T
460

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 .

Thermion answered 14/3, 2016 at 20:1 Comment(12)
Just to double check make sure you have super.onrequestpermissionresult set in your activityThermion
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.. :)Christianism
The super.onrequestpermissionresult was missing from the activity callback, leading to my fragment callback not getting calledUnruly
Number 3 and 4 were my issues.Essentiality
requestPermissions() requires API level 23. Is there another solution that is backwards compatible for API level 21?Edmanda
number 2 is my issue. I use ActivityCompat.requestPermissions instead of the one from v4 fragment.Charlie
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?Expiration
@Expiration 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);Hypogenous
Solved my problem. We should find this details more often in the Official documentation!Facelifting
Number 4 is not actually propagates the call to fragment in the targetsdk 28. The SDK check and requestpermissions from fragment would work.Scalpel
Update: If you are using Jetpack Navigation in your project, then it not required to call super.onRequestPermissionsResult from the activity's onRequestPermissionsResultQuartana
Once and for all, lets admin that Google screwed this up!.Persistence
P
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.

Pyxidium answered 4/8, 2018 at 12:25 Comment(3)
Works like a charm :)Hoopen
it's not working with kotlin can you please help me for the same here is used this requestPermissions(context as Activity ,permissionList.toTypedArray(), MY_PERMISSIONS_REQUEST)Maimaia
Thanks :),you save my timeDissuasive
B
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/

Bathsheeb answered 30/11, 2019 at 8:38 Comment(0)
D
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
)
Dermot answered 29/3, 2020 at 7:41 Comment(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.Wouldbe
S
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);
Schach answered 18/8, 2020 at 12:24 Comment(0)
H
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"
Hakim answered 9/2, 2018 at 20:40 Comment(1)
FragmentCompat is deprecated from version 27.1.0Scalpel
S
6

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

Spires answered 12/1, 2021 at 17:48 Comment(0)
G
3

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.

}
Gabardine answered 6/7, 2020 at 7:43 Comment(0)
P
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

Peat answered 26/12, 2020 at 10:1 Comment(0)
G
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

Gilbertogilbertson answered 5/12, 2016 at 14:35 Comment(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.Avirulent
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.Agace
G
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 ...

Gebhart answered 1/10, 2019 at 9:24 Comment(0)
B
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?

Burtis answered 19/11, 2019 at 14:45 Comment(0)
C
0

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

Carrasco answered 9/6, 2017 at 18:25 Comment(0)
S
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);
                    }
Scalpel answered 27/9, 2018 at 3:9 Comment(1)
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 neededDominiquedominium
S
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

Stated answered 20/12, 2019 at 21:9 Comment(0)
F
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 :)

Fornix answered 7/2, 2020 at 10:28 Comment(0)
B
-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

Bendicty answered 22/9, 2016 at 5:29 Comment(1)
Instead of copying an answer, you could just provide a link - https://mcmap.net/q/88413/-android-m-permissions-onrequestpermissionsresult-not-being-calledThistle

© 2022 - 2024 — McMap. All rights reserved.