Communitygithub.com

android/skills

Adapta aplicaciones existentes de Android para transmisión de video, juegos y navegadores web para que funcionen como aplicaciones estacionadas en Android Auto y Android Automotive OS.

¿Qué es skills?

Esta habilidad permite a desarrolladores y agentes de IA adaptar aplicaciones Android existentes (transmisión de video, juegos y navegadores web) para que se ejecuten como aplicaciones estacionadas en las plataformas Android Auto y Android Automotive OS. Es útil para cumplir con las pautas de calidad para aplicaciones de automóviles al distribuir en Google Play, cubriendo aspectos como la configuración del manifiesto, declaraciones de funciones de hardware, modo de compatibilidad, navegación hacia atrás, compatibilidad de orientación y continuidad de visualización, inserciones de barras de sistema controlables, recortes de pantalla irregulares, manejo del ciclo de vida con distracción del conductor, restricciones de reproducción de MediaSession con CarUxRestrictionsManager, audio en segundo plano mientras se conduce y protección de datos sensibles en navegadores. No debe usarse para aplicaciones de audio multimedia, aplicaciones de navegación de la biblioteca de aplicaciones para automóviles, puntos de interés, Internet de las cosas, clima o aplicaciones de comunicación diseñadas para usarse mientras se conduce.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/android/skills/tree/HEAD/cars/android-for-cars-parked-apps

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Adapta aplicaciones existentes de Android para video, juegos y navegadores web para que se ejecuten como aplicaciones estacionadas en Android Auto y Android Automotive OS. Sigue estos pasos para cumplir con las pautas de calidad para aplicaciones de automóviles para su distribución en Google Play.

Requisitos previos

  • Comienza con una aplicación Android adaptativa existente en una de las categorías de aplicaciones estacionadas admitidas: aplicaciones de transmisión de video, juegos o navegadores web.

Glosario

  • Aplicaciones estacionadas: Las aplicaciones estacionadas se ejecutan en Android Auto y Android Automotive OS solo mientras el vehículo está estacionado. Las tres categorías estacionadas son video, juegos y navegadores; otras categorías no se pueden publicar como aplicaciones estacionadas.
  • Android Auto: Android Auto es un sistema de proyección basado en teléfono. Las aplicaciones se ejecutan en el teléfono del usuario y se proyectan en la pantalla del automóvil a través de una conexión por cable o inalámbrica. Android Auto es una plataforma separada de Android Automotive OS.
  • Android Automotive OS: Android Automotive OS, o AAOS, es una variante de Android que se ejecuta directamente en el vehículo. Android Automotive OS es una plataforma separada de Android Auto.
  • Categoría de video: Las aplicaciones de video muestran transmisiones de video mientras están estacionadas. Generalmente disponible en Android Automotive OS; no compatible con Android Auto.
  • Categoría de juegos: Las aplicaciones de juegos proporcionan juego mientras están estacionadas. Generalmente disponible en Android Automotive OS y Android Auto.
  • Categoría de navegadores: Los navegadores web permiten a los usuarios navegar por la web mientras están estacionados. Disponible en beta en Android Automotive OS; no compatible con Android Auto.
  • Categoría de medios: No es una categoría estacionada. Las aplicaciones de medios reproducen contenido de audio (música, radio, audiolibros, excluyendo video) mientras conducen o están estacionados.
  • Plataforma Android for Cars: Android for Cars es un término general que incluye Android Auto y Android Automotive OS.
  • Categorías generalmente disponibles: Permitidas en las pistas de prueba interna, prueba cerrada, prueba abierta y producción de Google Play para una plataforma compatible.
  • Categorías beta: Permitidas en las pistas de prueba interna o cerrada; las pistas de prueba abierta y producción requieren aceptación en un programa de acceso anticipado.
  • Audio mientras se conduce: Una función beta en Android Automotive OS que permite a las aplicaciones de video reproducir audio mientras el vehículo está en movimiento.
  • Pautas de calidad para aplicaciones de automóviles: Al auditar una aplicación según los criterios de Nivel 3 (Car ready), Nivel 2 (Car optimized) o Nivel 1 (Car differentiated), DEBE consultar pautas de calidad para aplicaciones de automóviles.
  • Modo de compatibilidad de Android Automotive OS: El modo de compatibilidad (android.software.car.display_compatibility) es una función del sistema en vehículos seleccionados que proporciona una acción de retroceso del sistema, renderizado de área segura, escalado de densidad y bloqueo opaco del modo de conducción (moviendo actividades al estado Stopped). El modo de compatibilidad solo es relevante para aplicaciones que admiten Android Automotive OS; no es relevante para aplicaciones que solo admiten Android Auto.

