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-alpha12" 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-alpha12") 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 ツリーのルートを定義します。Jetpack Compose Glimmer を使用してHomeScreenコンポーザブルを実装します。- アクティビティの
onCreateメソッドで UI を初期化します(投影されたアクティビティのライフサイクルを参照)。 - Glass のハードウェアにアクセスするカメラ関連の機能に備えるため、権限ランチャーを登録し、
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コンポーネントは、AI グラスのディスプレイに「Hello, AI Glasses!」というテキストを表示します。 - Jetpack Compose Glimmer の
Buttonは、AI グラス アクティビティのonCloseを介してfinish()を呼び出すことでアクティビティを閉じます。
AI グラスが接続されているかどうかを確認する
アクティビティを起動する前に、ユーザーの AI グラスがスマートフォンに接続されているかどうかを判断するには、ProjectedContext.isProjectedDeviceConnected メソッドを使用します。このメソッドは、アプリが接続ステータスのリアルタイム更新を取得するために監視できる Flow<Boolean> を返します。
アクティビティを開始する
基本的なアクティビティを作成したので、グラスで起動できます。グラスのハードウェアにアクセスするには、次のコードに示すように、投影コンテキストを使用するようにシステムに指示する特定のオプションを指定して、Activity を開始する必要があります。
val options = ProjectedContext.createProjectedActivityOptions(context) val intent = Intent(context, GlassesMainActivity::class.java) context.startActivity(intent, options.toBundle())
ProjectedContext の createProjectedActivityOptions メソッドは、投影されたコンテキストでアクティビティを開始するために必要なオプションを生成します。context パラメータは、スマートフォンまたはメガネ型デバイスのコンテキストにすることができます。
次のステップ
AI グラス用の最初のアクティビティを作成したので、その機能を拡張する他の方法を見てみましょう。
- Text to Speech を使用してオーディオ出力を処理する
- 自動音声認識を使用して音声入力を処理する
- Jetpack Compose Glimmer で UI を構築する
- AI グラスのハードウェアにアクセスする