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

# Android リファレンス

> OneS1ght Android SDK の全 API シグネチャ・モデル・エラー定義です。

<Info>
  このドキュメントは **v0.0.4** 基準です。稼働中のバージョンは `OneS1ght.SDK_VERSION` で確認できます。
</Info>

`OneS1ght` はアプリ全体で 1 つだけの `object` エントリーポイントです — インスタンスは作らず、すべての API を直接呼び出します。
非同期 API は**同じ名前で 2 つの形式**があります — Kotlin は `suspend fun`、Java は最後の引数に `Callback<T>` を受け取る形式です。
以下の表は Kotlin の形式で記載しています。

```kotlin theme={null}
import co.onecheck.ones1ght.android.*          // OneS1ght · FloorSession · SdkError · リスナー
import co.onecheck.ones1ght.android.model.*    // Building · Floor · Zone · Coordinates · Trigger · ConfigChange
```

## ライフサイクル

| API | 説明 |
| - | - |
| `suspend initialize(context: Context, sdkKey: String, baseUrl: String = …)` | アプリ起動時に 1 回。キー検証 → 設定の読み込み。冪等 — 成功後の再呼び出しは無視、失敗後の再呼び出しは再試行、**別のキーで再呼び出しするとセッションを再構成** |
| `suspend permissions(activity: ComponentActivity): PermissionStatus` | 測位権限（`RANGING` + 正確な位置情報）の確認・リクエスト — **必要に応じてシステムダイアログが表示されます**。`initialize` の前でも呼び出し可能 |
| `suspend reset()` | セッションを破棄。その後、別のキーで `initialize` 可能（実行時のキー切り替え用） |
| `setLanguage(code: String?)` | SDK のログ・案内文の言語 — `"ko"`·`"ja"`·`"en"`。`null` の場合は端末の言語（既定値） |

`initialize` のパラメーター:

| パラメーター | 型 | 説明 |
| - | - | - |
| `context` | `Context` | アプリの Context。SDK は `applicationContext` のみを保持します |
| `sdkKey` | `String` | OneS1ght コンソールで発行（`ock_sdk_…`）。**アプリが渡すキーはこれ 1 つだけ**で、測位に必要なその他のキーは SDK がサーバーから直接取得します |
| `baseUrl` | `String`（既定は運用サーバー） | 自社サーバーを構築したお客様のみ。運用/開発の区別はこの引数ではなく**キー**で決まります |

既定の `baseUrl` は `https://console.ones1ght.com/api/sdk/v1` です。

<Warning>
  **`initialize` は建物・フロアを取得せず、端末の対応状況も確認しません。** 非対応端末も初期化は通過し（図面・ゾーンの取得は可能）、
  測位の開始（`begin()`）でのみ拒否されます。空間の設定は `setFloorMap` の役割です。
</Warning>

## 測位セッション — FloorSession

```kotlin theme={null}
val session = OneS1ght.floorSession()
```

| API | 説明 |
| - | - |
| `floorSession(): FloorSession` | セッションの取得。**常に同じインスタンス** — UWB 無線・判定エンジン・座標バッファは端末ごとに 1 つ。`initialize` を一度も呼んでいない場合は `SdkError.NotInitialized` |
| `session.begin()` | 測位開始（店舗への入店時）。`suspend` |
| `session.begin(provider: PositioningProvider)` | カスタム測位の注入 — テスト・デモ用（`MockPositioningProvider`）。座標のみを供給し、ゾーンコールバックは発生しません |
| `session.end()` | 測位停止 + 残りの座標を送信。初期化・フロアは維持 → `begin` の再呼び出しで再開可能。`suspend` |
| `session.pause()` | **一時停止** — 座標の表示・送信・ゾーン判定のみ止め、**エンジンは動作し続けます**。再開は即時です |
| `session.resume()` | 一時停止の解除。判定器をクリアして続けて受け取ります |
| `session.floor: Floor?` | 現在指定されているフロア |
| `session.isRunning: Boolean` | 測位が稼働中かどうか |
| `session.isPaused: Boolean` | 一時停止中かどうか。`begin`・`end` はこの状態を引き継ぎません |

