Créer votre première activité pour des lunettes audio et des lunettes à écran

Appareils XR concernés
Ces conseils vous aident à créer des expériences pour ces types d'appareils XR.
Lunettes audio et
lunettes avec affichage

Les expériences de réalité augmentée pour les lunettes audio et les lunettes avec affichage sont basées sur l' API du framework Activity Android existant et incluent des concepts supplémentaires pour prendre en charge les aspects uniques de ces lunettes. Contrairement aux casques XR qui exécutent un APK complet sur l'appareil, les lunettes audio et les lunettes avec affichage utilisent une activité dédiée qui s'exécute dans l'application existante de votre téléphone. Cette activité est projetée de l'appareil hôte vers les lunettes.

Pour créer l'expérience de votre application pour les lunettes audio et les lunettes avec affichage, vous étendez votre application téléphonique existante en créant une Activity projetée. Cette activité sert de point d'entrée principal pour lancer votre application sur les lunettes. Cette approche simplifie le développement, car vous pouvez partager et réutiliser la logique métier entre votre téléphone et vos lunettes.

Compatibilité des versions

Consultez les exigences de compatibilité du SDK Android pour le SDK Jetpack XR.

Dépendances

Ajoutez les dépendances de bibliothèque suivantes pour les lunettes audio et les lunettes avec affichage :

Groovy

dependencies {
    implementation "androidx.xr.runtime:runtime:1.0.0-alpha15"
    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-alpha15")
    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")
}

Déclarer votre activité dans le fichier manifeste de votre application

Comme pour les autres types d'activités, vous devez déclarer votre activité dans le fichier manifeste de votre application pour que le système puisse la voir et l'exécuter.

<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>

Points clés concernant le code

  • Spécifie android.hardware.display.category.XR_PROJECTED pour l'attribut android:requiredDisplayCategory afin d'indiquer au système qu'il s'agit d'une activité projetée qui peut être projetée sur des lunettes audio et des lunettes avec affichage.
  • android.intent.action.MAIN définit cette activité comme activité de lancement par défaut.
  • android.intent.category.XR_PROJECTED_LAUNCHER est une catégorie spécialisée qui permet aux commandes vocales Gemini de découvrir votre activité projetée.

    Lorsqu'un utilisateur émet une commande vocale à l'aide du nom de l'application (par exemple, "Ouvrir l'exemple de catalogue d'IA", "Lancer l'exemple de catalogue d'IA" ou "Démarrer l'exemple de catalogue d'IA"), le système utilise cette catégorie pour localiser et démarrer l'activité désignée sur les lunettes audio ou les lunettes avec affichage.

Créer votre activité

Ensuite, vous allez créer une petite activité qui peut afficher quelque chose sur les lunettes d'IA lorsque l'écran est allumé.

@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))
    }
}

Points clés concernant le code

Implémenter le composable

L'activité que vous avez créée référence une fonction composable HomeScreen que vous devez implémenter. Le code suivant utilise Jetpack Compose Glimmer pour définir un composable qui peut afficher du texte sur l'écran des lunettes :

@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")
        }
    }
}

Points clés concernant le code

  • Comme vous l'avez défini précédemment dans votre activité, la fonction HomeScreen inclut le contenu modulable que l'utilisateur voit lorsque l'écran des lunettes est allumé.
  • Le composant Text de Jetpack Compose Glimmer affiche le texte "Hello, AI Glasses!" sur l'écran des lunettes.
  • Le Button de Jetpack Compose Glimmer ferme l'activité en appelant finish() via onClose dans l'activité projetée.

Vérifier si des lunettes audio ou des lunettes avec affichage sont connectées

Pour déterminer si les lunettes audio ou les lunettes avec affichage d'un utilisateur sont connectées à leur téléphone avant de lancer votre activité, utilisez la ProjectedContext.isProjectedDeviceConnected méthode. Cette méthode renvoie un Flow<Boolean> que votre application peut observer pour obtenir des mises à jour en temps réel sur l'état de la connexion.

Démarrer votre activité

Maintenant que vous avez créé une activité de base, vous pouvez la lancer sur vos lunettes. Pour accéder au matériel des lunettes, votre application doit démarrer votre activité avec des options spécifiques qui indiquent au système d'utiliser un contexte projeté, comme illustré dans le code suivant :

val options = ProjectedContext.createProjectedActivityOptions(context)
val intent = Intent(context, GlassesMainActivity::class.java)
context.startActivity(intent, options.toBundle())

La méthode createProjectedActivityOptions dans ProjectedContext génère les options nécessaires pour démarrer votre activité dans un contexte projeté. Le paramètre context peut être un contexte du téléphone ou de l'appareil des lunettes.

Étapes suivantes

Maintenant que vous avez créé votre première activité pour les lunettes audio et les lunettes avec affichage, découvrez d'autres façons d'étendre ses fonctionnalités :