java.lang.StackOverflowError in onRequestPermissionsResult (Android) - java

In my code, I request:
int permissionCheck = ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_PHONE_STATE);
int permissionCheck1 = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
int permissionCheck2 = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS);
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_PHONE_STATE}, 0);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, 2);
I also include:
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 0: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_PHONE_STATE}, 0);
}
return;
}
case 1: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1);
}
return;
}
case 2: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_CONTACTS}, 2);
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
When I run y app, I first get the request, and then, after a secon of not touching anything, my app crashes with the following error:
FATAL EXCEPTION: main
Process: com.example.ortel.tagnet, PID: 28445
java.lang.StackOverflowError: stack size 8MB
at com.example.ortel.tagnet.MainActivityOld.onRequestPermissionsResult(MainActivityOld.java:894)
at android.app.Activity.requestPermissions(Activity.java:4455)
at android.support.v4.app.ActivityCompat.requestPermissions(ActivityCompat.java:507)
at com.example.ortel.tagnet.MainActivityOld.onRequestPermissionsResult(MainActivityOld.java:894)
at android.app.Activity.requestPermissions(Activity.java:4455)
at android.support.v4.app.ActivityCompat.requestPermissions(ActivityCompat.java:507)
at com.example.ortel.tagnet.MainActivityOld.onRequestPermissionsResult(MainActivityOld.java:894)
at android.app.Activity.requestPermissions(Activity.java:4455)
at android.support.v4.app.ActivityCompat.requestPermissions(ActivityCompat.java:507)
at com.example.ortel.tagnet.MainActivityOld.onRequestPermissionsResult(MainActivityOld.java:894)
For Your Information, (MainActivityOld.java:894) is
ActivityCompat.requestPermissions(this, new
String[]{android.Manifest.permission.READ_PHONE_STATE}, 0);
What is happening? It seems that it keeps calling my request.
Shouldn't it wait for my answer?
EDIT: Please Address if you don't know why this is happening.

You can try to request all your permissions at once calling Activity.requestPermissions with input a String[] with all the 3 permission you need to ask, in your code you are actually prompting the system to require the permissions with 3 different dialogues as separate entities, maybe when the second permission request is executed it overrides the first one and create a loop that generate the StackOverflowException.
Example:
List <String> str = new ArrayList <> ();
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
str.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
str.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
str.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
str.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
str.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (str.size() > 0) {
String[]strings = new String[str.size()];
str.toArray(strings);
ActivityCompat.requestPermissions(StartActivity.this,
strings,
PERMISSION_CODE_STATE);
}
And then in the callback receiving the result to check if you received all the permissions something like that or examine every grantResult manually:
boolean gotPermissions = true;
for (int i : grantResults) {
if (i != PackageManager.PERMISSION_GRANTED) {
gotPermissions = false;
break;
}
}

See this answer.
You have an infinite loop which I'm guessing is caused by someone denying Location permission, and selecting the "Never ask agan" checkbox

Related

Android App crash when ask for permission

I need 2 permissions for my app= Location and Record Audio. I check, if it was granted, if no, I ask for permission. The code, where I ask for permisssion looks like this=
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// ask for permission
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
} else {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, locationListener);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
// ask for permission
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 2);
}
}
My onRequestPermissionsResult method looks like this=
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, locationListener);
}
}
case 2:
permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
break;
}
}
When i install the apk on my phone and change to that activity, where I need this 2 permissions, the app crashes in the background, but the permission windows for location is still open,when I grant it and reopen the app, change to that activity, I just have to give Location permission and everything works fine. Why does my app crash? When I only had location permission, it worked fine, after inserting audio record permission, it closes. When I run this on my emulator, it doesnt crash.
you should requestPermissions once with array of all needed permissions and you have two separated calls - second one will be called, when your app is already in background (because dialog with location permission appeared)
easiest fix would be adding return in proper place for checking is this the case (without stacktrace of exception its hard to guess)
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// ask for permission
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
return; // return in here
} else {
///... rest of code
better approach would be summing up all needed permissions and calling requestPErmissions once
if (Build.VERSION.SDK_INT >= 23) {
boolean needLocPerm = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED;
boolean needAudioPerm = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED;
String[] permsArray = null;
if(needAudioPerm && needLocPerm ){
permsArray = new String[]{Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_FINE_LOCATION};
}
else if(needAudioPerm){
permsArray = new String[]{Manifest.permission.RECORD_AUDIO};
}
else if(needLocPerm ){
permsArray = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
}
if(permsArray!=null && permsArray.length>0)
ActivityCompat.requestPermissions(this, permsArray, 123);
else locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 0, locationListener);
}
after this code improvement you should refactor your onRequestPermissionsResult method and check which permissions were granted (inspect String[] permissions and int[] grantResults arrays)
without a stacktrace of exception this is only guess, besides above problem everything looks fine, but there is a chance your exception is fired by some call made in another method, e.g. onPause

