AI グラスのエクスペリエンスは、既存の Android Activity フレームワーク
API を基盤として構築されており、AI グラスの固有の側面をサポートするための追加のコンセプトが含まれています。デバイスで完全な APK を実行する XR ヘッドセットとは異なり、AI グラスはスマートフォンの既存のアプリ内で実行される専用の Activity を使用します。この Activity は、ホストデバイスから AI グラスに投影されます。
アプリの AI グラスのエクスペリエンスを作成するには、AI グラス用の新しい投影された Activity を作成して、既存のスマートフォン アプリ
を拡張します。このアクティビティは、AI グラスでのアプリのメインの起動エントリ ポイントとして機能します。このアプローチでは、スマートフォンと AI グラスのエクスペリエンス間でビジネス ロジックを共有して再利用できるため、開発が簡素化されます。
バージョンの互換性
Jetpack XR SDK の Android SDK の互換性要件を確認してください。
依存関係
AI グラス用の次の ライブラリ依存関係 を追加します。
Groovy
dependencies { implementation "androidx.xr.runtime:runtime:1.0.0-alpha11" implementation "androidx.xr.glimmer:glimmer:1.0.0-alpha08" implementation "androidx.xr.projected:projected:1.0.0-alpha05" implementation "androidx.xr.arcore:arcore:1.0.0-alpha11" }
Kotlin
dependencies { implementation("androidx.xr.runtime:runtime:1.0.0-alpha11") implementation("androidx.xr.glimmer:glimmer:1.0.0-alpha08") implementation("androidx.xr.projected:projected:1.0.0-alpha05") implementation("androidx.xr.arcore:arcore:1.0.0-alpha11") }
アプリのマニフェストでアクティビティを宣言する
他のタイプのアクティビティと同様に、システムがアクティビティを認識して実行できるようにするには、アプリのマニフェスト ファイルでアクティビティを宣言する必要があります。
<application>
<activity
android:name="com.example.xr.projected.GlassesMainActivity"
android:exported="true"
android:requiredDisplayCategory="xr_projected"
android:label="Example AI Glasses activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>
コードに関する主なポイント
android:requiredDisplayCategory属性にxr_projectedを指定して、このアクティビティが 投影されたコンテキスト を使用してコネクテッド デバイスからハードウェアにアクセスする必要があることをシステムに伝えます。
アクティビティを作成する
次に、ディスプレイがオンのときに AI グラスに何かを表示できる小さなアクティビティを作成します。
@OptIn(ExperimentalProjectedApi::class) class GlassesMainActivity : ComponentActivity() { private var displayController: ProjectedDisplayController? = null private var isVisualUiSupported by mutableStateOf(false) private var areVisualsOn by mutableStateOf(true) private var isPermissionDenied by mutableStateOf(false) // Register the permissions launcher using the ProjectedPermissionsResultContract. private val requestPermissionLauncher: ActivityResultLauncher<List<ProjectedPermissionsRequestParams>> = registerForActivityResult(ProjectedPermissionsResultContract()) { results -> if (results[Manifest.permission.CAMERA] == true) { isPermissionDenied = false initializeGlassesFeatures() } else { // Handle permission denial. isPermissionDenied = true } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onDestroy(owner: LifecycleOwner) { displayController?.close() displayController = null } }) if (hasCameraPermission()) { initializeGlassesFeatures() } else { requestHardwarePermissions() } setContent { GlimmerTheme { HomeScreen( areVisualsOn = areVisualsOn, isVisualUiSupported = isVisualUiSupported, isPermissionDenied = isPermissionDenied, onRetryPermission = { requestHardwarePermissions() }, onClose = { finish() } ) } } } private fun initializeGlassesFeatures() { lifecycleScope.launch { // Check device capabilities val projectedDeviceController = ProjectedDeviceController.create(this@GlassesMainActivity) isVisualUiSupported = projectedDeviceController.capabilities.contains(CAPABILITY_VISUAL_UI) val controller = ProjectedDisplayController.create(this@GlassesMainActivity) displayController = controller val observer = GlassesLifecycleObserver( context = this@GlassesMainActivity, controller = controller, onVisualsChanged = { visualsOn -> areVisualsOn = visualsOn } ) lifecycle.addObserver(observer) } } private fun hasCameraPermission(): Boolean { return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED } private fun requestHardwarePermissions() { val params = ProjectedPermissionsRequestParams( permissions = listOf(Manifest.permission.CAMERA), rationale = "Camera access is required to overlay digital content on your physical environment." ) requestPermissionLauncher.launch(listOf(params)) } }
コードに関する主なポイント
- Jetpack Projected ライブラリのオプトイン API の使用をオプトインします。
GlassesMainActivityは、モバイル開発の場合と同様にComponentActivityを拡張します。- すべての AI グラスにディスプレイがあるわけではないため、
ProjectedDeviceControllerを使用してデバイスにディスプレイがあるかどうかを確認します。 onCreate関数内のsetContentブロックは、アクティビティのコンポーズ可能な UI ツリーのルートを定義します。HomeScreenコンポーザブルをJetpack Compose Glimmerを使用して実装します。- アクティビティの
onCreateメソッドで UI を初期化します( 投影されたアクティビティのライフサイクルを参照)。 - グラスのハードウェアに
アクセスするカメラ関連の機能に備えて、権限ランチャーを登録し、
hasCameraPermission関数とrequestHardwarePermissions関数を定義して、権限が 付与されているかどうかをinitializeGlassesFeaturesを呼び出す前に確認することで、ハードウェア権限をリクエストします。
コンポーザブルを実装する
作成したアクティビティは、実装する必要がある HomeScreen コンポーズ可能な関数を参照します。次のコードでは、Jetpack Compose Glimmer を
使用して、AI グラスのディスプレイにテキストを表示できるコンポーザブルを定義します。
@Composable fun HomeScreen( areVisualsOn: Boolean, isVisualUiSupported: Boolean, isPermissionDenied: Boolean, onRetryPermission: () -> Unit, onClose: () -> Unit, modifier: Modifier = Modifier ) { Box( modifier = modifier .surface(focusable = false) .fillMaxSize(), contentAlignment = Alignment.Center ) { if (isPermissionDenied) { Card( title = { Text("Permission Required") }, action = { Button(onClick = onClose) { Text("Exit") } } ) { Text("Camera access is needed to use AI glasses features.") Button(onClick = onRetryPermission) { Text("Retry") } } } else if (isVisualUiSupported) { Card( title = { Text("Android XR") }, action = { Button(onClick = onClose) { Text("Close") } } ) { if (areVisualsOn) { Text("Hello, AI Glasses!") } else { Text("Display is off. Audio guidance active.") } } } else { Text("Audio Guidance Mode Active") } } }
コードに関する主なポイント
- アクティビティで定義したように、
HomeScreen関数には、AI グラスのディスプレイがオンのときにユーザーに表示されるコンポーズ可能なコンテンツが含まれています。 - Jetpack Compose Glimmer
Textコンポーネントは、グラスのディスプレイに「Hello, AI Glasses!」というテキストを表示します。 - Jetpack Compose Glimmer の
Buttonは、AI グラスのアクティビティのonCloseを介してfinish()を呼び出してアクティビティを閉じます。
AI グラスが接続されているかどうかを確認する
アクティビティを起動する前に、ユーザーの AI グラスがスマートフォンに接続されているかどうかを確認するには、
メソッドを使用します。ProjectedContext.isProjectedDeviceConnectedこのメソッドは、アプリが接続ステータスのリアルタイム更新を取得するために監視できる Flow<Boolean> を返します。
アクティビティを開始する
基本的なアクティビティを作成したので、グラスで起動できます。 グラスのハードウェアにアクセスするには、次のコードに示すように、投影されたコンテキストを使用するようにシステムに指示する特定の オプションを使用して、アプリがアクティビティを開始する必要があります。
val options = ProjectedContext.createProjectedActivityOptions(context) val intent = Intent(context, GlassesMainActivity::class.java) context.startActivity(intent, options.toBundle())
ProjectedContext
の createProjectedActivityOptions メソッドは、投影されたコンテキストでアクティビティを開始するために必要なオプションを生成します。
context パラメータには、スマートフォンまたはグラス デバイスのコンテキストを指定できます。
次のステップ
AI グラス用のアクティビティを初めて作成したので、その機能を拡張する他の方法を調べてみましょう。
- テキスト読み上げを使用してオーディオ出力を処理する
- 自動音声認識を使用して音声入力を処理する
- Jetpack Compose Glimmer で UI を構築する
- AI グラスのハードウェアにアクセスする