## コールバック

セッションのコールバックは `FloorSession` インスタンスに、デバッグログは `OneS1ght` に登録します。すべてのコールバックは
**メインスレッド**で呼び出されます。リスナーは `fun interface` のため、Kotlin では `ZoneListener { zone -> … }`、Java ではラムダで登録します。

| コールバック | リスナー | 説明 |
| - | - | - |
| `session.onPosition` | `PositionListener` — `(Coordinates)` | リアルタイム座標（図面ローカルのメートル） |
| `session.onZoneEnter` | `ZoneListener` — `(Zone)` | ゾーン進入 — 端末内の判定で即時（サーバー往復なし） |
| `session.onZoneExit` | `ZoneListener` — `(Zone)` | ゾーン退出 |
| `session.onZoneDwell` | `DwellListener` — `(Zone, Double)` | 滞在 — （ゾーン、滞在秒数）。ゾーンごとに 1 回 |
| `session.onTriggers` | `TriggersListener` — `(String, List<Trigger>)` | （zoneId、トリガー一覧）— **サーバーがマッチング**したパーソナライズアクション |
| `session.onConfigChanged` | `ConfigChangeListener` — `(ConfigChange)` | コンソールでゾーン・図面・施策が変わると通知 — 測位中のみ有効 |
| `OneS1ght.onDebugLog` | `DebugLogListener` — `(LogLevel, String)` | SDK の内部動作ログ。`initialize` より先に登録しないと初期化ログを取り逃します |

### ConfigChange — コンソールの変更

| ケース | 意味 | 推奨される対応 |
| - | - | - |
| `ZonesChanged(floorId)` | ゾーンが作成・変更・削除された | `refreshZones()`（連続受信は 1 秒ほどまとめて） |
| `PlanChanged(floorId)` | フロアの図面が変わった | 図面を描き直す |
| `RulesChanged(zoneId)` | 施策の状態が変わった | 滞在中のゾーンのイベントを再取得 |
| `SdkConfigChanged(rateHz, logLevel)` | リモート設定が変わった | — |
| `ResyncNeeded` | 接続が再確立された、またはイベントを取り逃した | 使用中の情報をまとめて再取得 |

### LogLevel — ログレベル

```kotlin theme={null}
enum class LogLevel { LOG, INFO, WARN, ERROR }   // LOG < INFO < WARN < ERROR
```

`import co.onecheck.ones1ght.android.runtime.LogLevel` でインポートします。宣言順に比較できるため、
`level >= LogLevel.WARN` のように絞り込めます。

| レベル | 意味 |
| - | - |
| `LOG` | 流れの記録 — 普段は見なくても構いません |
| `INFO` | 知っておくとよいこと — 正常ですが、目に留まると役立ちます |
| `WARN` | 確認が必要なこと — 故障ではありませんが、このままでは期待どおりに動きません |
| `ERROR` | 故障 — 対処しないとその機能は動作しません |

<Warning>
  サーバーの応答は `onTriggers` だけです — ネットワークが切れると進入判定は届きますが、トリガーは届きません。
</Warning>

## 空間の取得

エンドポイント 1 つにつきメソッド 1 つで、一覧と単体が対になっています。すべて `suspend` です。

| API | 説明 |
| - | - |
| `buildings(): List<Building>` | 建物一覧。コンソールに連携された空間がなければ空の一覧 |
| `building(buildingId): Building` | 建物 1 件 |
| `floors(buildingId): List<Floor>` | フロア一覧 — **図面画像なし**（`image == null`、一覧を軽く保つため） |
| `floor(buildingId, floorId): Floor` | フロア 1 件 — 図面画像を含む（キャッシュから返るためリクエストは増えません） |
| `zones(buildingId, floorId): List<Zone>` | フロアのゾーン一覧 |
| `zone(buildingId, floorId, zoneId): Zone` | ゾーン 1 件 |
| `locators(buildingId, floorId): FloorLocators` | フロアのロケーター配置と UWB セッション ID |

