Android Q privacy change: User control over app access to device location

As of Android Q Beta 4, this change has the following properties:

  • Affects your app if you request access to device location while in the background
  • The user might receive a reminder after giving an app access to device location 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

We're interested in hearing your feedback! Report issues you find when using this feature during the Android Q beta program.

Screen capture of user-facing dialog
Figure 1. Dialog requesting user consent for location

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 using the app (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 device 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:

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 device'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 device location only in the foreground.
  • Your app's use case relies on periodic checks of a device'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 give your app access to device location all the time in order to operate correctly, then request access to background location.

Continuation of user-initiated action

Note: If your app doesn't require location access while running in the background, it's a best practice to target Android Q and not request the new background location permission. That way, your app only receives location updates while the user is using the app.

An example of such an app appears in the LocationUpdatesForegroundService project on GitHub.

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 device'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 device'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 device's location

Your app might have a use case that requires access to the device'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 the device's location.

The following code snippet demonstrates how to declare a service that requests access to device location all the time:

<!-- It's unnecessary to include a foreground service type for services that must have
     access to the device's location "all the time" in order to run successfully.-->
<service
    android:name="MyFamilyLocationSharingService" ... >
    ...
</service>

An example of such an app is the LocationUpdatesPendingIntent project on GitHub.

Screen capture of system notification
Figure 2. Notification reminding user that they've granted an app "all-the-time" access to device location

Each time the user chooses to allow your app all-the-time access to device location, the system schedules a notification to send to the user. This notification reminds the user that they've allowed your app to access device location all the time. An example notification appears in Figure 2.

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 a workflow within 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 3 appears:

Screen capture of user-facing dialog
Figure 3. Dialog requesting user consent for all-the-time access to location

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 device'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 device'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);
}

Design for device upgrade scenarios

If a user completes the following steps:

  1. Installs your app on a device running Android 9 (API level 28).
  2. Grants your app access to device location – either ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION.
  3. Upgrades their device from Android 9 to Android Q.

...then the system automatically updates your app's default location permission state based on its target SDK version and its defined permissions, as shown in the following table:

Table 1. Changes in location permission state after device upgrade to Android Q

Target SDK version Coarse or fine
permission granted?
Background permission
defined in manifest?
Updated default permission state
Android Q Yes Yes Foreground and background access
Android Q Yes No Foreground access only
Android Q No (Ignored by system) No access
Android 9 or lower Yes Automatically added by the system at device upgrade time Foreground and background access
Android 9 or lower No (Ignored by system) No access

Note: Even after the system automatically updates your app's access to device location, the user has the option to change this level of access. The user might reduce your app's access to foreground only or revoke access entirely.

For this reason, before accessing the device's location updates, follow best practices to check whether the user still allows your app to receive this location information.

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 level of access to device 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.

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.

Additional resources

For more information about changes regarding an app's access to device location, see the following additional resources:

Samples