Exploración del código base

Busca en el código base los archivos AndroidManifest.xml (o crea Assets/Plugins/Android/AndroidManifest.xml en proyectos Unity), res/xml/automotive_app_desc.xml, build.gradle, build.gradle.kts, o gradle/libs.versions.toml. Localiza reproductores de video existentes, clases MediaSession, llamadas requestedOrientation y manejadores WindowInsets. A menos que el usuario indique lo contrario, pide permiso antes de agregar dependencias.

Paso 1: Configurar el manifiesto de la aplicación

Declara la categoría de la aplicación, las plataformas de destino, los requisitos de funciones de hardware y la configuración de la actividad en AndroidManifest.xml.

1.1: Identificar la categoría de la aplicación

  • Aplicaciones de video: Las aplicaciones de video DEBEN establecer android:appCategory="video" en <application> y NO DEBEN incluir app/src/main/res/xml/automotive_app_desc.xml con uses name="video".
  • Juegos: Los juegos DEBEN establecer android:appCategory="game" en <application>. Declara android.hardware.gamepad con android:required="false" si la aplicación admite entrada de controlador.
  • Navegadores: Los navegadores DEBEN incluir <category android:name="android.intent.category.APP_BROWSER"/> en el <intent-filter> MAIN de un <activity> exportado (android:exported="true").

1.2: Identificar plataformas de destino y funciones de hardware

  • Android Auto: Las aplicaciones que apuntan a Android Auto (Android 15+) DEBEN agregar <category android:name="android.intent.category.CAR_LAUNCHER"/> a un <intent-filter> en el archivo AndroidManifest.xml. Agrégalo al <intent-filter> MAIN a menos que el usuario especifique un filtro de intención diferente. NUNCA agregues esta categoría si la aplicación solo apunta a Android Automotive OS.
  • Android Automotive OS: Las aplicaciones que apuntan a Android Automotive OS DEBEN declarar <uses-feature android:name="android.hardware.type.automotive" android:required="false"/> ("false" para pistas móviles o de múltiples factores de forma; "true" solo si la aplicación se publicará en la pista dedicada de Automotive OS) en el archivo AndroidManifest.xml. NUNCA agregues esta etiqueta de función si la aplicación solo apunta a Android Auto.
  • Funciones de hardware no requeridas (DO-1): Para cumplir con los requisitos de funciones de Google Play y DO-1, declara funciones no admitidas (android.hardware.wifi, android.hardware.screen.portrait, android.hardware.screen.landscape, android.hardware.camera) con android:required="false", y elimina android:required="true" en funciones ausentes en los automóviles.
  • Continuidad de visualización (LS-C1): Configura android:configChanges para screenSize, smallestScreenSize, orientation, screenLayout y density en <activity> para que el movimiento hacia o desde una pantalla distante no recrea la actividad o interrumpe la reproducción.
  • Modo de compatibilidad y distracción: Declarar el modo de compatibilidad es opcional y solo es relevante para aplicaciones que admiten Android Automotive OS. NUNCA agregues el modo de compatibilidad para aplicaciones que solo admiten Android Auto. Agregar android.hardware.type.automotive deshabilita el modo de compatibilidad a menos que se agregue <meta-data android:name="android.software.car.display_compatibility" android:value="true"/> a <application>. Cuando una aplicación declara android.software.car.display_compatibility en AndroidManifest.xml, la aplicación DEBE verificar PackageManager.hasSystemFeature("android.software.car.display_compatibility") en tiempo de ejecución y ocultar las acciones de retroceso o cierre duplicadas dentro de la aplicación cuando devuelve true. Las aplicaciones estacionadas NO DEBEN incluir <meta-data android:name="distractionOptimized" android:value="true"/> en ningún <activity> (DD-2, DD-3).