How to fix 'show permission dialog ' every time when I send sms?

I want to send SMS by android-app, but the permission dialog show before the send a message every time, I supposed to send a message without dialog show after the first permission asked.
My android app is run on mi-8, target SDK-version is 29.
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.SEND_SMS}, 3);
} else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_PHONE_STATE}, 4);
} else {
sendMsg();
}
I expect the permission dialog did not show when I send a message after the first asked permission, but actual every time show dialog when I send a message .
use this function to check whether you have given the permission if say so you have given as required persmission it will return true flag
check by this way
private boolean checkAndRequestPermissions(){
//add as much as permission you need
int readSMS = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS);
int sendSms = ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS);
List<String> listPermissionsNeeded = new ArrayList<>();
if (readSMS != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_SMS);
}
if (receiveSms != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.RECEIVE_SMS);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),
REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
check by this way
if (checkAndRequestPermissions()){
sendMsg();
}else{
//do what you want
}
no need to do this by hardcode way

Unable to request multiple dangerous permissions at once

I'm working on an app that collects data for processing, as such it requires multiple dangerous permissions (namely ACCESS_FINE_LOCATION and READ_PHONE_STATE). At the moment it requests one then crashes.
I have tried requesting the permissions separately using ActivityCompat.requestPermissions, and I have tried having both of the permissions in the array. I have also tried using the request codes 0,1 and 7 as I saw these used in different answers to similar questions on this topic, but nothing seems to change.
private void setupPermissions() {
ArrayList<String> permissions = new ArrayList<>();
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.READ_PHONE_STATE);
}
if (permissions.size()>0){
ActivityCompat.requestPermissions(getActivity(), permissions.toArray(new String[permissions.size()]), 7);
}
}
Expected results:
Upon first opening the app both permissions should be requested for, either by two separate dialog boxes (one after the other) or by a multiple page dialog box.
The app should then run as expected
Actual results:
requests the first
allows you to continue with the app
crashes when you try to use a feature that requires the second
reopen app
requests the second
allows app to continue as normal
Call this checkAndRequestPermissions() Method whenevr you want permission
private boolean checkAndRequestPermissions() {
int ACCESS_FINE_LOCATION = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
int READ_PHONE_STATE = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
List<String> listPermissionsNeeded = new ArrayList<>();
if (READ_PHONE_STATE != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_PHONE_STATE);
}
if (ACCESS_FINE_LOCATION != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray
(new String[listPermissionsNeeded.size()]), 101);
return false;
}
return true;
}
Try out the following code
(from this answer)
public static boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) !=
PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
int PERMISSION_ALL = 1;
String[] PERMISSIONS = {
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.READ_PHONESTATE
};
if(!hasPermissions(this, PERMISSIONS)){
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
}

How to check permission in fragment

