Descubre los aspectos básicos de Android XR: Parte 1 - Modos y paneles espaciales

1. Antes de comenzar

Qué aprenderás

  • Las experiencias del usuario únicas que hace posibles el factor de forma de realidad extendida
  • Los aspectos básicos de cómo se pueden adaptar las apps para aprovechar al máximo su ejecución en auriculares de Android XR usando elementos componibles proporcionados por la biblioteca de realidad extendida de Jetpack Compose
  • Cómo usar los elementos de la IU proporcionados por la biblioteca de realidad extendida de Compose
  • Dónde obtener más información sobre la compilación de apps para Android XR

Qué no es este codelab

Requisitos

Qué compilarás

En este codelab, mejorarás una app básica con una única pantalla para ofrecer una experiencia del usuario inmersiva a través de Android XR.

Punto de partida

Resultado final

2. Prepárate

Obtén el código

  1. El código de este codelab se puede encontrar en el directorio xr-fundamentals dentro del repositorio xr-codelabs de GitHub. Para clonar el repositorio, ejecuta el siguiente comando:
git clone https://github.com/android/xr-codelabs.git
  1. También tienes la opción de descargar el repositorio como archivo ZIP:

Abre el proyecto

  • Después de iniciar Android Studio, importa el proyecto. Elige solamente el directorio xr-fundamentals/start. El directorio xr-fundamentals/part1 contiene el código de la solución, que puedes consultar en cualquier momento si no logras avanzar o si deseas ver el proyecto completo.

Familiarízate con el código

  • Después de abrir el proyecto en Android Studio, dedica un momento a analizar el código de partida.

3. Descubre los conceptos de realidad extendida: Modos y paneles espaciales

En este codelab, aprenderás dos conceptos de Android XR: los modos y los paneles espaciales. También aprenderás a aplicar estos conceptos a apps que se ejecuten en un dispositivo Android XR.

Modos

En dispositivos Android XR, las apps se ejecutan en uno de dos modos: el modo de espacio principal o el modo de espacio completo.

Modo de espacio principal

d779257a53898d36.jpeg

En el modo de espacio principal, varias apps se ejecutan una al lado de la otra para que los usuarios puedan realizar varias tareas a la vez en las apps. Las apps para Android se pueden ejecutar en el modo de espacio principal sin modificación.

Modo de espacio completo

c572cdee69669a23.jpeg

En el modo de espacio completo, se ejecuta una app a la vez sin límites de espacio. Todas las demás apps se ocultan. Las apps deben realizar un trabajo adicional para abrir el modo de espacio completo y usar las capacidades complementarias disponibles para ellas en este modo.

Para obtener más información sobre estos modos, consulta ​​ Modos de espacio principal y de espacio completo.

Paneles espaciales

Los paneles espaciales son elementos contenedores que constituyen los componentes básicos de las apps para Android XR.

Cuando se ejecuta en el modo de espacio principal, la app estará contenida dentro de un único panel para lograr una experiencia similar al modo de ventanas de escritorio en un dispositivo Android de pantalla grande.

Cuando se ejecuta en el modo de espacio completo, se puede dividir el contenido de la app en uno o más paneles para ofrecer una experiencia más inmersiva.

Para obtener más información sobre los paneles, consulta Paneles espaciales.

4. Ejecuta la app en el emulador de Android XR

Antes de comenzar a mejorar la app para Android XR, puedes ejecutarla en el emulador de Android XR para ver qué aspecto tiene en el modo de espacio principal.

Instala la imagen del sistema de Android XR

  1. Primero, abre SDK Manager en Android Studio y selecciona la pestaña SDK Platforms si aún no está seleccionada. En la esquina inferior derecha de la ventana de SDK Manager, asegúrate de que esté marcada la casilla junto a Show package details.
  2. En la sección Android 14, instala la imagen del emulador Android XR ARM 64 v8a o Android XR Intel x86_64. Las imágenes solo se pueden ejecutar en máquinas que tienen su misma arquitectura (x86/ARM).

Crea un dispositivo virtual Android XR

  1. Después de abrir el Administrador de dispositivos, selecciona XR en la columna Category en la parte izquierda de la ventana. Luego, selecciona el perfil de hardware XR Device de la lista y haz clic en Next.

