Android M Permissions: onRequestPermissionsResult() not being called

JavaAndroidPermissionsAndroid Permissions

Java Problem Overview


I'm updating our app to use the new M runtime permissions system. It's all working except for onRequestPermissionsResult(). I need to check a permission on a button press, and if it's successful, send a text message. When I grant permission to do it, the dialog closes, but it doesn't trigger the Send Text until I press the button again.

I've debugged and set breakpoints in the onRequestPermissionsResult() method but it never goes into it.

This method gets called first:

    private void askForPermission() {
    String[] permissions = new String[]{Manifest.permission.SEND_SMS};
    ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE);
}

And then my callback looks like this:

    @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == PERMISSIONS_CODE) {
        for (int i = 0; i < permissions.length; i++) {
            String permission = permissions[i];
            int grantResult = grantResults[i];

            if (permission.equals(Manifest.permission.SEND_SMS)) {
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    onPPSButtonPress();
                } else {
                    requestPermissions(new String[]{Manifest.permission.SEND_SMS}, PERMISSIONS_CODE);
                }
            }
        }
    }
}

Has anybody run into a similar issue? Appreciate any help with this. Thanks

Java Solutions


Solution 1 - Java

I ran into the same issue and I just found the solution. When using the Support library, you have to use the correct method calls. For example:

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

Solution 2 - Java

You can try this:

requestPermissions(permissions, PERMISSIONS_CODE);

If you are calling this code from a fragment it has it's own requestPermissions method. I believe the problem is that you are calling static method.

Pro Tip if you want the onRequestPermissionsResult() in a fragment: FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)

Solution 3 - Java

I hope it works fine

For Activity :

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);
                

For Fragment :

 requestPermissions(permissionsList,REQUEST_CODE);

Solution 4 - Java

I encountered this problem too. If you want the activity that handles permissions not in the history/recents, then you will be tempted to change your AndroidManifest.xml entry.

If you set the activity that you call requestPermissions or AppCompatActivity.requestPermissions with

android:noHistory="true"
android:excludeFromRecents="true"

in your AndroidManifest.xml then onRequestPermissionsResult() will not be called. This is true if your Activity is derived from Activity or AppCompatActivity.

This can be fixed by removing both flags from 'AndroidManifest.xml' and finishing your activity with finishAndRemoveTask() instead.

Solution 5 - Java

If you have onRequestPermissionsResult in both activity and fragment, make sure to call super.onRequestPermissionsResult in activity. It is not required in fragment, but it is in activity.

Solution 6 - Java

Answer deprecated please refer to : https://developer.android.com/training/permissions/requesting

Inside fragment, you need to call:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

Not:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);

Solution 7 - Java

If you are using requestPermissions in fragment, it accepts 2 parameters instead of 3.

You should use requestPermissions(permissions, PERMISSIONS_CODE);

Solution 8 - Java

If for some reason you have extended a custom Activity located in some external library that do not call the super you will need to manually call the Fragment super.onRequestPermissionsResult yourself in your Activity onRequestPermissionsResult.

YourActivity extends SomeActivityNotCallingSuperOnRequestPermissionsResult{
Fragment requestingFragment;//the fragment requesting the permission
...
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestingFragment!=null)
            requestingFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
...

Solution 9 - Java

You have the checkPermissions function for pre Marshmallow devices in FragmentCompat. I use like this:

FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

Solution 10 - Java

I have found out that is important where you call android.support.v4.app.Fragment.requestPermissions.

If you do it in onCreate(), onRequestPermissionsResult() is never called.

Solution: Call it in onActivityCreated();

@Override
public void onActivityCreated(Bundle savedInstanceState) {
	
	super.onActivityCreated(savedInstanceState);
	
	if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_DENIED) 
 		requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);
    
}

Solution 11 - Java

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

