# Runtime permissions

## Location Permission

It is required to ask the user for location permission. Find below an example of how to ask location permission:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
fun checkLocationPermission(requestCode: Int) {
    val permissionFineLocationApproved = ActivityCompat.checkSelfPermission(this,
        Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED

    if (permissionFineLocationApproved) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val backgroundLocationPermissionApproved = ActivityCompat.checkSelfPermission(
                this, Manifest.permission.ACCESS_BACKGROUND_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
            if (!backgroundLocationPermissionApproved) {
                ActivityCompat.requestPermissions(this,
                    arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                    requestCode)
            }
        }
    } else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ActivityCompat.requestPermissions(this,
                arrayOf(
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                requestCode)
        } else {
            ActivityCompat.requestPermissions(this,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                requestCode)
        }
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
private void checkLocationPermission(int requestCode) {
        boolean permissionFineLocationApproved = ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;

        if (permissionFineLocationApproved) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                boolean backgroundLocationPermissionApproved = ActivityCompat.checkSelfPermission(
                        this, Manifest.permission.ACCESS_BACKGROUND_LOCATION
                ) == PackageManager.PERMISSION_GRANTED;
                if (!backgroundLocationPermissionApproved) {
                    ActivityCompat.requestPermissions(this,
                            new String[] { Manifest.permission.ACCESS_BACKGROUND_LOCATION },
                            requestCode);
                }
            }
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                ActivityCompat.requestPermissions(this,
                        new String[] {
                                Manifest.permission.ACCESS_FINE_LOCATION,
                                Manifest.permission.ACCESS_BACKGROUND_LOCATION },
                        requestCode);
            } else {
                ActivityCompat.requestPermissions(this,
                        new String[] { Manifest.permission.ACCESS_FINE_LOCATION },
                        requestCode);
            }
        }
    }

```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
If location permission is not granted by the user, Trip Analysis SDK will not work.
{% endhint %}

## Activity Recognition Permission

For device running Android 10 and above, it's required to ask the user for activity recognition permission. Find below an example of how to ask the permission:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
fun checkActivityRecognitionPermission(requestCode: Int) {
    var isActivityRecognitionAuthorize = true
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        isActivityRecognitionAuthorize = ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACTIVITY_RECOGNITION) == PackageManager.PERMISSION_GRANTED
    } else {
        // call DriveKitTripAnalysis.activateAutoStart(true)
    }
    if (!isActivityRecognitionAuthorize && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACTIVITY_RECOGNITION)) {
            // Display a message to explain why the permission is necessary
        } else {
            ActivityCompat.requestPermissions(this,
                arrayOf(Manifest.permission.ACTIVITY_RECOGNITION),
                requestCode)
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    // call DriveKitTripAnalysis.activateAutoStart(true)
}
```

{% endtab %}

{% tab title="Java" %}

```java
private void checkActivityRecognitionPermission(int requestCode) {
    boolean isActivityRecognitionAuthorize = true;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        isActivityRecognitionAuthorize = ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACTIVITY_RECOGNITION) == PackageManager.PERMISSION_GRANTED;
    } else {
        // call DriveKitTripAnalysis.INSTANCE.activateAutoStart(true)
    }
    if (!isActivityRecognitionAuthorize && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACTIVITY_RECOGNITION)) {
            // Display a message to explain why the permission is necessary
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[] { Manifest.permission.ACTIVITY_RECOGNITION },
                    requestCode);
        }
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // call DriveKitTripAnalysis.INSTANCE.activateAutoStart(true)
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
If activity recognition permission is not granted by the user, Trip Analysis component will not work.
{% endhint %}

## Battery optimization

It is required to ask the user to disable battery optimization for your app. Without battery optimization disabled, Trip Analysis SDK will not work properly.

The SDK usage is included into acceptable use cases for requesting or being on the Battery Optimizations exceptions whitelist. For more information you can read the Android developer documentation on [this topic](https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases).

Call the following code after explaining to the user why disabling battery optimization is required:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
fun checkBatteryOptimization() {
    val packageName = this.packageName
    val pm = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
    if (!pm.isIgnoringBatteryOptimizations(packageName)) {
        val intent = Intent()
        intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
        intent.data = Uri.parse("package:$packageName")
        this.startActivity(intent)
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
void checkBatteryOptimization() {
    Intent intent = new Intent();
    String packageName = getPackageName();
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    if (pm != null && !pm.isIgnoringBatteryOptimizations(packageName)) {
        intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + packageName));
        startActivity(intent);
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
If battery optimization is enabled, trip recording will not work.
{% endhint %}

{% hint style="warning" %}
Some manufacturers add other battery optimizations. You can find tutorials on how to disable these battery optimizations for main Android device manufacturers [here](https://info.drivequant.com/smartphone-configuration).
{% endhint %}

## Nearby Devices Permission

For devices running Android 12 and above, it's required to ask the user for [Nearby Devices permission](https://developer.android.com/guide/topics/connectivity/bluetooth/permissions). Find below an example of how to ask Nearby Devices permission:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
fun checkNearbyDevicesPermission(activity: Activity, requestCode : Int) {
    val isNearbyDevicesPermissionAuthorized = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        ContextCompat.checkSelfPermission(
            activity, Manifest.permission.BLUETOOTH_SCAN
        ) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(
            activity, Manifest.permission.BLUETOOTH_CONNECT
        ) == PackageManager.PERMISSION_GRANTED
    } else {
        true
    }

    if (!isNearbyDevicesPermissionAuthorized && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val shouldShowRationaleScan = shouldShowRequestPermissionRationale(activity, Manifest.permission.BLUETOOTH_SCAN)
        val shouldShowRationaleConnect = shouldShowRequestPermissionRationale(activity, Manifest.permission.BLUETOOTH_CONNECT)
        if (!shouldShowRationaleScan || !shouldShowRationaleConnect) {
            // Display a message to explain why the permission is necessary 
        } else {
            requestPermissions(activity, arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT), requestCode)
        }        
    }
}

```

