People have trust issues when it comes to mobile apps, thanks to all the recent leaks and hacks. Permissions on Android have always been an important area to consider when developing applications.
System Permissions, as such, is of two types:
- The ones that read your personal data [dangerous]
-
And the ones that don’t [normal]
Normal permissions cover areas where your app needs to access data or resources outside the app’s sandbox, but where there’s very little risk to the user’s privacy or the operation of other apps.For example, permission to turn on the flashlight is a normal permission.
Dangerous permissions cover areas where the app wants data or resources that involve the user’s private information, or could potentially affect the user’s stored data or the operation of other apps.For example, the ability to read the user’s contacts is a dangerous permission.
Until Android 5.1(API level 22), users must grant your app a variety of permissions while installing.
Thanks to Android 6.0 (API level 23), now users can grant permissions on runtime.This approach streamlines the app install / update process. It also gives the user more control over the app’s functionality.
Enter the hack
As a developer, you must check whether you have that permission every time you perform an operation that requires that permission. The user is always free to revoke the permission, so even if the app used the camera yesterday, it can’t assume it still has that permission today.
Here comes the fancy flow-chart to explain how you can handle this,
Step [1]: Check if the build version is greater than or equal to 23. Make use of the following code to do so:
if(Build.VERSION.SDK_INT >= 23) | |
if (checkAndRequestPermissions(permissions, request_code)) | |
permissionResultCallback.PermissionGranted(request_code); | |
else | |
permissionResultCallback.PermissionGranted(request_code); |
Step [2]: Check if the needed permissions have already been granted or not.
int hasPermission = ContextCompat.checkSelfPermission(current_activity,permissions.get(i)); | |
if (hasPermission != PackageManager.PERMISSION_GRANTED) | |
listPermissionsNeeded.add(permissions.get(i)); |
Step [3]: If the permissions are not granted in step 2, check if the user has already been asked for permissions earlier. If yes, check whether the user has enabled “Don’t ask again”. Else, show the rationale dialog to the user with an explanation of why the app needs the permission.
// Request Permissions | |
if (!listPermissionsNeeded.isEmpty()) | |
{ | |
ActivityCompat.requestPermissions(current_activity,listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),request_code); | |
return false; | |
} | |
// Check to show the rationale dialog | |
if(ActivityCompat.shouldShowRequestPermissionRationale(current_activity,listPermissionsNeeded.get(i))) | |
pending_permissions.add(listPermissionsNeeded.get(i)); | |
else{ | |
Log.i("Go to settings","and enable permissions"); | |
permissionResultCallback.NeverAskAgain(req_code); | |
Toast.makeText(current_activity, "Go to settings and enable permissions", Toast.LENGTH_LONG).show(); | |
return; | |
} |
Step [4]: If the user has selected “Ok” in the rationale dialog box, then the respective permission must be shown. But if the user has gone with “cancel” then you should go ahead and handle the permission.
new AlertDialog.Builder(current_activity) | |
.setMessage(" Explain here why the app needs permissions ") | |
.setPositiveButton("Ok", okListener) | |
.setNegativeButton("Cancel", okListener) | |
.create() | |
.show(); |
Step [5]: When the user accepts all the permissions needed by the app, exit the above loop and continue with the app’s workflow. But when the app is granted with only a few and not all of the permissions (like permission A is granted and not B), your app must be able to work with limited features.
How to use
- PermissionUtils: Used to check and request the needed permission from the user.
- PermissionsResultCallback: This is a callback that you use to execute code when the permissions you have requested are either granted or denied.
interface PermissionResultCallback | |
{ | |
void PermissionGranted(int request_code); | |
void PartialPermissionGranted(int request_code, ArrayList<String> granted_permissions); | |
void PermissionDenied(int request_code); | |
void NeverAskAgain(int request_code); | |
} |
Getting permissions from the user is simple. First, add all the needed permissions in a list.
ArrayList<String>permissions=new ArrayList<>(); | |
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); | |
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); |
Create an instance for the class “PermissionUtils”, and call the function check_permission by passing the list of permissions, the purpose of those permission and the request code.
permissionUtils=new PermissionUtils(getApplicationContext()); | |
permissionUtils.check_permission(permissions,"Explain here why the app needs permissions",1); |
Then redirect the onRequestPermissionsResult to permissionUtils.onRequestPermissionsResult
@Override | |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, | |
@NonNull int[] grantResults) { | |
// redirects to utils | |
permissionUtils.onRequestPermissionsResult(requestCode,permissions,grantResults); | |
} |
For receiving the callbacks you need to include PermissionResultCallback interface into your activity,
and also implement the needed methods.
public class PermissionActivity extends AppCompatActivity implements | |
OnRequestPermissionsResultCallback,PermissionResultCallback | |
{ | |
// Callback functions | |
@Override | |
public void PermissionGranted(int request_code) { | |
Log.i("PERMISSION","GRANTED"); | |
} | |
@Override | |
public void PartialPermissionGranted(int request_code, ArrayList<String> granted_permissions) { | |
Log.i("PERMISSION PARTIALLY","GRANTED"); | |
} | |
@Override | |
public void PermissionDenied(int request_code) { | |
Log.i("PERMISSION","DENIED"); | |
} | |
@Override | |
public void NeverAskAgain(int request_code) { | |
Log.i("PERMISSION","NEVER ASK AGAIN"); | |
} | |
} |
In AndroidManifest.xml
Specify all the needed permissions. If you don’t, permission requests fail silently. That’s an Android thing.
I created a sample project on GitHub to demonstrate the things covered in this article.
Feel free to comment and share, keep watching this space get more updates on Android Stuff!
Jaison Fernando
Latest posts by Jaison Fernando (see all)
- Phone number auth using Firebase Authentication SDK - March 20, 2020
- Password-less email auth using Firebase Authentication SDK - March 9, 2020
- How to use SharedPreferences API in Android? - February 10, 2020