Reputation: 5111
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
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 simplyrequestPermissions (this is an instance method of android.support.v4.app.Fragment)
If you call ActivityCompat.requestPermissions in a fragment, theonRequestPermissionsResult
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
Reputation: 71
You must call the Fragment.requestPermission()
if you want to get into the onPermissionResult
of your Fragment.
Upvotes: 6
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
Reputation: 182
In fragment you shouldn't use ActivityCompat for requestPermissions and you just use requestPermissions and pass two parameters in method.
for exp :
requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
Upvotes: 10
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
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
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
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
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
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
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
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
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
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
Reputation: 2695
Verify that both PERMISSION_REQUEST_CODE
inonRequestPermissionsResult
and inside yourFragment
contains the same value.
Upvotes: 0
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
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:
super.onRequestPermissionsResult
from the activity's onRequestPermissionsResult
.See if it helps .
Upvotes: 463