7a5f6b9c1766d837.png

  1. En la siguiente página, selecciona la imagen del sistema que instalaste anteriormente. Haz clic en Next y selecciona las opciones avanzadas que desees antes de crear el AVD haciendo clic en Finish.
  2. Ejecuta la app en el AVD que acabas de crear.

7cf6569ef7967d87.png

5. Configura dependencias

Antes de poder comenzar a agregar funciones específicas de realidad extendida a tu app, tendrás que agregar una dependencia en Jetpack Compose para la biblioteca de realidad extendida, androidx.xr.compose:compose, que contiene todos los elementos componibles que necesitas para compilar una experiencia optimizada de Android XR para tu app.

libs.version.toml

[versions]
...
xrCompose = "1.0.0-alpha01"

[libraries]
...
androidx-xr-compose = { group = "androidx.xr.compose", name = "compose", version.ref = "xrCompose" }

build.gradle.kts (módulo :app)

dependencies {
    ...
    implementation(libs.androidx.xr.compose)
    ...
}

Después de actualizar estos archivos, asegúrate de hacer una sincronización de Gradle para que las dependencias se descarguen en tu proyecto.

6. Abre el modo de espacio completo

Para usar las funciones de realidad extendida como paneles, una app debe ejecutarse en el modo de espacio completo. Una app puede abrir el modo de espacio completo de dos formas:

  • De forma programática, como en respuesta a la interacción del usuario dentro de tu app
  • Inmediatamente después del inicio, agregando una directiva al manifiesto de la app

Cómo abrir el modo de espacio completo de forma programática

Para abrir el modo de espacio completo de forma programática, puedes ofrecer indicaciones visuales en tu IU para que el usuario pueda controlar en qué modo quiere usar tu app. Además, puedes abrir el modo de espacio completo cuando corresponda según el contexto de uso de la app. Por ejemplo, se puede abrir el modo de espacio completo cuando se comienza a ver contenido de video y salir de él cuando finaliza la reproducción.

Para simplificar las cosas, este proceso se puede lograr agregando un botón en la barra superior de la aplicación para activar o desactivar el modo.

  1. Crea un nuevo archivo ToggleSpaceModeButton.kt en el paquete com.example.android.xrfundamentals.ui.component y agrega los siguientes elementos componibles:

ToggleSpaceModeButton.kt

package com.example.android.xrfundamentals.ui.component

import androidx.annotation.DrawableRes
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.xr.compose.platform.LocalSpatialCapabilities
import androidx.xr.compose.platform.LocalSpatialConfiguration
import com.example.android.xrfundamentals.R
import com.example.android.xrfundamentals.ui.theme.XRFundamentalsTheme

@Composable
fun ToggleSpaceModeButton(modifier: Modifier = Modifier) {
    val spatialConfiguration = LocalSpatialConfiguration.current

    if (LocalSpatialCapabilities.current.isSpatialUiEnabled) {
        ToggleSpaceModeButton(
            modifier = modifier,
            contentDescription = "Request Home Space mode",
            iconResource = R.drawable.ic_home_space_mode,
            onClick = { spatialConfiguration.requestHomeSpaceMode() }
        )
    } else {
        ToggleSpaceModeButton(
            modifier = modifier,
            contentDescription = "Request Full Space mode",
            iconResource = R.drawable.ic_full_space_mode,
            onClick = { spatialConfiguration.requestFullSpaceMode() }
        )
    }
}

@Composable
fun ToggleSpaceModeButton(
    contentDescription: String,
    @DrawableRes iconResource: Int,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    IconButton(
        modifier = modifier,
        onClick = onClick
    ) {
        Icon(
            painterResource(iconResource),
            contentDescription
        )
    }
}
  1. Agrega el botón como una acción en la TopAppBar cuando la app se esté ejecutando en un dispositivo de realidad extendida.

XRFundamentalsTopAppBar.kt

import androidx.xr.compose.platform.LocalHasXrSpatialFeature

...

TopAppBar(
    ...,
    actions = {
        // Only show the mode toggle if the device supports spatial UI
        if (LocalHasXrSpatialFeature.current) {
            ToggleSpaceModeButton()
        }
    }
)

Ahora, ejecuta la app.

La app ejecutándose en el modo de espacio principal cuando se inicia. Presiona el botón de la parte superior derecha del panel para cambiar al modo de espacio completo.

