Erweiterte Erlebnisse für Audio- und Display-Brillen basieren auf der
vorhandenen Android-ActivityFramework-API und enthalten zusätzliche
Konzepte, um die besonderen Aspekte dieser Brillen zu unterstützen. Im Gegensatz zu XR‑Headsets, auf denen eine vollständige APK auf dem Gerät ausgeführt wird, verwenden Audio- und Display-Brillen eine spezielle Aktivität, die in der vorhandenen App auf Ihrem Smartphone ausgeführt wird. Diese Aktivität wird vom Hostgerät auf die Brille projiziert.
Wenn Sie das Erlebnis Ihrer App für Audio- und Display-Brillen erstellen möchten, erweitern Sie Ihre vorhandene Smartphone-App, indem Sie eine neue projizierte Activity. Diese Aktivität dient als Haupteinstiegspunkt für Ihre App auf der Brille. Dieser Ansatz vereinfacht die Entwicklung, da Sie Geschäftslogik zwischen Ihren Smartphone- und Brillen-Erlebnissen gemeinsam nutzen können.
Versionskompatibilität
Prüfen Sie die Anforderungen an die Android SDK-Kompatibilität für das Jetpack XR SDK.
Abhängigkeiten
Fügen Sie die folgenden Bibliotheksabhängigkeiten für Audio- und Display Brillen hinzu:
Groovy
dependencies {
implementation "androidx.xr.runtime:runtime:1.0.0-alpha14"
implementation "androidx.xr.glimmer:glimmer:1.0.0-alpha12"
implementation "androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha12"
implementation "androidx.xr.projected:projected:1.0.0-alpha07"
implementation "androidx.xr.arcore:arcore:1.0.0-alpha13"
}
Kotlin
dependencies {
implementation("androidx.xr.runtime:runtime:1.0.0-alpha14")
implementation("androidx.xr.glimmer:glimmer:1.0.0-alpha12")
implementation("androidx.xr.glimmer:glimmer-google-fonts:1.0.0-alpha12")
implementation("androidx.xr.projected:projected:1.0.0-alpha07")
implementation("androidx.xr.arcore:arcore:1.0.0-alpha13")
}
Aktivität im Manifest Ihrer App deklarieren
Wie bei anderen Aktivitätstypen müssen Sie Ihre Aktivität in der Manifestdatei Ihrer App deklarieren, damit das System sie sehen und ausführen kann.
<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>
Wichtige Punkte zum Code
- Gibt
android.hardware.display.category.XR_PROJECTEDfür das Attributandroid:requiredDisplayCategoryan, um dem System mitzuteilen, dass es sich um eine projizierte Aktivität handelt, die auf Audio- und Display-Brillen projiziert werden kann. android.intent.action.MAINlegt diese Aktivität als Standard-Startaktivität fest.android.intent.category.XR_PROJECTED_LAUNCHERist eine spezielle Kategorie, mit der Ihre projizierte Aktivität über Gemini-Sprachbefehle gefunden werden kann.Wenn ein Nutzer einen Sprachbefehl mit dem Namen der App ausgibt (z. B. „Öffne das Beispiel für den KI-Katalog“, „Starte das Beispiel für den KI-Katalog“ oder „Beginne mit dem Beispiel für den KI-Katalog“), verwendet das System diese Kategorie, um die angegebene Aktivität auf der Audio- oder Display-Brille zu finden und zu starten.
Aktivität erstellen
Als Nächstes erstellen Sie eine kleine Aktivität, mit der etwas auf der KI-Brille angezeigt werden kann, wenn das Display eingeschaltet ist.
@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)) } }
Wichtige Punkte zum Code
- Aktiviert die Verwendung von Opt-in-APIs aus der Jetpack Projected Bibliothek.
GlassesMainActivityerweitertComponentActivity, wie Sie es von der mobilen Entwicklung gewohnt sind.- Da nicht alle Brillen ein Display haben, wird mit
ProjectedDeviceControllergeprüft, ob das Gerät ein Display hat. - Der Block
setContentin der FunktiononCreatedefiniert den Stamm des zusammensetzbaren UI-Baums für die Aktivität. Sie implementieren dieHomeScreenzusammensetzbare Funktion mit Jetpack Compose Glimmer. - Initialisiert die UI während der Methode
onCreateder Aktivität (siehe Lebenszyklus der projizierten Aktivität). - Um sich auf kamerabezogene Funktionen vorzubereiten, die
auf die Hardware der Brille zugreifen, werden Hardwareberechtigungen angefordert durch
Registrieren eines Berechtigungs-Launchers, Definieren der
hasCameraPermissionundrequestHardwarePermissionsFunktionen und Prüfen, ob Berechtigungen erteilt wurden, bevorinitializeGlassesFeaturesaufgerufen wird.
Zusammensetzbare Funktion implementieren
Die von Ihnen erstellte Aktivität verweist auf eine zusammensetzbare Funktion HomeScreen, die Sie implementieren müssen. Im folgenden Code wird Jetpack Compose Glimmer verwendet, um
eine zusammensetzbare Funktion zu definieren, mit der Text auf dem Display der Brille angezeigt werden kann:
@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") } } }
Wichtige Punkte zum Code
- Wie bereits in Ihrer Aktivität definiert, enthält die Funktion
HomeScreenden zusammensetzbaren Inhalt, den der Nutzer sieht, wenn das Display der Brille eingeschaltet ist. - Die Jetpack Compose Glimmer
Text-Komponente zeigt den Text "Hallo, KI-Brille!" auf dem Display der Brille an. - Die Jetpack Compose Glimmer-Komponente
Buttonschließt die Aktivität, indem siefinish()überonClosein der projizierten Aktivität aufruft.
Prüfen, ob eine Audio- oder Display-Brille verbunden ist
Mit der Methode ProjectedContext.isProjectedDeviceConnected können Sie prüfen, ob die Audio- oder Display-Brille eines Nutzers mit seinem
Smartphone verbunden ist, bevor Sie Ihre Aktivität starten. Diese Methode
gibt einen Flow<Boolean> zurück, den Ihre App beobachten kann, um Echtzeit-Updates zum
Verbindungsstatus zu erhalten.
Aktivität starten
Nachdem Sie nun eine grundlegende Aktivität erstellt haben, können Sie sie auf Ihrer Brille starten. Um auf die Hardware der Brille zuzugreifen, muss Ihre App Ihre Aktivität mit bestimmten Optionen starten, die dem System mitteilen, dass ein projizierter Kontext verwendet werden soll. Das sehen Sie im folgenden Code:
val options = ProjectedContext.createProjectedActivityOptions(context) val intent = Intent(context, GlassesMainActivity::class.java) context.startActivity(intent, options.toBundle())
Die createProjectedActivityOptions Methode in ProjectedContext
generiert die erforderlichen Optionen, um Ihre Aktivität in einem projizierten Kontext zu starten.
Der Parameter context kann ein Kontext vom Smartphone oder von der Brille sein.
Nächste Schritte
Nachdem Sie nun Ihre erste Aktivität für Audio- und Display-Brillen erstellt haben, können Sie die Funktionalität auf verschiedene Weise erweitern:
- Audioausgabe mit Text-zu-Sprache verarbeiten
- Audioeingabe mit automatischer Spracherkennung verarbeiten
- UI mit Jetpack Compose Glimmer erstellen
- Auf Hardware von Audio- und Display-Brillen zugreifen