# Android Quick Start

From zero to a `YES` verdict on an Android device in ten minutes.

:::note

Work through [Prerequisites](/docs/getting-started/prerequisites/) first. You will need a license key 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:1.2.1")
}
```

Pin 1.2.1 or later. Versions 1.0.0, 1.1.0, and 1.2.0 are deprecated for security reasons, and their artifacts have been removed from the Maven repo, so a build pinned to one of them no longer resolves.

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

### Verify the download (optional)

Each release publishes a SHA-256 checksum, SLSA build provenance, an SBOM (software bill of materials), and a keyless cosign signature for the AAR. To check them in a release pipeline, follow the "Verifying the download" section of [`INTEGRATION.md`](https://github.com/octetproof/octet-sdk-android/blob/main/INTEGRATION.md). A build runs without this step.

---

## 3. Request runtime permissions

The SDK refuses to start without `ACCESS_FINE_LOCATION`. Motion-classification confidence degrades without `ACTIVITY_RECOGNITION`. Request both before calling `Octet.start(...)`:

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

Wait for `onRequestPermissionsResult(...)` to confirm `ACCESS_FINE_LOCATION` was granted before continuing.

---

## 4. Start the SDK

:::tip[Don't have a key yet?]
`licenseKey` is a placeholder. Get a free key (free for up to 1,000 proofs a month, no credit card) at **[sdk.octetproof.com/signup](https://sdk.octetproof.com/signup)**, then paste it in.
:::

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

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

`Octet.start(...)` is a `suspend` function. Call it from a coroutine scope (`lifecycleScope`, `viewModelScope`, or your own). On first launch the SDK verifies the license key locally, exchanges it for an activation token via `api.octetproof.com/v1/activate`, caches the token in `EncryptedSharedPreferences`, and brings up the proof pipeline.

Any license problem throws a typed `LicenseError`. See [License Types](/docs/api-reference/license-types/).

---

## 5. Ask your first question

```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/api-reference/octet-verdict/). Never treat `INDETERMINATE` as `NO`.

---

## 6. 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 will always be `INDETERMINATE / NO_FIX` with the message `running on emulator -- location proofs are unavailable in this environment`. This is by design. The emulator's mock-location flag blocks proof generation. **Run on hardware** to see the full flow.
- **On a real device, indoors**, the first proof on Android usually arrives quickly via the cell-tower MCC signal even without GPS. `isWithin(country(...))` typically succeeds with `HIGH` confidence indoors on Android. Finer-grained predicates (city, polygon) may need a GPS fix. See [Concepts: Verdicts](/docs/concepts/verdicts/).

---

## 7. From here

- The [Android sample app](/docs/samples/android-toy-app/) is a single-button activity that exercises this whole flow.
- [Concepts: Proof of Location](/docs/concepts/proof-of-location/) explains what a verdict proves.
- [Session-binding](/docs/concepts/session-binding/) ties a proof to a specific login, so your verifier can confirm the proof was made for that login.
- [Verifying Proofs](/docs/concepts/verifying-proofs/) and the [Verifier Quick Start](/docs/getting-started/verifier-quickstart/) show how anyone can independently check the proofs your app produces.
- [What's new in 1.2](/docs/whats-new/) lists the API added since 1.1.
- [API Reference Overview](/docs/api-reference/overview/) maps the public surface.
