Prithniraj Nicyone
Prithniraj Nicyone

Reputation: 5111

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

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.

Upvotes: 239

Views: 115254

Answers (17)

Farruh Habibullaev
Farruh Habibullaev

Reputation: 2392

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/

Upvotes: 43

Modern Android
Modern Android

Reputation: 71

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

Upvotes: 6

Arian Shahpasand
Arian Shahpasand

Reputation: 300

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

Upvotes: 3

AlimItTech
AlimItTech

Reputation: 182

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

Upvotes: 10

MFQ
MFQ

Reputation: 878

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.

}

Upvotes: 3

delayKg
delayKg

Reputation: 216

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
)

Upvotes: 20

A.sobhdel
A.sobhdel

Reputation: 234

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

Upvotes: 0

Bohdan Ishchenko
Bohdan Ishchenko

Reputation: 89

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

Upvotes: 0

Nurseyit Tursunkulov
Nurseyit Tursunkulov

Reputation: 9370

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?

Upvotes: 1

Biplob Das
Biplob Das

Reputation: 3094

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

Upvotes: 2

user2002721
user2002721

Reputation: 159

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

Upvotes: 2

Raj kannan Iyyappan
Raj kannan Iyyappan

Reputation: 876

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

Upvotes: 0

Badr Bujbara
Badr Bujbara

Reputation: 8671

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.

Upvotes: 167

Juan Cruz Soler
Juan Cruz Soler

Reputation: 8254

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"

Upvotes: 6

dianakarenms
dianakarenms

Reputation: 2695

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

Upvotes: 0

Manikandan K
Manikandan K

Reputation: 921

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

Upvotes: -5

VarunJoshi129
VarunJoshi129

Reputation: 4852

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 .

Upvotes: 463

Related Questions