onRequestPermissionsResult not being called in fragment if defined in both fragment and activity

AndroidAndroid 6.0-Marshmallow

Android Problem Overview


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.

Android Solutions


Solution 1 - Android

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 .

Solution 2 - Android

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.

Solution 3 - Android

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/

Solution 4 - Android

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
)

Solution 5 - Android

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

Solution 6 - Android

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"

Solution 7 - Android

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

Solution 8 - Android

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

Solution 9 - Android

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

Solution 10 - Android

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 ...

Solution 11 - Android

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.

}

Solution 12 - Android

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

 fragment.requestPermissions(permissions, PERMISSIONS_CODE);

https://stackoverflow.com/questions/32714787/android-m-permissions-onrequestpermissionsresult-not-being-called/33080682#33080682

https://stackoverflow.com/questions/32890702/request-runtime-permissions-from-v4-fragment-and-have-callback-go-to-fragment

Solution 13 - Android

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

Solution 14 - Android

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

Solution 15 - Android

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

Solution 16 - Android

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 :)

Solution 17 - Android

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPrithniraj NicyoneView Question on Stackoverflow
Solution 1 - AndroidVarunJoshi129View Answer on Stackoverflow
Solution 2 - AndroidfullmoonView Answer on Stackoverflow
Solution 3 - AndroidFarruh HabibullaevView Answer on Stackoverflow
Solution 4 - AndroiddelayKgView Answer on Stackoverflow
Solution 5 - AndroidAlimItTechView Answer on Stackoverflow
Solution 6 - AndroidJuan Cruz SolerView Answer on Stackoverflow
Solution 7 - AndroidModern AndroidView Answer on Stackoverflow
Solution 8 - AndroidArian ShahpasandView Answer on Stackoverflow
Solution 9 - Androiduser2002721View Answer on Stackoverflow
Solution 10 - AndroidBiplob DasView Answer on Stackoverflow
Solution 11 - AndroidMFQView Answer on Stackoverflow
Solution 12 - AndroidNurseyit TursunkulovView Answer on Stackoverflow
Solution 13 - AndroiddianakarenmsView Answer on Stackoverflow
Solution 14 - AndroidRaj kannan IyyappanView Answer on Stackoverflow
Solution 15 - AndroidBohdan IshchenkoView Answer on Stackoverflow
Solution 16 - AndroidA.sobhdelView Answer on Stackoverflow
Solution 17 - AndroidManikandan KView Answer on Stackoverflow