# Android Sample: OctetV1Toy

Minimal demo of the OctetSDK public API: **one button, one verdict**. Use it to confirm your environment is set up correctly and to play with the predicate API without the noise of a full app.

The sample lives under [`octet-sdk-android/sample/`](https://github.com/octetproof/octet-sdk-android/tree/main/sample). It is a standalone Gradle project. `git clone`, configure your license key, and build. The SDK is resolved from the parent repo's Maven branch. There is no source dependency. The same instructions below also live in [`sample/README.md`](https://github.com/octetproof/octet-sdk-android/blob/main/sample/README.md) in that repository. Handy if you're working offline.

## What it does

- Requests `ACCESS_FINE_LOCATION` at runtime.
- Calls `Octet.start(context, OctetConfig(licenseKey = ...))`. The SDK verifies your license, activates against `api.octetproof.com/v1/activate` on first run, caches the token in `EncryptedSharedPreferences`, and brings up the proof pipeline.
- On button tap, runs `sdk.loc.isWithin(OctetRegion.country("US"), Instant.now())` and renders the verdict.

## Build and run

### 1. Get a license key

Free key from [sdk.octetproof.com/signup](https://sdk.octetproof.com/signup).

### 2. Configure your local copy

```bash
cd octet-sdk-android/sample
cp local.properties.example local.properties
```

Open `local.properties` and fill in:

- **`octet.licenseKey`**. Paste your key. Missing it isn't a build error. The app launches and throws `LicenseError.MalformedKey` at `Octet.start`.
- **`sdk.dir`**. Android SDK install path. Android Studio writes this automatically the first time you open the project, so leave it commented out if you only build from the IDE. If you build from the CLI (`./gradlew ...`) on a machine that hasn't run Studio against this project yet, uncomment and set the path (e.g. `/Users/<you>/Library/Android/sdk` on macOS) or export `ANDROID_HOME` in your shell.

`local.properties` is gitignored.

### 3. Enable USB debugging

Settings -> About -> tap *Build number* 7x to unlock Developer options, then enable *USB debugging*. Confirm:

```bash
adb devices
```

### 4. Build and run

Pick whichever path fits your workflow.

#### Using Android Studio (recommended)

1. **File -> Open** -> select the `octet-sdk-android/sample/` folder.
2. Wait for the initial Gradle sync to finish (~1 min the first time).
3. Plug in your device (USB debugging enabled per step 3).
4. Click the green **Run ** button (or Shift+F10 / Ctrl+R on macOS).

Studio handles the install, launch, and log streaming. Subsequent runs are quick.

#### From the command line

Install in one step:

```bash
./gradlew :app:installDebug
```

Or build the APK and sideload manually:

```bash
./gradlew :app:assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
```

### 5. First-launch permissions

A single prompt for **Location**. Grant it. The SDK refuses to start otherwise. Tap the button to fire a verdict.

## Annotated source

The whole activity is ~90 lines. The interesting bits:

```kotlin
// Bring up the SDK once permission is granted.
lifecycleScope.launch {
    val config = OctetConfig(licenseKey = BuildConfig.OCTET_LICENSE_KEY)
    val sdk = Octet.start(this@MainActivity, config)
}
```

```kotlin
// Fire a verdict on button tap.
val verdict = sdk.loc.isWithin(
    region = OctetRegion.country("US"),
    atTime = Instant.now()
)
```

```kotlin
// Render it.
buildString {
    append("result:  ").append(verdict.result).append('\n')
    append("reason:  ").append(verdict.reason).append('\n')
    append("message: ").append(verdict.message).append('\n')
    append("proof:   ").append(verdict.proof != null)
}
```

The license key is wired through `BuildConfig.OCTET_LICENSE_KEY`, generated from the `octet.licenseKey` line in `local.properties` at build time.

## Why emulator runs always return `INDETERMINATE`

`isWithin(country("US"))` from the Android emulator returns:

```
result:  INDETERMINATE
reason:  NO_FIX
message: running on emulator -- location proofs are unavailable in this environment
```

This is by design. The emulator's "telnet geo fix" provider sets `Location.isMock = true`, and the SDK's spoof-detection pipeline blocks proof generation. **Run on a real device** to see the full flow.

The SDK detects Android Studio AVDs (`goldfish` / `ranchu` / `sdk_gphone`), Genymotion, BlueStacks, and other generic / test-keys images. Custom ROMs that rewrite `Build.*` fields can defeat this. The check is a developer hint, not a security gate.

## A pre-built APK on every release

Each [GitHub Release](https://github.com/octetproof/octet-sdk-android/releases) attaches an unsigned debug-style APK for shape verification. It still needs a per-developer Octet license key to actually run. Wire it via `octet.licenseKey` in `local.properties` at build time, or `BuildConfig.OCTET_LICENSE_KEY` at runtime.

## Requirements

- Android 11 (API 30)+ on the device
- Android Studio Hedgehog (2023.1.1)+
- JDK 17
- A valid OctetSDK license key

## See also

- [Android Quick Start](/docs/getting-started/android-quickstart/). Integrating the SDK into your own app from scratch.
- [Troubleshooting FAQ](/docs/troubleshooting/faq/). What to do when verdicts don't look right.
