Requesting Location Permission at Runtime - android

I have a query implementing RuntimePermission for Location. When I tried to requestLocationUpdates, I got LintError suggesting me to add PermissionCheck for that line. Considering that I implemented run-time permissions. So this is how it looks,
if (isNetworkEnabled() && networkListener != null) {
if (ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity, new String[]
{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION);
} else
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener);
}
And my main class implements onRequestPermissionsResult callback. This looks like,
switch (requestCode) {
case REQUEST_LOCATION:
if (grantResults.length == 2 && grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener);
} else
Message.displayToast(context, "Without enabling permission, you can't access this feature");
break;
}
After the permission is granted, I request location updates again. But it again shows LintError to add the PermissionCheck. Refer the below image
Just for try I checkSelfPermission before requesting for requestLocationUpdate inside onRequestPermissionsResult and the error is gone. Like below code.
if (ActivityCompat.checkSelfPermission(context, permissions[0]) == PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(context, permissions[1]) == PackageManager.PERMISSION_GRANTED)
So, my question is do I need to check the permission once again if the user granted the permission? Correct me if I'm wrong!

You do need to check for checkSelfPermission because with latest OS 6 (Marshmallow) you can revoke the permissions granted for an app by going into settings.
So even if user has granted the permissions to app during installation time, at runtime you need to doublecheck whether your app still has the permissions or user has revoked those permissions.

Related

How to re-request BLUETOOTH_SCAN and BLUETOOTH_CONNECT permissions for Android 12 after a user denial?

I have a problem re-requesting the permissions required to scan and connect to bluetooth devices when targeting SDK 31 (Android 12).
I call this method inside my main activity's onCreate():
public void requestBluetoothPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if ((this.checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
|| (this.checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED)) {
Log.w(getClass().getName(), "requestBluetoothPermissions() BLUETOOTH_SCAN AND BLUETOOTH_CONNECT permissions needed => requesting them...");
this.requestPermissions(new String[]{
Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT
}, MyActivity.REQUEST_BLUETOOTH_PERMISSIONS);
}
}
}
It's works fine the first time it is called i.e. an Android pop-up is displayed to the user, prompting him to grant the permissions.
But if he refuses to grant the permissions, next time onCreate() is called, the pop-up will not be displayed, which means the user remains unable to grant the permissions.
Any idea why and how to fix this ?
It appears Android 12 blocks requesting the same permission after user denied it once only.
Therefore, I ended up using ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.BLUETOOTH_SCAN) to determine wether the permission can be requested or not, in which case a snackbar message is displayed explaining why is the permission needed, with a button opening the app settings where permission can be granted.
Here is a sample of the code:
public void requestBluetoothPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if ((this.checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
|| (this.checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED)) {
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.BLUETOOTH_SCAN)) {
// display permission rationale in snackbar message
} else {
Log.w(getClass().getName(), "requestBluetoothPermissions() BLUETOOTH_SCAN AND BLUETOOTH_CONNECT permissions needed => requesting them...");
this.requestPermissions(new String[]{
Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT
}, MyActivity.REQUEST_BLUETOOTH_PERMISSIONS);
}
}
}
}

Why do we use Context Compat and Activity Compat?

I was writing a code which asks user the permission to use location:
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
}
Why do we use them and why cant we just write checkSelfPermission?

ACCESS_COARSE_LOCATION not automatically granted on Android 5.1.1

I'm checking if application has ACCESS_COARSE_LOCATION permission granted because of Android M. As far as I know, device with version lower than Marshmallow automatically grants all permissions with installation.
However, if I add this piece of code, it returns false on Android 5.1.1
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
Is it because the device, I am using for testing, has completely disabled access to location for all apps?
Instead of this:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED)
Use this:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED)
For Below 6.0 Devices You will get Permission Denied(-1) if you check with Coarse Location.
Actually Android minimum sdk version 21-22 i.e. 5.0 doesn't need to check permission but when we have to Test the our app on different phones for eg. on minimum sdk version 23 i.e. on Marshmallow. You need to check permission externally in your App.
Write below code in Your Starting_Activity
//requesting Permission
private void requestingPermission(){
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_NETWORK_STATE)){
//Exaplian here why you need this permission
}
//Ask for the permission
ActivityCompat.requestPermissions(this,new String[]{
Manifest.permission.ACCESS_NETWORK_STATE, },STORAGE_PERMISSION_CODE);
}
Now Add another
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//checking the request code of Permission request
if (requestCode == STORAGE_PERMISSION_CODE){
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){//Toast.makeText(getApplicationContext(),"Permission Granted",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(),"Permission Denied",Toast.LENGTH_SHORT).show();
}
}
}
Dont forget call below method in your activity onCreate() Method
requestingPermission();

