> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rinne.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Device setup

> Show the merchant where the NFC antenna is with AntennaSetup, check NFC, location, connectivity and Play services before a sale with checkDeviceReadiness, and know what attestation still decides.

A merchant's first minutes with Tap on Phone decide whether they trust it. The SDK ships two helpers for that moment: an antenna guide that shows where to hold the card, and a readiness check that reports what is missing before a customer is waiting. Neither needs a terminal, a token or a card.

## Show where to tap

Open the antenna guide once, before the first sale. It walks the merchant through three screens: where to hold the card, the antenna's position on the back of this phone, and a test tap that confirms the spot. It returns `true` when the merchant taps a card where the guide points.

```kotlin theme={null}
import com.rinne.sdk.checkout.AntennaSetup

private val antenna = registerForActivityResult(AntennaSetup.Contract()) { confirmed ->
    if (confirmed) markOnboardingDone()
}

antenna.launch(Unit)
```

The guide inherits the last `CheckoutConfig` you passed to `Payments.getReady`, so it wears your brand. The test tap reads nothing from the card: it only proves the antenna works.

<Note>
  Android reports the antenna's coordinates only from Android 14 (API 34), and only on devices that publish them. On older or silent devices the guide says the position is approximate and gives generic advice instead of pointing at a spot. A marker in the wrong place would send the merchant looking for a faulty card, so the SDK never guesses.
</Note>

## Read the NFC state yourself

For your own onboarding or settings screens, the `Nfc` helpers answer the same questions without opening a screen:

```kotlin theme={null}
import com.rinne.sdk.Nfc

when (Nfc.status(context)) {
    Nfc.Status.READY -> showReady()
    Nfc.Status.DISABLED -> askToEnableNfc()
    Nfc.Status.UNAVAILABLE -> showUnsupportedDevice()
}

val antenna = Nfc.antennaInfo(context)   // null below API 34 or when the device reports nothing
```

`Nfc.enableTapTest(activity) { }` starts a test tap that fires when any contactless card touches the antenna, without reading it; pair it with `Nfc.disableTapTest(activity)` in `onPause`.

## Check readiness before a sale

`Payments.checkDeviceReadiness` runs without credentials and reports one entry per check, so a merchant learns that NFC is off during setup instead of with a customer waiting.

```kotlin theme={null}
val readiness = Payments.checkDeviceReadiness(context)
if (!readiness.isReady) {
    readiness.blocking.forEach { check -> showBlocker(check.id, check.detail) }
}
```

| `ReadinessCheckId` | Blocking when it fails | What it checks                                       |
| ------------------ | ---------------------- | ---------------------------------------------------- |
| `NFC`              | Yes                    | NFC is present and switched on                       |
| `LOCATION`         | Yes                    | Location permission granted and location services on |
| `PLAY_SERVICES`    | Yes                    | Google Play services present and current             |
| `CONNECTIVITY`     | Yes                    | A validated network; a captive portal fails          |
| `OS_PATCH_LEVEL`   | No                     | Security patch level newer than a year               |

A device can pass every check and still be refused with `ATTESTATION_FAILED`. The integrity check runs inside the card reader before every transaction and is not something this pre-flight can predict. Emulators, rooted devices, unlocked bootloaders and custom ROMs fail it by design.

## What the checkout handles for you

* **Location permission.** The managed checkout asks for `ACCESS_FINE_LOCATION` before the first charge and shows a dedicated screen with an **Allow location** button when it is denied. Location is a hard requirement of the card reader.
* **Keep the screen on.** The payment screen keeps the display on for the whole transaction and releases it afterwards, without a wake lock or a permission.
* **The certified PIN pad.** It draws over your app; nothing in your app may draw over it. Screen recording, a busy camera or microphone, or an overlay from another app blocks PIN entry with `SECURE_ENTRY_BLOCKED` until they stop.

## Troubleshooting

| Symptom                                                           | Likely cause                                                                                                                  |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| The card is never read                                            | NFC off, or the card held away from the antenna. Open `AntennaSetup`, and check `Nfc.status`.                                 |
| `LOCATION_UNAVAILABLE` on every sale                              | Location denied or location services off. The failed screen offers to grant it.                                               |
| `ATTESTATION_FAILED` on a phone that passes every readiness check | Emulator, rooted device, unlocked bootloader, missing Play services, or a build not installed from Google Play in production. |
| `CONNECTIVITY` fails on a network that "works"                    | A captive portal. The check requires a validated connection.                                                                  |

## Next steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/tap-on-phone/android/quickstart">
    Prepare the terminal and take a sandbox payment.
  </Card>

  <Card title="Going to production" icon="rocket-launch" href="/tap-on-phone/android/production">
    Install source, Play Integrity, permissions and the go-live checklist.
  </Card>
</CardGroup>