Paso 2: Proporcionar navegación hacia atrás y soporte de orientación

2.1: Agregar acciones de retroceso y cierre dentro de la aplicación

Los vehículos con Android Automotive OS no están obligados a tener un botón de retroceso de hardware o software ni navegación por gestos (AN-1). Proporciona controles explícitos de retroceso y cierre en la interfaz de usuario en cada pantalla que no sea raíz, incluyendo pantallas de detalle y reproductores de pantalla completa:

  • Si AndroidManifest.xml no declara android.software.car.display_compatibility: Muestra controles explícitos de retroceso y cierre dentro de la aplicación de forma incondicional.
  • Si AndroidManifest.xml declara android.software.car.display_compatibility con android:value="true": Muestra controles de retroceso y cierre dentro de la aplicación solo cuando PackageManager.hasSystemFeature("android.software.car.display_compatibility") devuelve false.

2.2: Proteger las solicitudes de orientación en tiempo de ejecución

Las pantallas de los vehículos tienen orientaciones fijas. Solicitar orientación horizontal en una pantalla de automóvil fija vertical causa bandas negras o bucles de parpadeo (DO-1). Elimina los atributos de manifiesto android:screenOrientation codificados y verifica PackageManager.FEATURE_SCREEN_LANDSCAPE y PackageManager.FEATURE_SCREEN_PORTRAIT antes de establecer requestedOrientation.

Paso 3: Adaptarse a las barras del sistema y los recortes de pantalla irregulares

3.1: Rastrear las inserciones de barras del sistema controlables

En Android Automotive OS, los OEM pueden bloquear las barras del sistema visibles para que los controles de clima y vehículo sigan siendo accesibles (AR-1). Rastrea las inserciones controlables con OnControllableInsetsChangedListener, oculta solo las barras controlables y aplica windowInsetsPadding para las inserciones no controlables de statusBars, navigationBars y displayCutout.

3.2: Renderizar de forma segura en recortes de pantalla irregulares

Para cumplir con el criterio de Nivel 1 AR-2 en pantallas de automóvil curvas o no rectangulares, NUNCA uses LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT (0) o LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES (1). Configura LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS (3) o LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER (2) usando el calificador de recurso car en res/values-car-v30/integers.xml:

<integer name="windowLayoutInDisplayCutoutMode">3</integer>

Protege la interfaz de usuario interactiva, las barras de la aplicación y las listas desplazables con WindowInsets.safeDrawing.

Paso 4: Cumplir con los requisitos de distracción del conductor y reproducción de medios

4.1: Pausar la reproducción en transiciones del ciclo de vida y bloquear la reanudación al conducir

Cuando un vehículo comienza a moverse, el sistema operativo cubre las actividades estacionadas con una superposición de bloqueo y activa onPause (y onStop en vehículos con modo de compatibilidad). Para cumplir con DD-2, DD-3 y MC-1:

  1. Pausa la reproducción en ON_PAUSE o ON_STOP usando LifecycleEventEffect de androidx.lifecycle:lifecycle-runtime-compose.
  2. Expón un MediaSession (androidx.media3:media3-session) con comandos de reproducción, pausa o detención y metadatos de elementos (MC-1), y libéralo en onCleared.
  3. Agrega useLibrary("android.car") en build.gradle.kts, envuelve ExoPlayer en ForwardingSimpleBasePlayer, escucha CarUxRestrictionsManager, pausa la reproducción cuando isRequiresDistractionOptimization se vuelve true, y elimina COMMAND_PLAY_PAUSE en getState para que los controles externos de MediaSession no puedan reanudar la reproducción mientras se conduce:
