1.0.0-alpha01時点で既存のAndroidアプリをSpatializing(空間化)する

Android XR は互換があればそのまま Android のアプリが動きますが、Spatializing する方法を 1.0.0-alpha01 時点の情報で試してみたメモです。


## Spatializing とは?
互換性のある Android アプリを Android XR で動かす場合はホームスペースで動作します。Spatializing はホームスペースではなくてフルスペースで動作させ、空間機能を使えるようにすることを指しています。
現時点では Spatializing されたアプリはフルスペースのみサポートされています。


## 前提
Android XR の公式からのライブラリは、フル Jetpack Compose かつ Material 3 である前提のサポートを提供しています。(もちろんサポートなしに 0 から実装もできます)
今回はフル Jetpack Compose かつ Material 3 の個人のプロジェクトで試しています。


以下の画像は何もしていないホームスペースで動作している個人のアプリで、フル Jetpack Compose かつ Material 3 と Material 3 Adaptive の [NavigationSuite](https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/navigationsuite/package-summary) を使用しています。

![Screenshot_20241215_150159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/8fbfb3e7-9d53-eef3-5445-5c2fd84a490f.png)


## アプリを XR に対応させる

### XR 関連の依存の追加

Jetpack Compose の依存やその他の依存は省略します。
Jetpack Compose の依存と同じスコープで XR 用の Jetpack Compose のライブラリを追加します。

```libs.versions.toml
xrCompose = "1.0.0-alpha01"

androidxXRCompose = { module = "androidx.xr.compose:compose", version.ref = "xrCompose" }
androidxXRComposeMaterial3 = { module = "androidx.xr.compose.material3:material3", version.ref = "xrCompose" }
```

```gradle.kts
implementation(libs.androidxXRCompose)
implementation(libs.androidxXRComposeMaterial3)
```

### minSdk を上げないよう回避策を追加する
XR のライブラリは既知の問題で minSdk が 32 以上を要求されます。
その回避として Manifest に以下の指定が必要です。

```AndroidManifest.xml
<manifest>
    ...
    <uses-sdk tools:overrideLibrary="androidx.xr.scenecore, androidx.xr.compose, androidx.xr.compose.material3" />
    ...
</manifest>
```

### デフォルトでフルスペースでアプリを動かす指定を追加する
そのままの Android アプリはホームスペースで動作するので、フルスペースで動作するように指定を追加します。
Application レベルもしくは Activity レベルで適用できます。

```AndroidManifest.xml
<application>
    <property
        android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
        android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" />
    ...
</application>
```

ここでは省略しますが、動的に切り替えることもできます。
https://developer.android.com/develop/xr/jetpack-xr-sdk/transition-home-space-to-full-space#transition-home

### コンポーネントを XR 用のものに自動で置き換わるようにする
`EnableXrComponentOverrides` という Composable fun で囲むことで、そのスコープ内で XR 用のコンポーネントに置き換えてくれるようになります。

```MainActivity.kt
setContent {
    EnableXrComponentOverrides {
        // Content
    }
}
```

これらの対応をするだけで `NavigationRail` が Orbiter に自動で対応されます。
![Screenshot_20241215_151852.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/9e4c3a08-7434-a5e4-544e-f6d0d224b0fe.png)

### もっと Spatializing する

それっぽくはなっていますが、このままでは Spatial panel の拡大縮小などが動かないため、もっと手を加えて Spatializing するには画面のルートを `SpatialPanel` で実装する必要があります。
(この辺りはライブラリ側で `Scaffold` が `SpatialPanel` のサポートがされるのではないか、されて欲しい)

```kotlin
if (LocalSpatialCapabilities.current.isSpatialUiEnabled) {
    Subspace {
        SpatialPanel(
            modifier = SubspaceModifier
                .width(1280.dp)
                .height(800.dp)
                .resizable()
                .movable()
        ) {
            // コンテンツ
        }
    }
} else {
    // 通常のアプリのレイアウトとコンテンツ
}
```

![Screenshot_20241215_155807.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126298/b3d93c3b-a751-95e5-1c8c-b16f4949f7ee.png)



## XR 向けにコンポーネントの見た目を切り替えている実装の中身

XR ではない androidx.compose.material3 に [LocalNavigationRailComponentOverride](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationRail.kt;l=829-836) というコンポーネントを差し替えるための Composition Local が用意されており、`EnableXrComponentOverrides` で XR のフルスペース用コンポーネントに上書きすることで実現しています。

1.0.0-alpha01 時点では `EnableXrComponentOverrides` で置き換わるコンポーネントは `NavigationBar` と `NavigationRail` のみとなっており、今後様々なコンポーネントが置き換わるようになりそうです。

また、ドキュメントに記載がある [ListDetailPaneScaffold](https://developer.android.com/develop/xr/jetpack-xr-sdk/material-design#list-detail-layout) や [SupportingPaneScaffold](https://developer.android.com/develop/xr/jetpack-xr-sdk/material-design#support-pane) の Spatial panel 対応については 1.0.0-alpha01 時点で未実装です。


## 所感

フル Jetpack Compose かつ Material 3 であればとても簡単に XR らしくすることができました。
もちろんアプリを 0 から XR に最適化して作るのも一つではありますが、前提条件がクリアできていれば既存のアプリ資産を使いつつコストを最小限に対応できる点が嬉しいですね。
今から XR に備えるには、Jetpack Compose の使用範囲を広げることや Material 3 を使っていくこと、大画面対応を開発計画に盛り込めると対応コストを下げつつ XR での体験を向上させることができそうです。

## リンク
- https://developer.android.com/develop/xr/get-started
- https://developer.android.com/develop/xr/jetpack-xr-sdk
- https://developer.android.com/develop/xr/jetpack-xr-sdk/add-xr-to-existing
- https://developer.android.com/develop/xr/jetpack-xr-sdk/transition-home-space-to-full-space
- https://developer.android.com/develop/xr/jetpack-xr-sdk/develop-ui
- https://developer.android.com/develop/xr/jetpack-xr-sdk/material-design