La app ejecutándose en el modo de espacio completo. Ten en cuenta que ya no está la IU del sistema para minimizar/cerrar la app. Presiona el botón de la parte superior derecha del panel para volver al modo de espacio principal.

Estos fragmentos incluyen algunas APIs nuevas para observar:

  • LocalSpatialConfiguration es un local de composición que ofrece acceso a la configuración espacial actual de la app. Más allá de los métodos para solicitar cambiar de modo, esto incluye otra información como el tamaño del volumen que contiene la app.
  • LocalSpatialCapabilities es un local de composición que se puede usar para determinar qué capacidades espaciales están disponibles para que use una app. Además del modo (espacio principal o espacio completo), esto incluye capacidades como audio espacial y compatibilidad con contenido 3D.
  • LocalHasXrSpatialFeature es un local de composición que se puede usar para determinar si la app se está ejecutando en un dispositivo compatible con funciones de IU espaciales. Bajo la superficie, verifica si el dispositivo tiene la función del sistema android.software.xr.immersive.

Cómo abrir el modo de espacio completo al inicio

Para indicar al SO que inicie una actividad en el modo de espacio completo, puedes incluir un elemento <property> con los siguientes atributos dentro del elemento <activity> correspondiente. Esto se recomienda únicamente si no es probable que los usuarios quieran usar otra app al mismo tiempo en que están usando la tuya.

AndroidManifest.xml

<activity
    android:name=".MainActivity" 
    ... >
    <property
        android:name="android.window.PROPERTY_XR_ACTIVITY_START_MODE"
        android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED" />
</activity>

Ahora, cuando se inicia la app, el usuario es llevado inmediatamente al modo de espacio completo.

abbf3d27cd2a4532.gif

Antes de continuar, quita el elemento <property> mencionado antes del manifiesto para que la app use el comportamiento predeterminado de abrirse en el modo de espacio principal.

7. Divide la IU en varios paneles

Ahora que tu app puede abrir el modo de espacio completo y salir de él, es momento de aprovecharlo mejor. Una fantástica forma de hacerlo es dividir el contenido de tu app en varios paneles para llenar el espacio y (opcionalmente) permitir que los usuarios muevan los paneles y les cambien el tamaño como lo deseen.

Incorpora tu app a un subespacio

Para comenzar, agrega un elemento Subspace componible después del elemento Scaffold componible en el elemento XRFundamentalsApp componible. Los subespacios son una partición de espacio 3D dentro de tu app, en donde puedes compilar diseños 3D (p. ej., agregando paneles espaciales), colocar modelos 3D y agregar profundidad a contenido que, de otra forma, es 2D.

Cuando se ejecuta en un dispositivo que no es de realidad extendida, el contenido del elemento Subspace componible nunca entra en la composición. Cuando se ejecuta en un dispositivo de realidad extendida, el contenido solo entra en la composición cuando la app se está ejecutando en el modo de espacio completo.

XRFundamentalsApp.kt

import androidx.xr.compose.spatial.Subspace

...

HelloAndroidXRTheme {
    Scaffold(...)
    Subspace {
    }
}

Ahora, ejecuta la app:

2d47561a616f4a11.gif

Cuando tu app incluye un elemento Subspace componible, este se mostrará en lugar del contenido 2D. Esto significa que, cuando hagas clic en el botón para abrir el modo de espacio completo, ya no se mostrará nada. Para corregir esto, debes agregar dos paneles espaciales en los siguientes pasos: uno que contenga el contenido principal y otro que contenga el contenido secundario.

Agrega un panel para el contenido principal

Para mostrar el contenido principal en el modo de espacio completo, agrega un SpatialPanel dentro del elemento componible Subspace.

Debido a que este es el panel principal de la app, puedes incluir el Scaffold dentro de él para mantener presentes los controles dentro de la barra superior de la aplicación. En el siguiente codelab, aprenderás sobre órbitas, que se pueden usar para asignar el espacio de los controles que suele contener la barra de la aplicación, como acciones de navegación y específicas del contexto.

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.SpatialPanel

...

Subspace {
    SpatialPanel() {
        Scaffold(
            topBar = { XRFundamentalsTopAppBar() }
        ) { innerPadding ->
            Box(Modifier.padding(innerPadding)) {
                PrimaryCard(
                    modifier = Modifier
                        .padding(16.dp)
                        .verticalScroll(rememberScrollState())
                )
            }
        }
    }
}

