# Android Quick Start

Install the SDK, start it, and get a first verdict on an Android device.

:::note

Work through [Prerequisites](/docs/mobile/getting-started/prerequisites/) first. You will need a registered app (or a sandbox token for local development) and a plan for runtime permissions.

:::

---

## 1. Add the Maven repo

In your project's root `settings.gradle.kts`:

```kotlin
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven {
            url = uri("https://raw.githubusercontent.com/octetproof/octet-sdk-android/mvn-repo")
        }
    }
}
```

The OctetSDK Maven artifacts live on the `mvn-repo` orphan branch of the public `octet-sdk-android` repository.

---

## 2. Add the dependency

In your app `build.gradle.kts`:

```kotlin
dependencies {
    implementation("com.octetproof:sdk:3.1.2")
}
```

Pin 3.1.2 or later. If you are on 3.0, read [What's new in 3.1](/docs/mobile/whats-new/). If you are on 2.x, read [Upgrading from 2.x](/docs/mobile/getting-started/upgrading-from-2x/) first. If you are on 1.x, read [Migrating from 1.x](/docs/mobile/getting-started/migrating-from-1x/) as well.

Sync Gradle. The SDK's foreground permissions merge into your manifest automatically. For proofs while the app is backgrounded, add `ACCESS_BACKGROUND_LOCATION` to your own manifest. See [Prerequisites](/docs/mobile/getting-started/prerequisites/).

---

## 3. Request runtime permissions

The SDK needs a location permission to start, precise or approximate. Request `ACCESS_FINE_LOCATION` and `ACCESS_COARSE_LOCATION` together, so the user can choose. With approximate location only, country proofs work, finer levels return `INSUFFICIENT_PRECISION`, and a proof is at most `PLAUSIBLE`. Motion-classification confidence degrades without `ACTIVITY_RECOGNITION`. Request these before calling `Octet.start(...)`:

```kotlin
ActivityCompat.requestPermissions(
    this,
    arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACTIVITY_RECOGNITION,
    ),
    REQUEST_CODE
)
```

Wait for `onRequestPermissionsResult(...)` to confirm that a location permission, precise or approximate, was granted before continuing.

---

## 4. Start the SDK

`Octet.start(...)` bootstraps the license by attesting the app with Android hardware key attestation, then brings up the proof pipeline. On a real device, no key or token is needed (see [Prerequisites](/docs/mobile/getting-started/prerequisites/)).

```kotlin
import com.octetproof.sdk.api.Octet
import com.octetproof.sdk.api.OctetConfig

lifecycleScope.launch {
    val sdk = Octet.start(context = applicationContext, config = OctetConfig())
    // sdk is ready
}
```

On an **emulator** or a locally built debug build, there is no hardware attestation. Mint a sandbox bypass token (see [Prerequisites](/docs/mobile/getting-started/prerequisites/)) and pass it:

```kotlin
val config = OctetConfig(sandboxBypassToken = "octet_sbx_...")
```

`Octet.start(...)` is a `suspend` function. Any license or bootstrap problem throws a typed `LicenseError`. See [License Types](/docs/mobile/api-reference/license-types/) and [Attested bootstrap](/docs/mobile/concepts/attested-bootstrap/).

---

## 5. Query a region

```kotlin
import com.octetproof.sdk.api.OctetRegion
import com.octetproof.sdk.api.OctetVerdict
import java.time.Instant

val verdict = sdk.loc.isWithin(
    region = OctetRegion.country("US"),
    atTime = Instant.now()
)

when (verdict.result) {
    OctetVerdict.Result.YES ->
        println("YES, proof attached: ${verdict.proof != null}")
    OctetVerdict.Result.NO ->
        println("NO, provable negative")
    OctetVerdict.Result.INDETERMINATE ->
        println("INDETERMINATE, reason: ${verdict.reason}")
}
```

The predicate returns an [`OctetVerdict`](/docs/mobile/api-reference/octet-verdict/). Never treat `INDETERMINATE` as `NO`.

---

## 6. Close when done

When your proof flow ends, release the session and stop the location foreground service:

```kotlin
sdk.close()
```

See [Session Lifecycle](/docs/mobile/concepts/lifecycle/) for why this matters.

---

## 7. What to expect

- **On a real device, outdoors**, with cellular and GPS available, `isWithin(country("US"))` typically returns `YES` with an attached proof.
- **On the Android emulator** the verdict is always `INDETERMINATE / NO_FIX` with the message `running on emulator -- location proofs are unavailable in this environment`. Run on hardware to see the full flow.
- **On a real device, indoors**, a `country` query can often answer. See [Concepts: Verdicts](/docs/mobile/concepts/verdicts/).

---

## 8. Next steps

- The [Android sample app](/docs/mobile/samples/android-toy-app/) exercises this whole flow.
- [On-device Verification](/docs/mobile/concepts/on-device-verification/) checks a proof with [`Octet.verify`](/docs/mobile/api-reference/octet-verify/), offline.
- [Proof Binding](/docs/mobile/concepts/proof-binding/) ties a proof to a login or a decision, and `forceFresh` mints one on demand.
- [Verifying Proofs](/docs/mobile/concepts/verifying-proofs/) and the [Verifier Quick Start](/docs/mobile/getting-started/verifier-quickstart/) show independent verification.
- [What's new in 3.0](/docs/mobile/whats-new/) summarizes the release. The full notes are in the changelogs.