{% endtab %}

{% tab title="Java" %}

```java
public void checkNearbyDevicesPermission(Activity activity, int requestCode) {
    boolean isNearbyDevicesPermissionAuthorized;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        isNearbyDevicesPermissionAuthorized = ContextCompat.checkSelfPermission(
                activity, Manifest.permission.BLUETOOTH_SCAN
        ) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(
                activity, Manifest.permission.BLUETOOTH_CONNECT
        ) == PackageManager.PERMISSION_GRANTED;
    }  else {
        isNearbyDevicesPermissionAuthorized = true;
    }
    
    if (!isNearbyDevicesPermissionAuthorized && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        final boolean shouldShowRationaleScan = shouldShowRequestPermissionRationale(activity, Manifest.permission.BLUETOOTH_SCAN);
        final boolean shouldShowRationaleConnect = shouldShowRequestPermissionRationale(activity, Manifest.permission.BLUETOOTH_CONNECT);
        if (!shouldShowRationaleScan || !shouldShowRationaleConnect) {
            // Display a message to explain why the permission is necessary
        } else {
            requestPermissions(activity, new String[] { Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT }, requestCode);
        }
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
If Nearby Devices permission is not granted by the user, Trip Analysis component won't work correctly.
{% endhint %}

## Notification Runtime Permission

For devices running Android 13 and above, it's required to ask the user for [Notification runtime permission](https://developer.android.com/develop/ui/views/notifications/notification-permission). If the permission is not granted, the user will not receive notifications.

Find below an example of how to ask the Notification permission:

First, declare the permission in your Manifest app file:

```xml
<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>

```

Then request the permission on your UI:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
fun checkNotificationPermission(activity: Activity, requestCode: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        val isNotificationPermissionAuthorized = ContextCompat.checkSelfPermission(activity,
            Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED

        if (!isNotificationPermissionAuthorized) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
                    Manifest.permission.POST_NOTIFICATIONS)) {
                // Display a message to explain why the user need to grant the permission
            } else {
                ActivityCompat.requestPermissions(activity,
                    arrayOf(Manifest.permission.POST_NOTIFICATIONS),
                    requestCode)
            }
        }
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
public void checkNotificationPermission(Activity activity, int requestCode) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        boolean isNotificationPermissionAuthorized = ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED;
        if (!isNotificationPermissionAuthorized) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity,
                    Manifest.permission.POST_NOTIFICATIONS)) {
                // Display a message to explain why the user need to grant the permission
            } else {
                ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.POST_NOTIFICATIONS }, requestCode);
            }
        }
    }
}
```

{% endtab %}
{% endtabs %}

## Full-screen intent permission

For Android 14 devices and above, it is now necessary to ask the user for this permission to display full screen notification for the [Crash Detection feedback](https://docs.drivequant.com/trip-analysis/crash-detection#configure-crash-detection-feedback) feature.

If the permission is not granted, the user will not receive full-screen notifications when the smartphone is locked, but instead an expanded heads-up notification on lockscreen. Find below an example of how to ask the full-screen intent permission:

First, declare the permission in your Manifest app file:

```xml
<manifest ...>
    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
    <application ...>
        ...
    </application>
</manifest>

```

Then request the permission on your UI:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    DiagnosisHelper.requestFullScreenPermission(activity)
}
```

{% endtab %}

{% tab title="Java" %}

```java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    DiagnosisHelper.INSTANCE.requestFullScreenPermission(activity);
}
```

{% endtab %}
{% endtabs %}

## Google Play Services

Trip Analysis component requires Google Play Services Location `21.0.1` or above.

You can check if Play Services are available on the device with the following code:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
fun checkGooglePlayServices() {
    val apiAvailability = GoogleApiAvailability.getInstance()
    val resultCode = apiAvailability.isGooglePlayServicesAvailable(this)
    if (resultCode != ConnectionResult.SUCCESS) {
        if (apiAvailability.isUserResolvableError(resultCode)) {
            apiAvailability.getErrorDialog(this, resultCode, 9000).show()
        }
    }
}
```

{% endtab %}
{% endtabs %}
