Android Academy · Lesson

Location Permissions Done Right

Foreground and precise location.

Lesson 4 of 413 steps

Location Permissions Done Right is a free Android Academy lesson on CoddyKit. This is lesson 4 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Android Academy learning path, and your progress syncs across the web and the CoddyKit app. The Android Academy course includes 4 lessons in total.

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.

Free to start

Learn Kotlin with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
36
Lessons
152

Frequently Asked Questions

Is the “Location Permissions Done Right” lesson free?

Yes — any 3 lessons of the Android Academy learning path, including “Location Permissions Done Right”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Android Academy course includes 4 lessons in total.

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, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

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