I want to check a permission inside a fragment.
my code:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(getActivity(),
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
1);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
but onRequestPermissionsResult not called after allow or deny.
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
Log.e("test","0");
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
//yes
Log.e("test","1");
Intent intent = new Intent(getActivity(), MapsActivity.class);
intent.putExtra("latitude", 35.694828);
intent.putExtra("longitude", 51.378129);
startActivity(intent);
} else {
utilityFunctions.showSweetAlertWarning(getActivity(),r.getString(R.string.str_warning_title_empty),
r.getString(R.string.str_you_must_allow_this_permission_toast),
r.getString(R.string.str_warning_btn_login));
Log.e("test","2");
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
This is how I did, it works for me. Thanks!
For Activity :
ActivityCompat.requestPermissions(this, permissionsList, REQUEST_CODE);
For Fragment :
requestPermissions(permissionsList, REQUEST_CODE);
Fragment has requestPermissions() and onRequestPermissionsResult() methods, use it.
But checkSelfPermission() is from ActivityCompat (not require Activity, only Context).
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions( //Method of Fragment
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_PERMISSIONS_CODE_WRITE_STORAGE
);
} else {
downloadImage();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSIONS_CODE_WRITE_STORAGE) {
if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
proceedWithSdCard();
}
}
}
I have done following to check a permission inside a fragment.
if (ActivityCompat.checkSelfPermission(getContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(getContext(),
android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(getActivity(),
new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION);
} else {
Log.e("DB", "PERMISSION GRANTED");
}
Update
Since Fragment.requestPermissions is now deprecated, Google advises using registerForActivityResult instead.
I have done the request like this:
val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// Do if the permission is granted
}
else {
// Do otherwise
}
}
permissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
For more documentation on this method you can check this link.
Check Permissions from Fragment (the 2021 way)
The registerForActivityResult() method in fragment is now deprecated. The deprecation message suggests to use registerForActivityResult. So after some trial and errors, here is the 2021 way:
Suppose your fragment's name is AwesomeFragment. Then in the constructor (before the fragment's onCreate method to be precise), you initialize ActivityResultLauncher<String[]> activityResultLauncher.
java version
private ActivityResultLauncher<String[]> activityResultLauncher;
public AwrsomeFragment() {
activityResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
#Override
public void onActivityResult(Map<String, Boolean> result) {
Log.e("activityResultLauncher", ""+result.toString());
Boolean areAllGranted = true;
for(Boolean b : result.values()) {
areAllGranted = areAllGranted && b;
}
if(areAllGranted) {
capturePhoto();
}
}
});
}
Then maybe on some button click, you invoke the launch method:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String[] appPerms;
appPerms = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
this.cameraClick.setOnClickListener(v -> {
this.activityResultLauncher.launch(appPerms);
});
}
kotlin version
private var activityResultLauncher: ActivityResultLauncher<Array<String>>
init{
this.activityResultLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()) {result ->
var allAreGranted = true
for(b in result.values) {
allAreGranted = allAreGranted && b
}
if(allAreGranted) {
capturePhoto()
}
}
}
// --- ---
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// ... ... init views / binding... ...
someBtn.setOnClickListener{
val appPerms = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
activityResultLauncher.launch(appPerms)
}
}
To handle permissions in a Fragment call requestPermissions method. If you override onRequestPermissionsResult method in both fragment and activity, containing that fragment, make sure to call super.onRequestPermissionsResult(...) in the activity method to propagate call to the onRequestPermissionsResult method in the fragment.
Using Kotlin, you call requestPermissions(arrayOf(Manifest.permission.THE_PERMISSION_CODE_YOU_WANT), PERMISSION_REQUEST_CODE) and add the following override to your fragment
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out kotlin.String>, grantResults: IntArray): Unit {
}
onRequestPermissionsResult is invoked in the activity not the fragment. Try overriding onRequestPermissionsResult in the activity instead.
What worked for me was calling the onRequestPermissionsResult method in the activity inside which fragment is implemented rather than calling it in fragment itself.
Inside onCreateView method in fragment:
Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int permissionCheck = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, MY_PERMISSIONS_REQUEST_READ_MEDIA);
}else{
//Do your work
fetchMethod();
}
}
});
In the Activity which helps to implement fragment, outside of onCreate method:
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_MEDIA:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
fetchMethod();
}else{
Toast.makeText(getApplicationContext(), "Permission not granted!", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
If you closed your permission of app from settings , you can not open your permission from code or your android version lower than Marshmallow.
You can check this documentation
https://developer.android.com/training/permissions/requesting.html
And this is a example
https://www.learn2crack.com/2015/10/android-marshmallow-permissions.html
I was getting tripped up using checkSelfPermission() in a Fragment and wondering what would be the best approach for Context being null (Kotlin specific)... should I use !! or something else?
I went with something else based on code I found in iosched. Have a look at the sample below, and remember, before the Fragment is attached to an Activity, the Context will be null.
private fun fineLocationPermissionApproved(): Boolean {
val context = context ?: return false
return PackageManager.PERMISSION_GRANTED == checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
)
}
To check permission within a fragment, I did the following.
Before onCreateView in Fragment add the following,
private final int STORAGE_PERMISSION_CODE = 1;
private Activity mActivity;
#Override
public void onAttach(#NotNull Context context) {
super.onAttach(context);
mActivity = (Activity) context;
}
Check the permission,
if ((ContextCompat.checkSelfPermission(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED))
{
if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
new AlertDialog.Builder(mActivity)
.setTitle("Permission needed")
.setMessage("Allow "+getResources().getString(R.string.app_name)+" to access your storage?")
.setPositiveButton("ok", (dialog, which) -> ActivityCompat.requestPermissions(mActivity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE)
)
.setNegativeButton("cancel", (dialog, which) -> {
dialog.dismiss();
Toast.makeText(mActivity, "Please allow this permission!", Toast.LENGTH_SHORT).show();
})
.create().show();
} else {
ActivityCompat.requestPermissions(mActivity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}
}
Place the following code in MainActivity to enable permission from the app's settings if the user denied the permission forever.
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_PERMISSION_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission GRANTED", Toast.LENGTH_SHORT).show();
} else {
//Now further we check if used denied permanently or not
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// 1. The user has temporarily denied permission.
Toast.makeText(MainActivity.this, "Permission DENIED", Toast.LENGTH_SHORT).show();
} else {
// 2. Permission has been denied.
// From here, you can access theĀ setting's page.
new AlertDialog.Builder(MainActivity.this)
.setTitle("Permission Required")
.setMessage("This permission was already declined by you. Please open settings, go to \"Permissions\", and allow the permission.")
.setPositiveButton("Settings", (dialog, which) -> {
final Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + MainActivity.this.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
MainActivity.this.startActivity(i);
})
.setNegativeButton("cancel", (dialog, which) -> {
dialog.dismiss();
Toast.makeText(MainActivity.this, "Please allow this permission!", Toast.LENGTH_SHORT).show();
})
.create().show();
}
}
}
}
If anyone is interested in Kotlin call permission.
private fun directCall() {
val numberText = phoneNo
val intent = Intent(Intent.ACTION_CALL)
intent.data = Uri.parse("tel:$numberText")
if (ActivityCompat.checkSelfPermission(requireContext(),Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED)
{
if(ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.CALL_PHONE)){
Toast.makeText(requireContext(), "Permission denied.", Toast.LENGTH_LONG).show()
return //<-- Check user input history if user already denied then second time not request and not ask.
}
else{
requestPermissions(arrayOf(Manifest.permission.CALL_PHONE),1)
return //<--return will call onRequestPermissionsResult and wait for user input.
}
}
startActivity(intent)
}
override fun onRequestPermissionsResult(requestCode: Int,permissions: Array<out String>,grantResults: IntArray) {
if (requestCode == requestPhoneCall && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
directCall()
}else{
Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_LONG).show()
return
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ContextCompat.checkSelfPermission( getActivity(),Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
its working in my case
checkSelfPermission not working in fragments?? we can try this code
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
ActivityCompat.checkSelfPermission(
getActivity(),Manifest.permission.READ_CONTACTS) !=
PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[].
{Manifest.permission.READ_CONTACTS},
PERMISSIONS_REQUEST_READ_CONTACTS); //After this point you wait for
callback in onRequestPermissionsResult(int, String[], int[]) overriden
method } else { // Android version is lesser than 6.0 or the permission
is already granted. List<String> contacts = getContactNames();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ActivityCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
//After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
} else {
// Android version is lesser than 6.0 or the permission is already granted.
List contacts = getContactNames();
}
To check permissions inside a fragment
we should use requestPermissions instead of ActivityCompat.requestPermissions
// Replace with Permissions you need to check.
requestPermissions(arrayOf(
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.ACCESS_FINE_LOCATION"
), YOUR_REQUEST_CODE)
Then override onRequestPermissionsResult as uduel
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == YOUR_REQUEST_CODE) {
if (
grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED
) {
// Permission granted
Log.d("onRequestPermissionsResult", "permission granted")
} else {
// Permission was denied. Display an error message.
Log.d("onRequestPermissionsResult", "permission denied")
}
}
}