Android Request Permission Callback

I'm trying to implement Android permissions from https://developers.google.com/android/guides/permissions
A couple of ques:
1) The callback onRequestPermissionResult - where are the parameters String[] permissions and int[]grantResults from?
2) I keep getting null values for grantResults and String[] permissions
3) I have set the value of the const REQUEST_LOCATION to 0 - does it matter what the value of this const is?
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Check Permissions Now
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_LOCATION);
} else {
// permission has been granted, continue as usual
Location myLocation =
LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
One unrelated ques...when getting a google map API key is it required to set the SHA-1 value or is that optional and just limits the key to android.
Thanks.
public void onRequestPermissionsResult(int requestCode,
String[] permissions,
int[] grantResults)
Get your run time permission like this
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
// Permission already Granted
//Do your work here
//Perform operations here only which requires permission
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}
and if permission is not already granted override onRequestPermission Results like this
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == 1) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Permission Granted
//Do your work here
//Perform operations here only which requires permission
}
}
}
public class RequestUserPermission {
private Activity activity;
// Storage Permissions
private static final int REQUEST_PERMISSION = 1;
private static String[] PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
};
public RequestUserPermission(Activity activity) {
this.activity = activity;
}
public boolean verifyStoragePermissions() {
// Check if we have write permission
int permissionWrite = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
int permissionRead = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
if ((permissionWrite != PackageManager.PERMISSION_GRANTED) ||
(permissionRead != PackageManager.PERMISSION_GRANTED)) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS,
REQUEST_PERMISSION
);
return false;
}else{
return true;
}
}
public void providePermission(){
verifyStoragePermissions();
}
public void forceFullOpenPermission(){
if(!verifyStoragePermissions()){
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
activity.startActivityForResult(intent, REQUEST_PERMISSION);
}
}
In your Activity
RequestUserPermission requestUserPermission = new
RequestUserPermission(DashBoard.this);
requestUserPermission.verifyStoragePermissions();
If you want to forceful open permission
requestUserPermission.forceFullOpenPermission();
1) request code is the one you named it REQUEST_LOCATION with value of 0. permissions is the requests you have sent. for example you can request for Location permission and Read SMS permission at once so you will get them in permissions string array. and grantResults is the status of each requests for example if user accepts Location request it will be 1 and if he rejected Read SMS it will be 0
2)I think this means you have rejected the request
3)With that if you have requested multiple times from different places you can determine which result is for which request
and answer of your unrelated question: no it's optional and if you don't want other applications uses your key you have to set that
1) The callback onRequestPermissionResult - where are the parameters String[] permissions and int[]grantResults from?
permissions is the list of permissions you requested and grantResults are the results of those requests. So since you only requested one permission (ACCESS_FINE_LOCATION), you will get back ACCESS_FINE_LOCATION in permissions, and either PackageManager.PERMISSION_GRANTED or PackageManager.PERMISSION_DENIED in grantResults
2) I keep getting null values for grantResults and String[] permissions
This means that the user did not click Accept or Decline in the permission dialog. Rather, they cancelled the dialog by clicking outside of it, or leaving the application.
3) I have set the value of the const REQUEST_LOCATION to 0 - does it matter what the value of this const is?
No, this can be anything

Android permissions for Lollipop

Problem is, even when I refuse to give permission for ACCESS_COARSE_LOCATION in dialog, when I check permission in another activity of this app, it returns PERMISSION_GRANTED. It happens in android 5(Lollipop). Could you give some advice, why it's happening?
I check permission by this way:
int permissionCheck = ContextCompat.checkSelfPermission(Browser.this,
android.Manifest.permission .ACCESS_COARSE_LOCATION);
if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
}else{
}
you have to check if current sdk is below marshmallow
if (Build.VERSION.SDK_INT >= 23) {
int permissionCheck = ContextCompat.checkSelfPermission(Browser.this,
android.Manifest.permission .ACCESS_COARSE_LOCATION);
if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
}else{
}
} else {
// permission alredy granted
}

Categories

Resources