@UnstableApi
class CarAwarePlayer(context: Context) :
    ForwardingSimpleBasePlayer(ExoPlayer.Builder(context).build()) {
    private var shouldPreventPlay = false
    private var pausedByUxRestrictions = false
    private lateinit var carUxRestrictionsManager: CarUxRestrictionsManager

    init {
        if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
            val car = Car.createCar(context)
            carUxRestrictionsManager =
                car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
            shouldPreventPlay =
                carUxRestrictionsManager.currentCarUxRestrictions.isRequiresDistractionOptimization
            invalidateState()

            carUxRestrictionsManager.registerListener { restrictions: CarUxRestrictions ->
                shouldPreventPlay = restrictions.isRequiresDistractionOptimization
                if (!shouldPreventPlay && pausedByUxRestrictions) {
                    handleSetPlayWhenReady(true)
                    invalidateState()
                } else if (shouldPreventPlay && isPlaying) {
                    pausedByUxRestrictions = true
                    handleSetPlayWhenReady(false)
                    invalidateState()
                }
            }
        }
    }

    override fun getState(): State {
        val state = super.getState()
        return state.buildUpon()
            .setAvailableCommands(
                state.availableCommands.buildUpon()
                    .removeIf(COMMAND_PLAY_PAUSE, shouldPreventPlay)
                    .build()
            )
            .build()
    }

    override fun handleRelease(): ListenableFuture<*> {
        if (::carUxRestrictionsManager.isInitialized) {
            carUxRestrictionsManager.unregisterListener()
        }
        return super.handleRelease()
    }
}

4.2: Compatibilidad con audio en segundo plano mientras se conduce (función beta opcional)

Como esta es una función beta opcional, NUNCA implementes esta función a menos que el usuario lo solicite. Para implementar la función:

  1. Declara <uses-feature android:name="com.android.car.background_audio_while_driving" android:required="false" /> en AndroidManifest.xml, junto con los permisos FOREGROUND_SERVICE y FOREGROUND_SERVICE_MEDIA_PLAYBACK.
  2. Verifica la compatibilidad del vehículo en tiempo de ejecución con CarFeatures.isFeatureEnabled(context, CarFeatures.FEATURE_BACKGROUND_AUDIO_WHILE_DRIVING) de androidx.car.app:app. Solo establece shouldPreventPlay cuando !isBackgroundAudioWhileDrivingSupported && restrictions.isRequiresDistractionOptimization.
  3. Aloja el MediaSession y el reproductor dentro de un MediaSessionService exportado con android:foregroundServiceType="mediaPlayback", y conéctate desde la interfaz de usuario usando MediaController.Builder y buildAsync.

Paso 5: Proteger datos confidenciales en aplicaciones de navegador

Debido a que los vehículos son dispositivos compartidos, los navegadores DEBEN bloquear el acceso a contraseñas guardadas y métodos de pago a menos que estén protegidos por un bloqueo de perfil (SD-1). Antes de sincronizar contraseñas o datos de pago con el vehículo, los navegadores DEBEN solicitar al usuario que se autentique y mostrar un aviso en la pantalla del automóvil indicando que sus datos se sincronizarán con el automóvil (SD-2).

Verifica si se ha establecido un PIN, patrón o contraseña usando KeyguardManager, abre Settings.ACTION_SECURITY_SETTINGS si no está configurado, y autentica con BiometricPrompt usando solo BiometricManager.Authenticators.DEVICE_CREDENTIAL (los vehículos no tienen hardware biométrico):

val keyguardManager = context.getSystemService<KeyguardManager>()
val isDeviceSecure = keyguardManager?.isDeviceSecure == true
lateinit var biometricPrompt: BiometricPrompt

if (!isDeviceSecure) {
    context.startActivity(
        Intent(Settings.ACTION_SECURITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    )
} else {
    val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle(context.getString(R.string.auth_title))
        .setSubtitle(context.getString(R.string.sync_data_to_car_notice))
        .setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
        .build()
    biometricPrompt.authenticate(promptInfo)
}

Paso 6: Verificar la implementación

Compila la aplicación usando ./gradlew assembleDebug. Encuentra y corrige cualquier error de compilación.

Skills relacionados