Le esperienze aumentate per gli occhiali audio e con display si basano sull'
API del framework Activity di Android esistente e includono concetti
aggiuntivi per supportare gli aspetti unici di questi occhiali. A differenza dei visori XR che eseguono un APK completo sul dispositivo, gli occhiali audio e con display utilizzano un'attività dedicata che viene eseguita all'interno dell'app esistente dello smartphone. Questa attività viene proiettata dal dispositivo host sugli occhiali.
Per creare l'esperienza della tua app per gli occhiali audio e con display, tu
estendi l'app per smartphone esistente creando una nuova Activity proiettata. Questa attività funge da punto di accesso principale per l'avvio dell'app sugli occhiali. Questo approccio semplifica lo sviluppo perché puoi condividere e riutilizzare la logica di business tra le esperienze per smartphone e occhiali.
Compatibilità con le versioni
Controlla i requisiti di compatibilità dell'SDK Android per l'SDK Jetpack XR.
Dipendenze
Aggiungi le seguenti dipendenze della libreria per gli occhiali audio e con display glasses:
Alla moda
dependencies {
implementation "androidx.xr.runtime:runtime:1.0.0-alpha14"
implementation "androidx.xr.glimmer:glimmer:1.0.0-alpha13"
implementation "androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha13"
implementation "androidx.xr.projected:projected:1.0.0-alpha08"
implementation "androidx.xr.arcore:arcore:1.0.0-alpha14"
}
Kotlin
dependencies {
implementation("androidx.xr.runtime:runtime:1.0.0-alpha14")
implementation("androidx.xr.glimmer:glimmer:1.0.0-alpha13")
implementation("androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha13")
implementation("androidx.xr.projected:projected:1.0.0-alpha08")
implementation("androidx.xr.arcore:arcore:1.0.0-alpha14")
}
Dichiara l'attività nel file manifest dell'app
Come per gli altri tipi di attività, devi dichiarare l'attività nel file manifest dell'app affinché il sistema possa vederla ed eseguirla.
<application>
<activity
android:name="com.example.xr.projected.ProjectedMainActivity"
android:exported="true"
android:requiredDisplayCategory="android.hardware.display.category.XR_PROJECTED"
android:label="Example activity for audio glasses and display glasses">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
</intent-filter>
</activity>
</application>
Punti chiave sul codice
- Specifica
android.hardware.display.category.XR_PROJECTEDper l'attributoandroid:requiredDisplayCategoryper indicare al sistema che si tratta di un'attività proiettata e che può essere proiettata su occhiali audio e con display. android.intent.action.MAINimposta questa attività come attività di avvio predefinita.android.intent.category.XR_PROJECTED_LAUNCHERè una categoria specializzata che rende la tua attività proiettata rilevabile dai comandi vocali di Gemini.Quando un utente emette un comando vocale utilizzando il nome dell'app (ad esempio "Apri l'esempio di catalogo AI", "Avvia l'esempio di catalogo AI" o "Inizia l'esempio di catalogo AI"), il sistema utilizza questa categoria per individuare e avviare l'attività designata sugli occhiali audio o con display.
Crea l'attività
Ora creerai una piccola attività in grado di visualizzare qualcosa sugli occhiali AI ogni volta che il display è acceso.
@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)) } }
Punti chiave sul codice
- Consente di utilizzare le API con consenso esplicito della libreria Jetpack Projected.
GlassesMainActivityestendeComponentActivity, come previsto nello sviluppo mobile.- Poiché non tutti gli occhiali hanno un display, verifica se il dispositivo ha un
display utilizzando
ProjectedDeviceController. - Il blocco
setContentall'interno della funzioneonCreatedefinisce la radice dell'albero dell'interfaccia utente composable per l'attività. Implementerai ilHomeScreencomposable utilizzando Jetpack Compose Glimmer. - Inizializza l'interfaccia utente durante il metodo
onCreatedell'attività (vedi ciclo di vita dell'attività proiettata). - Per prepararsi alle funzionalità correlate alla fotocamera che
accedono all'hardware degli occhiali, richiede le autorizzazioni hardware registrando un launcher di autorizzazioni, definendo le
hasCameraPermissionerequestHardwarePermissionsfunzioni e verificando se le autorizzazioni sono state concesse prima di chiamareinitializeGlassesFeatures.
Implementare il composable
L'attività che hai creato fa riferimento a una funzione composable HomeScreen che devi implementare. Il seguente codice utilizza Jetpack Compose Glimmer per
definire un composable in grado di visualizzare del testo sul display degli occhiali:
@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") } } }
Punti chiave sul codice
- Come hai definito in precedenza nell'attività, la funzione
HomeScreeninclude i contenuti composable che l'utente vede quando il display degli occhiali è acceso. - Il componente
Textdi Jetpack Compose Glimmer visualizza il testo "Hello, AI Glasses!" sul display degli occhiali. - Il
Buttondi Jetpack Compose Glimmer chiude l'attività chiamandofinish()tramiteonClosenell'attività proiettata.
Verifica se gli occhiali audio o con display sono collegati
Per determinare se gli occhiali audio o con display di un utente sono collegati al suo
smartphone prima di avviare l'attività, utilizza il
ProjectedContext.isProjectedDeviceConnected metodo. Questo metodo
restituisce un Flow<Boolean> che la tua app può osservare per ricevere aggiornamenti in tempo reale sullo stato della connessione.
Avvia l'attività
Ora che hai creato un'attività di base, puoi avviarla sugli occhiali. Per accedere all'hardware degli occhiali, la tua app deve avviare l'attività con opzioni specifiche che indicano al sistema di utilizzare un contesto proiettato, come mostrato nel seguente codice:
val options = ProjectedContext.createProjectedActivityOptions(context) val intent = Intent(context, GlassesMainActivity::class.java) context.startActivity(intent, options.toBundle())
Il metodo createProjectedActivityOptions in ProjectedContext
genera le opzioni necessarie per avviare l'attività in un contesto proiettato.
Il parametro context può essere un contesto dello smartphone o del dispositivo degli occhiali.
Passaggi successivi
Ora che hai creato la tua prima attività per gli occhiali audio e con display, esplora altri modi per estenderne la funzionalità:
- Gestire l'uscita audio utilizzando la sintesi vocale
- Gestire l'input audio utilizzando il riconoscimento vocale automatico
- Creare l'interfaccia utente con Jetpack Compose Glimmer
- Accedere all'hardware degli occhiali audio e con display