When to request permission at runtime for Android Marshmallow 6.0?

I am testing my app on Marshmallow 6.0 and it's getting force closed for the android.permission.READ_EXTERNAL_STORAGE, even if it is defined in the Manifest already. Somewhere I have read that if I request permission at runtime then it would not force close your application. I have read this android document also, which is for requesting runtime permission.
So, I came to know that we can request a permission like below which is mentioned in the android document.
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
The above code has a callback method onRequestPermissionsResult which gets the result.
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
}
}
My question is where to exactly request the permission to user? Should we use the requesting permission at start of the app or should we do it as when the permission is required?
This is worked for me !!!
In Your Splash Activity of your application do the following,
1) Declare an int variable for request code,
private static final int REQUEST_CODE_PERMISSION = 2;
2) Declare a string array with the number of permissions you need,
String[] mPermission = {Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
3) Next Check the condition for runtime permission on your onCreate method,
try {
if (ActivityCompat.checkSelfPermission(this, mPermission[0])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[1])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[2])
!= MockPackageManager.PERMISSION_GRANTED ||
ActivityCompat.checkSelfPermission(this, mPermission[3])
!= MockPackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
mPermission, REQUEST_CODE_PERMISSION);
// If any permission aboe not allowed by user, this condition will execute every tim, else your else part will work
}
} catch (Exception e) {
e.printStackTrace();
}
4) Now Declare onRequestPermissionsResult method to check the request code,
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.e("Req Code", "" + requestCode);
if (requestCode == REQUEST_CODE_PERMISSION) {
if (grantResults.length == 4 &&
grantResults[0] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[1] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[2] == MockPackageManager.PERMISSION_GRANTED &&
grantResults[3] == MockPackageManager.PERMISSION_GRANTED) {
// Success Stuff here
}
}
}
Do like this
private static final int REQUEST_ACCESS_FINE_LOCATION = 111;
In your onCreate
boolean hasPermissionLocation = (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
if (!hasPermissionLocation) {
ActivityCompat.requestPermissions(ThisActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_ACCESS_FINE_LOCATION);
}
then check result
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode)
{
case REQUEST_ACCESS_FINE_LOCATION: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(ThisActivity.this, "Permission granted.", Toast.LENGTH_SHORT).show();
//reload my activity with permission granted
finish();
startActivity(getIntent());
} else
{
Toast.makeText(ThisActivity.this, "The app was not allowed to get your location. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show();
}
}
}
}
In general, request needed permissions it as soon as you need them. This way you can inform the user why you need the permission and handle permission denies much easier.
Think of scenarios where the user revokes the permission while your app runs: If you request it at startup and never check it later this could lead to unexpected behaviour or exceptions.
In my opinion, there is no one correct answer to your question. I strongly suggest you to look at this official permissions patterns page.
Couple of things suggested by Google :
"Your permissions strategy depends on the clarity and importance of the permission type you are requesting. These patterns offer different ways of introducing permissions to the user."
"Critical permissions should be requested up-front. Secondary permissions may be requested in-context."
"Permissions that are less clear should provide education about what the permission involves, whether done up-front or in context."
This illustration might give you better understanding.
Maybe the most crucial thing here is that whether you ask the permission up-front or in the context, you should always keep in mind that these permissions can be revoked anytime by the user (e.g. your app is still running, in background).
You should make sure that your app doesn't crash just because you asked the permission on the very beginning of the app and assumed that user didn't change his/her preference about that permission.
For requesting runtime permission i use GitHub Library
Add library in Build.gradle file
dependencies {
compile 'gun0912.ted:tedpermission:1.0.3'
}
Create Activity and add PermissionListener
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PermissionListener permissionlistener = new PermissionListener() {
#Override
public void onPermissionGranted() {
Toast.makeText(RationaleDenyActivity.this, "Permission Granted", Toast.LENGTH_SHORT).show();
//Camera Intent and access Location logic here
}
#Override
public void onPermissionDenied(ArrayList<String> deniedPermissions) {
Toast.makeText(RationaleDenyActivity.this, "Permission Denied\n" + deniedPermissions.toString(), Toast.LENGTH_SHORT).show();
}
};
new TedPermission(this)
.setPermissionListener(permissionlistener)
.setRationaleTitle(R.string.rationale_title)
.setRationaleMessage(R.string.rationale_message) // "we need permission for access camera and find your location"
.setDeniedTitle("Permission denied")
.setDeniedMessage("If you reject permission,you can not use this service\n\nPlease turn on permissions at [Setting] > [Permission]")
.setGotoSettingButtonText("Settings")
.setPermissions(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.check();
}
}
string.xml
<resources>
<string name="rationale_title">Permission required</string>
<string name="rationale_message">we need permission for read <b>camera</b> and find your <b>location</b></string>
</resources>
Android Easy Runtime Permissions with Dexter:
1. Dexter Permissions Library
To get started with Dexter, add the dependency in your build.gradle
dependencies {
// Dexter runtime permissions
implementation 'com.karumi:dexter:4.2.0'
}
1.1 Requesting Single Permission
To request a single permission, you can use withPermission() method by passing the required permission. You also need a PermissionListener callback to receive the state of the permission.
> onPermissionGranted() will be called once the permission is granted.
> onPermissionDenied() will be called when the permission is denied. Here you can check whether the permission is permanently denied by using response.isPermanentlyDenied() condition.
The below code requests CAMERA permission.
Dexter.withActivity(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener() {
#Override
public void onPermissionGranted(PermissionGrantedResponse response) {
// permission is granted, open the camera
}
#Override
public void onPermissionDenied(PermissionDeniedResponse response) {
// check for permanent denial of permission
if (response.isPermanentlyDenied()) {
// navigate user to app settings
}
}
#Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
token.continuePermissionRequest();
}
}).check();
1.2 Requesting Multiple Permissions
To request multiple permissions at the same time, you can use withPermissions() method. Below code requests STORAGE and LOCATION permissions.
Dexter.withActivity(this)
.withPermissions(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
// check if all permissions are granted
if (report.areAllPermissionsGranted()) {
// do you work now
}
// check for permanent denial of any permission
if (report.isAnyPermissionPermanentlyDenied()) {
// permission is denied permenantly, navigate user to app settings
}
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
token.continuePermissionRequest();
}
})
.onSameThread()
.check();
A good explanation and HowTo can be found here:
https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
I wrote this code to check and request the permissions at runtime in a BaseActivity.class which is parent of every other Activity.class I implemented:
public static final int PERMISSION_REQUEST = 42;
public static final int MULTIPLE_PERMISSION_REQUEST = 43;
//Marshmallow Permission Model
public boolean requestPermission(String permission /* Manifest.permission...*/) {
if (ContextCompat.checkSelfPermission(this,
permission) != PackageManager.PERMISSION_GRANTED) {
if (Utils.hasMarshmallow())
ActivityCompat.requestPermissions(this,
new String[]{permission}, PERMISSION_REQUEST
);
else {
requestPermissions(new String[]{permission},
PERMISSION_REQUEST);
}
return false;
} else {
return true;
}
}
public boolean requestPermission(String... permissions) {
final List<String> permissionsList = new ArrayList<String>();
for (String perm : permissions) {
addPermission(permissionsList, perm);
}
if (permissionsList.size() > 0) {
if (Utils.hasMarshmallow())
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
MULTIPLE_PERMISSION_REQUEST);
else
ActivityCompat.requestPermissions(this, permissionsList.toArray(new String[permissionsList.size()]),
MULTIPLE_PERMISSION_REQUEST);
return false;
} else
return true;
}
private boolean addPermission(List<String> permissionsList, String permission) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
// Check for Rationale Option
if (Utils.hasMarshmallow())
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST:
case MULTIPLE_PERMISSION_REQUEST: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
Simply example call:
activity.requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE);
Return result will let you know if the permission is already granted or not.
calling this function we can allow user to open dialog for asking permission to allow camera and record Audio.
if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
ActivityCompat.shouldShowRequestPermissionRationale (this,
Manifest.permission.RECORD_AUDIO) ) {
Toast.makeText (this,
R.string.permissions_needed,
Toast.LENGTH_LONG).show ();
} else {
ActivityCompat.requestPermissions (
this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
CAMERA_MIC_PERMISSION_REQUEST_CODE);
}
https://material.io/guidelines/patterns/permissions.html
This link will give you different type of scenario where permissions can be asked. Choose accordingly to your needs.
I like short code. I use RxPermission for permissions.
RxPermission is best library, which makes permission code unexpected just 1 line.
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA,
Manifest.permission.READ_PHONE_STATE) // ask single or multiple permission once
.subscribe(granted -> {
if (granted) {
// All requested permissions are granted
} else {
// At least one permission is denied
}
});
add in your build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
}
Isn't this easy?
if ( ActivityCompat.shouldShowRequestPermissionRationale (this, Manifest.permission.CAMERA) ||
ActivityCompat.shouldShowRequestPermissionRationale (this,
Manifest.permission.RECORD_AUDIO) ) {
Toast.makeText (this,
R.string.permissions_needed,
Toast.LENGTH_LONG).show ();
} else {
ActivityCompat.requestPermissions (
this,
new String[]{Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO},
CAMERA_MIC_PERMISSION_REQUEST_CODE);
}

Categories

Resources