## フロアの指定

| API | 説明 |
| - | - |
| `suspend setFloorMap(floor: Floor?, buildingId: String? = null)` | フロアの指定 — ロケーター・セッション・ゾーンを測位パイプラインに注入。稼働中は**即時にフロアを切り替え**（セッション維持）。`null` で解除。`buildingId` を省略すると直前の建物 |
| `suspend refreshZones(): List<Zone>` | 現在のフロアのゾーンのみ再取得（軽量 — 図面の再ダウンロードなし）。判定に即時反映。失敗しても例外を投げず、手元のゾーンを返します |

<Warning>
  エンジンが BLE でフロアを自ら見つけるため、**`setFloorMap` なしでも座標は出ます**（`E3001`、WARN — 正常な
  経路）。ただし**ゾーンイベント**（進入・退出・滞在）を受け取るには `setFloorMap` でフロアを指定する必要が
  あります — エンジンの領域名に対応するコンソールゾーンがないと `E3009`、エンジンが検出したフロアと指定
  フロアが異なると `E3008`、20 秒以内にフロアが見つからないと `E3007` が出力されます。
</Warning>

## プロフィール

| API | 説明 |
| - | - |
| `suspend createProfile(attributes: Map<String, String>): String` | プロフィールの作成 — サーバーが発行した `profileId` を返します。**アプリで保存して再利用** |
| `suspend getProfile(profileId): Map<String, String>` | 属性の取得 |
| `suspend putProfile(profileId, attributes)` | 属性を**すべて置き換え**（部分更新ではありません） |
| `suspend deleteProfile(profileId)` | プロフィールの削除 |
| `identify(profileId: String?)` | 連携 — 測位の前に必ず、**`initialize` の後に**。ログアウト時は `null`。メインスレッドで呼び出し |

<Note>
  貴社の会員 ID はサーバーに送られません — 対応関係は貴社のみが保持します。
</Note>

## データ送信

座標は **300 件または 60 秒**のうち先に達した時点で送信されます。
バックグラウンドへの移行時と `end()` 時にも残りの座標を送信します。

| API | 説明 |
| - | - |
| `suspend send()` | バッファを今すぐ送信 |
| `empty()` | バッファを**破棄** — 送信しません。メインスレッドで呼び出し |

## 状態の取得

| API | 型 | 説明 |
| - | - | - |
| `isInitialized` | `Boolean` | 初期化に成功したか（キー有効 + 設定読み込み済み） |
| `deviceAvailability` | `DeviceAvailability` | 測位可否 + 不可の理由。ネットワーク不使用。**`initialize` の後に読む** |
| `isDeviceAvailable` | `Boolean` | 上記の簡易版（`== AVAILABLE`） |
| `googleMapKey` | `String?` | コンソールから提供される Google Maps キー — アプリ独自の地図を描く場合に使用。`initialize` 成功前は `null` |
| `SDK_VERSION` | `String` | SDK バージョン（例: `"0.0.4"`） |

Java からは getter で読みます — `OneS1ght.isInitialized()`、`OneS1ght.getDeviceAvailability()`、`OneS1ght.getGoogleMapKey()`。

```kotlin theme={null}
enum class DeviceAvailability {
    AVAILABLE,             // 測位可能
    OS_VERSION_TOO_LOW,    // Android 17（API 37）未満 —「OS をアップデートすると利用可能」と案内
    DEVICE_NOT_SUPPORTED,  // UWB DL-TDoA 非対応端末
}

enum class PermissionStatus {
    AUTHORIZED,            // 測位を開始できる
    DENIED,                // 拒否（おおよその位置情報のみの許可・30 秒無応答を含む）— 設定アプリへ案内
    UNSUPPORTED,           // この端末・OS では測位自体ができない
}
```

