18 July

Runtime permissions in Android Marschmallow

Each application requires user's permission to use network, access sensors and memory of the device. API-23, that is Android 6.0, introduced a new model of permissions system. So far, before an installation, a user had to absolutely approve a list of permissions requested by application. Currently applications can push at runtime requests only for the specific permissions needed at a given moment.

Old vs. new

If we set targetSdkVersion at 22 or below, everything will work as usual, so we do not have to worry too much about older applications used in the new system. We will be asked for all permissions at the installation time, as usual. However there are some exceptions related to the reorganization of group permissions. For example, to enable full usage of bluetooth, it is not enough to request permissions which were already used. To scan devices and to connect, an app now needs a permission to access location. You can read more about it here: an explanation.

In the old applications that use Bluetooth you will need to add permission to ACCESS_COARSE_LOCATION although everything was designed for an API older than in the version 23! But it is enough to add just one line to the manifesto and the functionalities will work as usual.

Safety

By setting targetSdkVersion at 23 or higher, we are forced to call a system window asking for specific permission. Regardless of the version all licenses must be listed in the manifest file, but from the API 23 on, a user must be shown a system window asking for access to sensitive data at runtime. Fortunately, not all requests need to interrupt users while they are using the application. There is a group of dangerous permits, which must be handled this way and they can be found here: group of dangerous permissions.

It is also worth noting that you can revoke or accept a dangerous permission at any time directly in the system settings.

To call up a window asking for permission, you will need a simple code called in any activity:

ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);

The answer will come in the overwritten method of activity:

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

But we don't need to do it each time before we use functions requiring given permission. First, we need to check whether the permission has already been granted. The correct code may look like this:

public static final int REQUEST_PERMISSION_CAMERA = 12;

public void checkCameraPermission() {
   requestPermission(Manifest.permission.CAMERA, REQUEST_PERMISSION_CAMERA);
}

private void requestPermission(String permission, int requestCode) {
   int hasPermission = ActivityCompat.checkSelfPermission(this, permission);
   if (hasPermission == PackageManager.PERMISSION_GRANTED) {
       onPermissionCameraGranted();
       return;
   }
   ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
   switch (requestCode) {
       case REQUEST_PERMISSION_CAMERA:
           if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
               onRequestCameraGranted();
           } else {
               onRequestCameraDenied();
           }
           break;
   }
}

By calling checkCameraPermission method, we get an answer and redirection to function onRequestCameraGranted or onRequestCameraDenied. We can call several queries at the same time, because the method requestPermissions adopts new String array of permission names. But this is not recommended, as we will discuss in the next paragraph.

Good practices

One of the most important things to keep in mind is to request a permission only when the application actually needs it. You should not ask for everything at once, and certainly not right from the start, unless this is specific for a particular application. For example, if you need access to the camera ask for permission only when the user selects the function of taking a picture. You shouldn't overload the user with notifications all the time, so you should always be ready for the refusal. You mustn't repeat the request, if the user already refused it. In such a situation you should push a short message informing the user that such license is necessary for further action and that it can be changed at any time in the settings. A good example would be to show Snackbar with an information which will disappear on its own in a moment, but will also have a button enabling switching quickly to the settings screen. It is good to remember user's choice, and in case of refusal to show only this information with the option of quickly turning desired permission on.

After the first refusal the user will have a default opportunity to select the option of not wishing to be requested this permission again. Then we will get a negative result just as we try to repeat the request. We must remember to make sure that our application works well even without certain permissions. By refusing permission to access contacts, users condemn themselves to not being able to import contacts etc. It is their choice, and the one we must respect and take into account. If the function is critical to the entire application functionality, the only option we are left with is to inform the user that without this the application cannot run.

Conclusions

The new model of permissions is definitely a step in the right direction and the answer to the many requests and suggestions submitted by experienced users. It provides greater security and transparency of running applications in the Android ecosystem. First of all, we don’t have to agree to everything application asks for, under the threat of not being able to install the product. We can accept just some of things or simply start with testing what will be needed at what time to better understand the purpose of granting given permission. Introduced changes are well-thought and bring a lot of good. Keep doing that, Google!