0Pricing
Android Academy · Lesson

Location Permissions Done Right

Foreground and precise location.

Location Permissions Done Right is a free Android Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Permissions Are Not Optional

Location is one of Android's most sensitive permissions. Declaring it in the manifest isn't enough — on modern Android you must ask the user at runtime and handle every answer gracefully.

This lesson covers the permission tiers, requesting them in Compose, handling denials and the new precise vs approximate and background rules.

The Three Location Permissions

Android splits location into tiers:

  • ACCESS_COARSE_LOCATION — approximate (~city block).
  • ACCESS_FINE_LOCATION — precise (GPS-level).
  • ACCESS_BACKGROUND_LOCATION — access while your app isn't in the foreground.

Only request what you actually need. Background access triggers extra scrutiny on the Play Store.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- only if truly needed: -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Requesting Permissions in Compose

The Activity Result APIs give you a launcher for permission dialogs. In Compose, use rememberLauncherForActivityResult with the RequestMultiplePermissions contract.

import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts

val launcher = rememberLauncherForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { result ->
    val fine = result[Manifest.permission.ACCESS_FINE_LOCATION] == true
    val coarse = result[Manifest.permission.ACCESS_COARSE_LOCATION] == true
    // react to the user's choice
}

Launching the Request

Trigger the dialog by calling launch() with the array of permissions — typically in response to a button tap, not automatically on screen load.

Button(onClick = {
    launcher.launch(
        arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
    )
}) {
    Text("Enable location")
}

Checking If Already Granted

Don't re-prompt if the permission is already granted. Check with ContextCompat.checkSelfPermission before launching the request.

import androidx.core.content.ContextCompat
import android.content.pm.PackageManager

fun hasFineLocation(context: Context): Boolean {
    return ContextCompat.checkSelfPermission(
        context,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED
}

Precise vs Approximate

Since Android 12 (API 31), users can grant approximate location even when you asked for fine. So you must request both fine and coarse together, and accept that the user may downgrade you to coarse.

Design your feature to work acceptably with approximate location where possible.

// Request both — the system shows a Precise/Approximate toggle
launcher.launch(
    arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION
    )
)
// If only COARSE comes back granted, you got approximate location.

Showing a Rationale

If the user denied once, Android lets you check shouldShowRequestPermissionRationale. When it's true, show a friendly explanation of why you need location before asking again.

import androidx.core.app.ActivityCompat

val shouldExplain = ActivityCompat.shouldShowRequestPermissionRationale(
    activity,
    Manifest.permission.ACCESS_FINE_LOCATION
)
if (shouldExplain) {
    // show a dialog: "We use your location to find nearby stores"
}

Handling Permanent Denial

If the user picks Don't ask again (or denies twice), the system no longer shows the dialog. Your only path is to send them to app settings to enable it manually.

import android.content.Intent
import android.provider.Settings
import android.net.Uri

fun openAppSettings(context: Context) {
    val intent = Intent(
        Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
        Uri.fromParts("package", context.packageName, null)
    )
    context.startActivity(intent)
}

Using Accompanist Permissions

The accompanist-permissions library wraps all of this in Compose-friendly state. rememberMultiplePermissionsState tracks granted status and exposes a launchMultiplePermissionRequest() call.

import com.google.accompanist.permissions.rememberMultiplePermissionsState

val permissions = rememberMultiplePermissionsState(
    listOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION
    )
)

if (permissions.allPermissionsGranted) {
    // show the map / read location
} else {
    Button(onClick = { permissions.launchMultiplePermissionRequest() }) {
        Text("Grant location")
    }
}

Background Location Rules

Background location requires a two-step flow: first grant foreground (fine/coarse), then separately request ACCESS_BACKGROUND_LOCATION, which opens system settings on Android 11+. The Play Store demands a clear justification and a privacy policy.

Only ask for it if your app genuinely needs location while closed — geofencing, fitness tracking, etc.

// Step 1: request foreground first and confirm it's granted.
// Step 2: only then request background:
launcher.launch(
    arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
)
// On Android 11+ this sends the user to settings to pick "Allow all the time".

A Permission-Gated Map

Tie it together: gate the map behind the permission state. Show the map only once granted, otherwise show a request prompt. This is the standard, user-respecting pattern.

@Composable
fun LocationGate(permissions: MultiplePermissionsState) {
    when {
        permissions.allPermissionsGranted -> MapScreen()
        else -> Column {
            Text("We need location to show nearby places.")
            Button(onClick = { permissions.launchMultiplePermissionRequest() }) {
                Text("Allow location")
            }
        }
    }
}

Quick Check

Since Android 12, a user can choose Approximate instead of Precise location. What does this mean for your request?

Recap

You now know how to request location responsibly:

  • Declare coarse/fine (and background only if essential) in the manifest.
  • Request at runtime with Activity Result APIs or accompanist-permissions.
  • Request fine + coarse together to support the precise/approximate toggle.
  • Show a rationale, and route permanently-denied users to app settings.
  • Handle background location as a separate, justified two-step flow.

That completes Maps & Location Services — you can show a map, find the user, place markers, and ask for permission the right way.

Frequently asked questions

Is the “Location Permissions Done Right” lesson free?

Yes — the full text of “Location Permissions Done Right” is free to read here on the web, and the Android Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Android Academy course, upgrade to CoddyKit PRO.

What will I learn in “Location Permissions Done Right”?

Foreground and precise location. You practise Android Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Android Academy?

No prior experience is required. Android Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Location Permissions Done Right” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Android Academy lesson?

Yes. Every Android Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Showing a Map
  2. Getting the User Location
  3. Markers and Camera
  4. Location Permissions Done Right
← Back to Android Academy