Solution 12 - Java

 /* use the object of your fragment to call the 
 * onRequestPermissionsResult in fragment after
 * in activity and use different request Code for 
 * both Activity and Fragment */

   if (isFragment)
    mFragment.requestPermissions(permissions.toArray(new
    String[permissions.size()]),requestPermission);
  
   else
    ActivityCompat.requestPermissions(mActivity,permissions.toArray(new
    String[permissions.size()]),requestPermission);

Solution 13 - Java

This will work..

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

Solution 14 - Java

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,
                            permissionsList,
                            permissionscode);

and if in a Fragment, just call

requestPermissions(permissionsList,
                            permissionscode);

Solution 15 - Java

I had a similar problem except I was pressing a button to make a call, which triggers the callIntent. I checked permission first, if not granted I ask for permission and onRequestPermissionResult I call the check permission and call again.

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case Constants.PERMISSIONS_REQUEST_CALL_PHONE: {
            if ( grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                checkPermissionsAndCall();
            }
        }
    }
}

public void checkPermissionsAndCall(){
    if (Build.VERSION.SDK_INT > 22) {
        if(ContextCompat.checkSelfPermission(getContext(),
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED){
            requestPermissions( new String[]{Manifest.permission.CALL_PHONE}, Constants.PERMISSIONS_REQUEST_CALL_PHONE);
        }
        else{
            callIntent();
        }
    }
}

Solution 16 - Java

Based on goodgamerguy's answer the solution is:

myFragment.this.requestPermissions(....)

Solution 17 - Java

Before you check everything according to above answers, make sure your request code is not 0!!!

check the code of onRequestPermissionsResult() in FragmentActivity.java:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    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);
        }
    }
}

Solution 18 - Java

private void showContacts() {
	if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
	 	!= PackageManager.PERMISSION_GRANTED) {
		requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
	} else {
		doShowContacts();
	}
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
	if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
		doShowContacts();
	}
}

Solution 19 - Java

I have an amazing solution to achieve this make a BaseActivity like this.

public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));


}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case 1: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                CustomToast.getInstance().setCustomToast("Now you can share the Hack.");

            } else {
                Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

}

Now yo can call the code to ask for permission like this

 ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

Now every time this happens anywhere whether in your fragment or in any activity the base activity would be called.

Thanks

Solution 20 - Java

You can use requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);. Do not use FragmentCompat if you are using v4.

Solution 21 - Java

UPDATE: saw someone else's answer about calling super.onRequestPermissionResult() in Activity and that fixes the request code issue I mentioned and calls the fragment's onRequestPermissionResult.

ignore this stuff:

