As of Android Q Beta 1, this change has the following properties:
- Affects your app if you request access to the user's location while in the background
- Mitigate by using new permission to access location in the background and by ensuring graceful degradation in the absence of background location updates
- Behavior is always enabled on Android Q
Android Q gives users more control over when apps can get access to device location. When an app running on Android Q requests location access, users see the dialog shown in Figure 1. This dialog allows users to grant location access to two different extents: while in use (foreground only) or all the time (foreground and background).
To support the additional control that users have over an app's access to location information, Android Q introduces a new location permission, ACCESS_BACKGROUND_LOCATION
. Unlike the existing ACCESS_FINE_LOCATION
and ACCESS_COARSE_LOCATION
permissions, the new permission only affects an app's access to location when it's running in the background. An app is considered to be in the background unless one of its activities is visible or the app is running a foreground service.
Request background location
If your app targets Android Q and needs to access the user's location when running in the background, you must declare the new permission in your app's manifest file:
<manifest> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> </manifest>
If your app runs on Android Q but targets Android 9 (API level 28) or lower, the following behavior applies:
- If your app declares a
<uses-permission>
tag for eitherACCESS_FINE_LOCATION
orACCESS_COARSE_LOCATION
, the system automatically adds a<uses-permission>
tag forACCESS_BACKGROUND_LOCATION
during installation. - If your app requests either
ACCESS_FINE_LOCATION
orACCESS_COARSE_LOCATION
, the system automatically addsACCESS_BACKGROUND_LOCATION
to the request.
Request background location access
If your app's use case requires access to location information when running in the background, it's important to consider the extent to which you need this access:
- Your app's use case relies on a continuation of a user-initiated action , such as navigation or a smart home action. In that case, configure your foreground service so that it can retain access to a user's location after the user presses the Home button on their device or turns their device display off, even if the user has requested that your app have access to their location only in the foreground.
- Your app's use case relies on periodic checks of a user's location all the time, such as geofencing or location sharing. In that case, your app should explain to the user that they need to allow your app to access their location all the time in order to operate correctly, then request access to background location.
Continuation of user-initiated action
In cases where the user has given your app foreground-only access to location, the user might still launch a workflow that requires your app to access their location, even after the user presses the Home button on their device or turns their device's display off.
To retain access to the user's location in this specific use case, start a foreground service that you've declared as having a foreground service type of "location"
in your app's manifest:
<service android:name="MyNavigationService" android:foregroundServiceType="location" ... > ... </service>
Before starting the foreground service, make sure that your app still has access to the user's location:
Kotlin
val permissionAccessCoarseLocationApproved = ActivityCompat .checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED if (permissionAccessCoarseLocationApproved) { // App has permission to access location in the foreground. Start your // foreground service that has a foreground service type of "location". } else { // Make a request for foreground-only location access. ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION), YOUR_PERMISSION_REQUEST_CODE ) }
Java
boolean permissionAccessCoarseLocationApproved = ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (permissionAccessCoarseLocationApproved) { // App has permission to access location in the foreground. Start your // foreground service that has a foreground service type of "location". } else { // Make a request for foreground-only location access. ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION}, YOUR_PERMISSION_REQUEST_CODE); }
Periodic checks of user's location
Your app might have a use case that requires access to the user's location all the time. Such use cases include geofencing and location sharing with friends and family.
If these conditions apply to your app, you can continue requesting location updates without any changes, as long as the user grants your app all-the-time access to their location:
<!-- It's unnecessary to include a foreground service type for services that must have access to the user's location "all the time" in order to run successfully.--> <service android:name="MyFamilyLocationSharingService" ... > ... </service>
Although your app can request access to location in the background, the user has the option to reduce your app's access to foreground only or revoke access entirely. For this reason, whenever your app starts a service, check whether the user still allows your app to access location information in the background.
If the user has requested that your app access location only in the foreground, it's a best practice for your app to display a custom dialog, alerting the user that your app cannot function properly without access to their location all the time. After the user acknowledges this dialog, you can request background location, at which time the system dialog shown in Figure 2 appears:
An example of this permission-checking logic appears in the following code snippet:
Kotlin
val permissionAccessCoarseLocationApproved = ActivityCompat .checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED if (permissionAccessCoarseLocationApproved) { val backgroundLocationPermissionApproved = ActivityCompat .checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED if (backgroundLocationPermissionApproved) { // App can access location both in the foreground and in the background. // Start your service that doesn't have a foreground service type // defined. } else { // App can only access location in the foreground. Display a dialog // warning the user that your app must have all-the-time access to // location in order to function properly. Then, request background // location. ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), YOUR_PERMISSION_REQUEST_CODE ) } } else { // App doesn't have access to the user's location at all. Make full request // for permission. ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), YOUR_PERMISSION_REQUEST_CODE ) }
Java
boolean permissionAccessCoarseLocationApproved = ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (permissionAccessCoarseLocationApproved) { boolean backgroundLocationPermissionApproved = ActivityCompat.checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED; if (backgroundLocationPermissionApproved) { // App can access location both in the foreground and in the background. // Start your service that doesn't have a foreground service type // defined. } else { // App can only access location in the foreground. Display a dialog // warning the user that your app must have all-the-time access to // location in order to function properly. Then, request background // location. ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_BACKGROUND_LOCATION}, YOUR_PERMISSION_REQUEST_CODE); } } else { // App doesn't have access to the user's location at all. Make full request // for permission. ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION }, YOUR_PERMISSION_REQUEST_CODE); }
Follow location best practices
By checking and requesting location permissions in the ways shown in this guide, your app can successfully keep track of its access level regarding the user's location.
For more information about how to keep your users' data safe, see the permissions best practices guide.
Ask only for the permissions you need
Ask for permissions only when needed. For example:
- Don't request a location permission at app startup unless absolutely necessary.
- If your app targets Android Q and needs access to location information only when running in the foreground, don't request
ACCESS_BACKGROUND_LOCATION
.
READ ALSO:
Guardian Mobile Firewall
Support graceful degradation if permission isn't granted
To maintain a good user experience, design your app so that it can gracefully handle the following situations:
- Your app doesn't have any access to location information.
- Your app doesn't have access to location information when running in the background.