## エラー — SdkError

`SdkError` は SDK 自体が投げる 5 種類です。通信の失敗は `ApiError`（`co.onecheck.ones1ght.android.network`）で届きます。
どちらも `Exception` のサブクラスで、`.code.code` で[エラーコード](/ja/sdk/faq/error-code)の文字列を取り出せます。

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    try {
        OneS1ght.initialize(context = applicationContext, sdkKey = key)
    } catch (e: SdkError) {
        Log.w("OneS1ght", e.code.code)                   // "E1003"
    } catch (e: ApiError) {
        Log.w("OneS1ght", "${e.code.code} ${e.message}") // "E5005 …"
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    OneS1ght.initialize(context, key, new Callback<Void>() {
        @Override public void onSuccess(Void result) { }
        @Override public void onError(Throwable error) {
            if (error instanceof SdkError) {
                Log.w("OneS1ght", ((SdkError) error).getCode().getCode());   // "E1003"
            } else if (error instanceof ApiError) {
                Log.w("OneS1ght", ((ApiError) error).getCode().getCode() + " " + error.getMessage());
            }
        }
    });
    ```
  </Tab>
</Tabs>

| クラス | コード | 発生タイミング | 対処 |
| - | - | - | - |
| `SdkError.NotInitialized` | `E1001` | `initialize` なしで他の API を呼び出した | 呼び出し順を修正 |
| `SdkError.NotIdentified` | `E1004` | `identify` なしで測位を開始した | 認証直後に `identify(profileId)` |
| `SdkError.PositioningDisabled` | `E1003` | キーは有効だが測位機能がオフ | コンソール設定の確認・サポートへお問い合わせ |
| `SdkError.OsVersionTooLow` | `E2001` | Android 17（API 37）未満 | OS のアップデートを案内 |
| `SdkError.DeviceNotSupported` | `E2002` | UWB DL-TDoA 非対応端末 | `deviceAvailability` で事前に分岐 |
| `ApiError.InvalidKey` | `E1002` | キーが誤っている・破棄済み（401） | コンソールでキーの状態を確認・再発行 |
| `ApiError.Forbidden` | `E5004` | 他テナントのリソース（403） | キーのスコープを確認 |
| `ApiError.NotFound` | `E5003` | 対象なし（404） | 多くは契約の不一致 |
| `ApiError.Unprocessable` | `E5003` | ペイロードの問題（422） | SDK・サーバーのバージョン不一致を疑う |
| `ApiError.Server` | `E5002` | サーバー 5xx | 統合管理者に確認 |
| `ApiError.Network` | `E5001` | オフライン・タイムアウト | 自動で再試行 |
| `ApiError.Decoding` | `E5005` | 応答 JSON の形式不一致 | `message` に理由が入ります |

測位ランタイム（`E4001`〜`E4004`）、空間設定（`E3001`〜`E3009`）、権限（`E2003`）は throw されず、**ログにのみ**出力されます —
`onDebugLog` またはコンソールのログ分析で確認してください。[全一覧](/ja/sdk/faq/error-code)

## モデル

モデルは `co.onecheck.ones1ght.android.model` パッケージにあります。

### Coordinates — リアルタイム座標

```kotlin theme={null}
data class Coordinates(
    val x: Double,   // メートル
    val y: Double,   // メートル
    val z: Double,   // 高さ（2D 測位の場合は 0）
)
```

### Building · Floor — 建物・フロア

| 型 | フィールド | 説明 |
| - | - | - |
| `Building` | `id` · `name` | 建物 ID · 名前 |
| | `floorCount: Int?` | フロア数（サーバーが返さない場合は `null`） |
| `Floor` | `id` · `name` | フロア ID · 名前 |
| | `image: ByteArray?` | 図面 PNG — `floors()` で取得すると `null`、`floor()` で取得すると設定済み |
| | `hasPlan: Boolean` | 図面が登録されているか |
| | `originX` · `originY` | 図面原点のオフセット（メートル） |
| | `widthM` · `heightM` | 図面の実寸（メートル） |
| | `minX` · `minY` · `maxX` · `maxY` | 配置範囲（原点 + サイズから派生） |

### Locator · FloorLocators — ロケーター

| 型 | フィールド | 説明 |
| - | - | - |
| `Locator` | `address: Int` | UWB MAC の末尾 2 バイト（例: `0x9DD7`） |
| | `x` · `y` · `z` | 図面ローカルのメートル |
| `FloorLocators` | `locators: List<Locator>` | このフロアに設置されたロケーター |
| | `sessionId: Int?` | UWB セッション — フロアごとに異なります。`null` の場合は測位を開始できません |
| | `positioningReady: Boolean` | ロケーターがあり、セッションもあるか（派生値） |

### Zone — ゾーン

| フィールド | 型 | 説明 |
| - | - | - |
| `id` / `name` | `String` | ゾーン識別子 · 名前 — 測位エンジンが報告する領域名との照合キー |
| `polygon` | `List<Position>` | 頂点（順番どおり、表示用）— `Position` は図面ローカルのメートル (x, y) |
| `inDist` · `inCount` / `inCountInterval` · `outPeriod` · `priority` · `callInout` | — | 判定は測位エンジンが自身のジオフェンスで行うため、**もう使われません。** コンソールで値を変えても判定には影響しません |
| `dwellSeconds` | `Int?` | 滞在の判定基準（秒）— 到達時に 1 回発火。`null` または 0 の場合は滞在イベントなし |

コンソールゾーンは今後、**地図の表示・zone\_id へのマッピング・サーバーへの送信**のためにのみ使われます
（[設定方法](/ja/locator/areas)）。測位エンジンが報告する領域名とコンソールゾーンの名前が一致している
必要があり、一致するものがない場合は `E3009`（WARN）が 1 回出力され、その領域のイベントはサーバーへ
送られません。

<Note>
  判定パラメーターが残っているゾーンがあると、SDK が一度だけ WARN で知らせます — 値自体はもう判定に
  使われないという意味です。
</Note>

### Trigger — パーソナライズアクション

| フィールド | 型 | 説明 |
| - | - | - |
| `triggerId` | `String` | トリガー識別子 |
| `type` | `String` | `signage · coupon · tracking · merch · generic` |
| `payload` | `Map<String, String>?` | タイプ別の付加情報 |

### MockPositioningProvider — テスト用

```kotlin theme={null}
class MockPositioningProvider : PositioningProvider {
    fun simulateEnter(buildingId: String)
    fun simulatePosition(c: Coordinates, floorId: String?, atMs: Long)
    fun simulateZone(zoneId: String, status: ZoneEventStatus, floorId: String?, atMs: Long)
}
```

`co.onecheck.ones1ght.android.positioning` パッケージにあり、`session.begin(provider)` で注入すると UWB なしで SDK のパイプラインを
確認できます。`ZoneEventStatus` は `ENTER` · `DWELL` · `EXIT` です。

## スレッド

* Kotlin の `suspend` API はどのコルーチンから呼び出しても構いません。SDK が内部でスレッドを切り替えます。
* `identify`・`empty`・`pause`・`resume` は**メインスレッド**で呼び出します。
* コールバック（`onPosition` など）と Java の `Callback` の結果はメインスレッドで呼び出されます — そのまま UI を更新しても安全です。

## 知っておくべき制約

<Warning>
  Android の UWB 測位は**フォアグラウンド専用**です。アプリがバックグラウンドに移ると測位が止まり、残りの座標を送信した後、
  戻ると再開します。プラットフォームの制約のため、SDK で回避することはできません。
</Warning>

<Warning>
  座標バッファはメモリ上にあります。アプリが強制終了されると、まだ送信していない座標は失われます（`E5006`）。
</Warning>