For me it was calling the onRequestPermissionResult of the Activity despite me calling fragment.requestPermission(...), BUT it returned the result with an incorrect requestCode (111 turned into 65647 why ??? I'll never know).

Luckily this is the only permission we request on that screen so I just ignore the request code (don't have time to figure out why it's not correct right now)

Solution 22 - Java

Details

  • Kotlin 1.2.70
  • checked in minSdkVersion 19
  • Android studio 3.1.4

Algorithm

module - camera, location, ....

  1. Check if hasSystemFeature (if module exist in phone)
  2. Check if user has access to module
  3. Send permissions request (ask user to allow module usage)

Features

  1. Work with Activities and Fragments
  2. Has only one result response
  3. Can check several modules in one request

Solution

class PermissionType(val manifest_permission: String, val packageManager: String) {
    object Defined {
        val camera = PermissionType(Manifest.permission.CAMERA, PackageManager.FEATURE_CAMERA)
        val currentLocation = PermissionType(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.FEATURE_LOCATION_GPS)
    }
}

class  Permission {

    enum class PermissionResult {
        ACCESS_ALLOWED, ACCESS_DENIED, NO_SYSTEM_FEATURE;
    }

    interface ManagerDelegate {
        fun permissionManagerDelegate(result: Array<Pair<String, PermissionResult>>)
    }

    class Manager internal constructor(private val delegate: ManagerDelegate?) {

        private var context: Context? = null
        private var fragment: Fragment? = null
        private var activity: AppCompatActivity? = null
        private var permissionTypes: Array<PermissionType> = arrayOf()
        private val REQUEST_CODE = 999
        private val semaphore = Semaphore(1, true)
        private var result: Array<Pair<String, PermissionResult>> = arrayOf()


        constructor(permissionType: PermissionType, delegate: ManagerDelegate?): this(delegate) {
            permissionTypes = arrayOf(permissionType)
        }

        constructor(permissionTypes: Array<PermissionType>, delegate: ManagerDelegate?): this(delegate) {
            this.permissionTypes = permissionTypes
        }

        init {
            when (delegate) {
                is Fragment -> {
                    this.fragment = delegate
                    this.context = delegate.context
                }

                is AppCompatActivity -> {
                    this.activity = delegate
                    this.context = delegate
                }
            }
        }

        private fun hasSystemFeature(permissionType: PermissionType) : Boolean {
            return context?.packageManager?.hasSystemFeature(permissionType.packageManager) ?: false
        }

        private fun hasAccess(permissionType: PermissionType) : Boolean {
            return if (Build.VERSION.SDK_INT < 23) true else {
                context?.checkSelfPermission(permissionType.manifest_permission) == PackageManager.PERMISSION_GRANTED
            }
        }

        private fun sendRequest(permissionTypes: Array<String>) {

            if (fragment != null) {
                fragment?.requestPermissions(permissionTypes, REQUEST_CODE)
                return
            }

            if (activity != null){
                ActivityCompat.requestPermissions(activity!!, permissionTypes, REQUEST_CODE)
            }
        }

        fun check() {

            semaphore.acquire()
            AsyncTask.execute {
                var permissionsForSendingRequest: Array<String> = arrayOf()
                this.result = arrayOf()

                for (it in permissionTypes) {
                    if (!hasSystemFeature(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.NO_SYSTEM_FEATURE)
                        continue
                    }

                    if (hasAccess(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                    } else {
                        permissionsForSendingRequest += it.manifest_permission
                    }
                }

                if (permissionsForSendingRequest.isNotEmpty()) {
                    sendRequest(permissionsForSendingRequest)
                } else {
                    delegate?.permissionManagerDelegate(result)
                }
            }
        }

        fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
            when (requestCode) {
                REQUEST_CODE -> {
                    if (grantResults.isEmpty()) {
                        return
                    }
                    for ((i,permission) in permissions.withIndex()) {
                        for (item in this.permissionTypes) {
                            if (permission == item.manifest_permission && i < grantResults.size) {
                                result += if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                                } else {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_DENIED)
                                }
                                break
                            }
                        }
                    }
                    delegate?.permissionManagerDelegate(result)
                }
            }
            semaphore.release()
        }
    }
}

Usage in Activity (in fragment the same)

class BaseActivity : AppCompatActivity(), Permission.ManagerDelegate {

    private lateinit var permissionManager: Permission.Manager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_activity)

        permissionManager = Permission.Manager(arrayOf(PermissionType.Defined.camera, PermissionType.Defined.currentLocation), this)
        permissionManager.check()
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        permissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }


    override fun permissionManagerDelegate(result: Array<Pair<String, Permission.PermissionResult>>) {
        result.forEach {
            println("!!! ${it.first} ${it.second}")
//            when (it.second) {
//                Permission.PermissionResult.NO_SYSTEM_FEATURE -> {
//                }
//
//                Permission.PermissionResult.ACCESS_DENIED  -> {
//                }
//
//                Permission.PermissionResult.ACCESS_ALLOWED -> {
//                }
//            }
        }
    }
}

Solution 23 - Java

Here i want to show my code how i managed this.

