I would not negate the fact that "Nested Fragments do not receive request permissions (onRequestPermissionsResult()) callback"
.
But what I will do here is to explain the behavior observed by you regarding the different "weird" request codes received in the container activity for the requestPermissions()
made by the fragments and the nested fragments.
To explain this let's consider your example -
- HomeActivity (AppCompatActivity)
- FragmentA (V4 Fragment)
- ViewPager
- NestedFragmentA (V4 Fragment)
- NestedFragmentB (v4 Fragment)
- NestedFragmentC (v4 Fragment)
- NestedFragmentD (v4 Fragment)
- Fragment B (V4 Fragment)
- Fragment C (V4 Fragment)
Implement onRequestPermissionsResult()
only in HomeActivity, FragmentA and NestedFragmentA
for better understanding with logs printing the request code received
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Log.d("debug", "req code :: " + requestCode);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
Also request certain permission from FragmentA
and NestedFragmentA
. Let's take exmaple of location permissions
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 102);
Now whenever we requestPermissions()
from fragments or nested fragments, it calls Fragment class's requestPermissions()
which in turn calls FragmentHostCallback's onRequestPermissionsFromFragment()
which in turn calls FragmentActivity's requestPermissionsFromFragment()
. Now here lies the transformation of your request code.
After validating your request code, it calls
ActivityCompat's requestPermissions()
BUT
with the transformed request code -
ActivityCompat.requestPermissions(this, permissions,((fragment.mIndex + 1) << 8) + (requestCode & 0xff));
So the changed request code is -
((fragment.mIndex + 1) << 8) + (requestCode & 0xff)
where fragment.mIndex
is the fragment level . So for immediate fragment (means directly a child of the container activity), it will be "0"
and for immediate nested fragment(means the fragment immediately inside a fragment) it will be "1" and it will get incremented based on how deep your fragment is nested.
In our case, for FragmentA
, request code changes to
(((0 + 1) << 8) + (102 & 0xff)) which computes to 358
And for NestedFragmentA
, request code changes to
(((1 + 1) << 8) + (102 & 0xff)) which computes to 614
Now we know where the request code changes. Let's continue from ActivityCompat.requestPermissions()
. So we are aware of ActivityCompat.requestPermissions()
since we use this method to request permissions from activities.
Also, we know this will do some operations and the user will be shown the permission popup to accept/deny the requested permission.
Now we'll come to onRequestPermissionsResult()
. When the user will accept/deny then onRequestPermissionsResult()
of the container activity will get invoked because ultimately ActivityCompat.requestPermissions()
was called.
Let's say you accept/deny the permission from FragmentA
So you'll get the log-
req code ::358
After that
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
will invoke FragmentActivity's onRequestPermissionsResult()
which in turn performs some validation and call
frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
Bow you can see the request code passed in frag.onRequestPermissionsResult()
is different. requestCode
was 358
and after &0xff
it becomes 102
again.
Voila !!
That means although we got different request code (358
) in HomeActivity's onRequestPermissionsResult()
, yet we are calling FragmentA's onRequestPermissionsResult()
with the original request code (102
)
So we will get these logs from FragmentA
-
req code ::358
Now coming to NestedFragmentA
. Let's say you accept/deny the permission from NestedFragmentA
So you'll get the log in HomeActivity
-
req code ::614
But we know onRequestPermissionsResult()
will not be invoked for nested fragments so we won't get any logs in NestedFragmentA's onRequestPermissionsResult()
I guess I have explained the reason why we get different request codes in the container activity for the requestPermissions()
made by the fragment and nested fragments.
So I'd say that for the fragments which are not nested requestPermissions()
from the fragments only and implement onRequestPermissionsResult()
there only and not in the container activity.
For nested fragments, one should requestPermissions()
for the permissions required by the nested fragments from the parent fragment only . It seems this is the only workaround.