# Permission Handling

The library requires at least the following permissions to access Move services.

```
<uses-permission android:name="android.permission.INTERNET" />
```

Depending on the used services, different permissions are required. The following table gives an overview what's required:

## Permission overview

<table data-header-hidden><thead><tr><th width="150"></th><th width="166"></th><th width="186.61772853185596">Required permissions</th><th>Optional permissions</th></tr></thead><tbody><tr><td></td><td></td><td>Required permissions</td><td>Optional permissions</td></tr><tr><td><strong>Mode of Transport</strong></td><td>Driving</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a> - improves trip recognition and classification considerably</td></tr><tr><td></td><td>Bicycle</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a>,<br><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a></td><td></td></tr><tr><td></td><td>Walking</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACTIVITY_RECOGNITION">ACTIVITY_RECOGNITION</a></td><td></td></tr><tr><td><strong>Driving Services</strong></td><td>Distraction-Free-Driving (DFD)</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE">READ_PHONE_STATE</a>,<br><a href="https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW">SYSTEM_ALERT_WINDOW</a></td><td></td></tr><tr><td></td><td>Driving behaviour events (DBE)</td><td></td><td></td></tr><tr><td><strong>Other services</strong></td><td>Points of Interest</td><td><a href="https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION">ACCESS_FINE_LOCATION</a></td><td></td></tr></tbody></table>

{% hint style="warning" %}
[Background Location](#background-location) is not mandatory, but strongly recommended. Similarly for the optional Activity Recognition permission (Driving) - make sure to request this from the user, otherwise it will degrade the quality of the service.
{% endhint %}

More Information regarding the system permissions can be found here: <https://developer.android.com/reference/android/Manifest.permission>

The required permissions must be granted before the services can be used. If any single required permission is missing, the entire SDK stops working. In case of any permission error, the SDKState callback will be triggered with an error state: [MoveSdkState.Error](https://docs.movesdk.com/move-platform/move-sdk-1.x/sdk/models/movestate)

If there are permissions missing, the state is an object of type MoveSdkState.Error. The error state contains an error reason which can be any of the following:

* Overlay (ErrorReason.PermissionMissing.Overlay)
* Location (ErrorReason.PermissionMissing.Location)
* Phone (ErrorReason.PermissionMissing.Phone)
* Activity  (ErrorReason.PermissionMissing.Motion) (since Android 10 )

The *PermissionMissing* error reason contains a string pertaining to the relevant permission of the Android Manifest, e.g. *Manifest.permission.READ\_PHONE\_STATE*. This permission string can be used to request dangerous permission directly as shown in the code example below. For more information about dangerous visit the [official developer page](https://developer.android.com/guide/topics/permissions/overview).

In fact the SDK is not aware of permission changes, the developer can tell the SDK that the error is resolved. This can be done for example in [onRequestPermissionsResult()](https://developer.android.com/reference/androidx/core/app/ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult\(int,%20java.lang.String%5B%5D,%20int%5B%5D\)).

```kotlin
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
 
    val sdkStatus = moveSdk.getSdkState()
    if (sdkStatus is MoveSdk.State.Error) {
        // Tell the SDK that we have fixed our issue
        sdkStatus.resolved()
    }
}
```

## Runtime permissions

In Android there are some [permissions](https://developer.android.com/guide/topics/permissions/overview#dangerous_permissions) which require a request during runtime. Keep in mind that those need to be defined in the manifest as well. Before init of the MOVE SDK, the proper permissions should have been already requested.&#x20;

### Display over other apps

The overlay permission ([SYSTEM\_ALERT\_WINDOW](https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW)) ,which is required for distraction free driving, needs to be requested in a specific way. The user is lead to the app settings where the permission needs to be enabled.

Starting with Android 11, the user will only be taken to the settings overview screen, and the user needs to select the specific app itself.

```kotlin
val intent = Intent(
    Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
    Uri.parse("package:$packageName"))
startActivityForResult(intent, OVERLAY_REQUEST_CODE)
```

###

![Android App Info - Display over other apps](https://1197996007-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-McxM5LgwW5HR7ulVbpe%2F-McxoadttLu3hzrDV5Yf%2Fdevice-2021-06-24-133941.png?alt=media\&token=01f4e6c2-3ccc-41da-9fac-4e333f341429)

### Background location

Since Android 10 there is an additional background location which should be also requested when asking for location permission. In Android 11 the user must go to the location settings of the app to grant the "**Allow all the time**" permission.

![](https://1197996007-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-Ma7-Qp0tvRtlszHh2aC%2F-MaKm8RJuFvnXlq_gHv6%2Fimage.png?alt=media\&token=c1bfea51-62c5-4134-82dc-c1c639fff4af)

![](https://1197996007-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXD5xlIFUYU8eK_kkLo%2F-McxM5LgwW5HR7ulVbpe%2F-McxncGAwHg9FJ2NF_ct%2Fdevice-2021-06-24-133608.png?alt=media\&token=8bd2043f-a537-412c-a1ae-7421d8ac2a9e)

```kotlin
if (reason is ErrorReason.PermissionMissing.Location) {
    val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        // On Android Q both (foreground & background) permissions should be requested
        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
    } else {
        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
    }
    ActivityCompat.requestPermissions(this@MoveActivity, permissions, 0)
}
```

#### Full code example <a href="#androidpermissionhandlingv1.1-fullcodeexample" id="androidpermissionhandlingv1.1-fullcodeexample"></a>

The following shows an example which is used in our demo app.

```kotlin
val reason = errorState.reason
if (reason is ErrorReason.PermissionMissing) {
    if (reason is ErrorReason.PermissionMissing.Overlay) {
        requestOverlayPermission()
    } else if (reason is ErrorReason.PermissionMissing.Location) {
        val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // On Android Q both (foreground & background) permissions should be requested
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
        } else {
            arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
        }
        ActivityCompat.requestPermissions(this@MoveActivity, permissions, 0)
    } else {
        val missingPermission = reason.permission
        ActivityCompat.requestPermissions(this@MoveActivity, arrayOf(missingPermission), 0)
    }
}
...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
 
    if (requestCode == OVERLAY_REQUEST_CODE) {
        val moveSdk = yourApplication.getMoveSdk()
        val sdkStatus = moveSdk.getSdkState()
        if (sdkStatus is MoveSdkState.Error) {
            // Tell SDK that we have fixed our issue
            sdkStatus.resolved()
        }
    }
}
```