public class CheckPermission {

public Context context;

public static final int PERMISSION_REQUEST_CODE =  200;

public CheckPermission(Context context){
    this.context = context;
}

public boolean isPermissionGranted(){
    int read_contact = ContextCompat.checkSelfPermission(context.getApplicationContext() , READ_CONTACTS);
    int phone = ContextCompat.checkSelfPermission(context.getApplicationContext() , CALL_PHONE);

    return read_contact == PackageManager.PERMISSION_GRANTED && phone == PackageManager.PERMISSION_GRANTED;
   }
}

Here in this class i want to check permission granted or not. Is not then i will call permission from my MainActivity like

public void requestForPermission() {
       ActivityCompat.requestPermissions(MainActivity.this, new String[]    {READ_CONTACTS, CALL_PHONE}, PERMISSION_REQUEST_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
                    showMessageOKCancel("You need to allow access to both the permissions",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE},
                                                PERMISSION_REQUEST_CODE);
                                    }
                                }
                            });
                    return;
                }
            }
    }
}

Now in the onCreate method you need to call requestForPermission() function.

That's it.Also you can request multiple permission at a time.

Solution 24 - Java

I also met a problem that even if you call correct requestPermissions, you still can have this problem. The issue is that parent activity may override this method without calling super. Add super and it will be fixed.

Solution 25 - Java

for kotlin users, here my extension to check and validate permissions without override onRequestPermissionResult

 * @param permissionToValidate (request and check currently permission)
 *
 * @return recursive boolean validation callback (no need OnRequestPermissionResult)
 *
 * */
internal fun Activity.validatePermission(
    permissionToValidate: String,
    recursiveCall: (() -> Boolean) = { false }
): Boolean {
    val permission = ContextCompat.checkSelfPermission(
        this,
        permissionToValidate
    )

    if (permission != PackageManager.PERMISSION_GRANTED) {
        if (recursiveCall()) {
            return false
        }

        ActivityCompat.requestPermissions(
            this,
            arrayOf(permissionToValidate),
            110
        )
        return this.validatePermission(permissionToValidate) { true }
    }

    return true

}

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
QuestionAyohaychView Question on Stackoverflow
Solution 1 - Javayavor87View Answer on Stackoverflow
Solution 2 - JavaTieruView Answer on Stackoverflow
Solution 3 - JavaSanjay MangaroliyaView Answer on Stackoverflow
Solution 4 - JavaSimon FeatherstoneView Answer on Stackoverflow
Solution 5 - JavaDusan ZivkovicView Answer on Stackoverflow
Solution 6 - JavaBen.Slama.JihedView Answer on Stackoverflow
Solution 7 - JavaAkKiView Answer on Stackoverflow
Solution 8 - JavaTouchBoarderView Answer on Stackoverflow
Solution 9 - JavaMarta RodriguezView Answer on Stackoverflow
Solution 10 - JavaalmisoftView Answer on Stackoverflow
Solution 11 - JavaAyohaychView Answer on Stackoverflow
Solution 12 - JavaShahab RaufView Answer on Stackoverflow
Solution 13 - JavaSumit khareView Answer on Stackoverflow
Solution 14 - JavaPounKumar PurushothamanView Answer on Stackoverflow
Solution 15 - JavaNdhetiView Answer on Stackoverflow
Solution 16 - JavahavabonView Answer on Stackoverflow
Solution 17 - JavaChandlerView Answer on Stackoverflow
Solution 18 - Javauser2002721View Answer on Stackoverflow
Solution 19 - JavaAbhishek DubeyView Answer on Stackoverflow
Solution 20 - JavaRemarioView Answer on Stackoverflow
Solution 21 - JavagrgrssllView Answer on Stackoverflow
Solution 22 - JavaVasily BodnarchukView Answer on Stackoverflow
Solution 23 - JavapavelView Answer on Stackoverflow
Solution 24 - JavaVolodymyrHView Answer on Stackoverflow
Solution 25 - JavaAury0nView Answer on Stackoverflow