Vuelve a ejecutar la app, y verás que el SpatialPanel con el contenido principal se ve en el modo de espacio completo, pero es muy pequeño.

89152c1991d422d4.gif

Modifica el panel principal

Para que el panel principal se pueda usar mejor, puedes agrandarlo con un SubspaceModifier. Los modificadores de subespacios son similares a los modificadores y se usan para cambiar componentes espaciales como los paneles.

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.height
import androidx.xr.compose.subspace.layout.width
import androidx.compose.ui.unit.dp

...

SpatialPanel(
    modifier = SubspaceModifier
        .width(1024.dp)
        .height(800.dp)
){
    ...
}

Vuelve a ejecutar la app. El panel principal debería ocupar mucho más espacio.

c4f28838e16a3eb8.gif

Agrega un panel para el contenido secundario

Ahora que estás ejecutando la app en el modo de espacio completo y usando un panel para mostrar el contenido principal, es momento de mover el contenido secundario a su propio panel. Observa el uso de una Surface dentro del panel espacial. Sin ella, no habría un segundo plano para las tarjetas secundarias, ya que los paneles espaciales son transparentes (el elemento Scaffold componible controló este aspecto en el paso anterior).

XRFundamentalsApp.kt

Subspace {
    SpatialPanel() { ... }
    SpatialPanel(
        modifier = SubspaceModifier
            .width(340.dp)
            .height(800.dp)
    ) {
        Surface {
            SecondaryCardList(
                modifier = Modifier
                    .padding(16.dp)
                    .verticalScroll(rememberScrollState())
            )
        }
    }
}

Ahora, vuelve a ejecutar la app. A simple vista, puede parecer que el segundo panel no se ve, pero en realidad sí (solo que está oculto detrás del panel principal).

7db3c3428b64e482.gif

Diseña los paneles en una fila

Al igual que con el contenido 2D, el uso de filas y columnas es útil para organizar elementos componibles uno al lado del otro sin superponerse. Al trabajar con componentes espaciales como paneles, puedes usar los elementos SpatialRow y SpatialColumn componibles para lograrlo.

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.SpatialRow

...

Subspace {
    SpatialRow(
        curveRadius = 825.dp
    ) {
        SpatialPanel(...) { ... }
        SpatialPanel(...) { ... }
    }
}

Ejecuta la app una vez más. Deberías ver que los paneles están diseñados en una fila, uno detrás del otro. Además, gracias al curveRadius proporcionado a la SpatialRow, los paneles se curvan alrededor del usuario en lugar de permanecer en el mismo plano, lo cual ofrece una experiencia más abarcativa.

7455811775088baf.gif

Haz que los paneles se puedan cambiar de tamaño

Para darles a los usuarios el control de la apariencia de su app, puedes ofrecer la posibilidad de cambiar el tamaño de los paneles usando el modificador de subespacios resizable.

De forma predeterminada, los paneles de tamaño variable se pueden achicar a cero o expandir de forma indefinida. Por lo tanto, recomendamos que te tomes el tiempo para configurar los parámetros minimumSize y maximumSize adecuados en función del contenido que tendrán.

Consulta la documentación de referencia para obtener más detalles de todos los parámetros que admite el modificador resizable.

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.layout.resizable

...

SpatialPanel(
    modifier = SubspaceModifier
        ...
        .resizable(true)
)

2ff2db33032fd251.gif

Haz que los paneles se puedan mover

De forma similar, puedes hacer que los paneles se muevan usando el modificador de subespacios movable.

XRFundamentalsApp.kt

import androidx.xr.compose.subspace.layout.movable

...

SpatialPanel(
    modifier = SubspaceModifier
        ...
        .movable(true)
)

12b6166645ea1be.gif

Consulta la documentación de referencia para obtener más detalles de todos los parámetros que admite el modificador movable.

8. Felicitaciones

Para continuar aprendiendo a aprovechar al máximo la realidad extendida, consulta los siguientes recursos y ejercicios. También puedes solicitar participar en el bootcamp de realidad extendida.

Lecturas adicionales

Desafíos

  • Usa los parámetros adicionales disponibles para los modificadores de subespacios resizable y movable.
  • Agrega paneles adicionales.
  • Usa otros componentes espaciales como un diálogo espacial.

Documentos de referencia