Communitygithub.com

android/skills - Habilidades para Android Automotive

Adapte aplicativos existentes de streaming de vídeo, jogos e navegadores web para Android Auto e Android Automotive OS para executarem como aplicativos estacionados. Aborda configuração de manifesto, declarações de recursos de hardware do Google Play, modo de compatibilidade, navegação de retorno, orientação e continuidade de exibição, recortes de tela irregulares, ciclo de vida com distração do motorista, restrições de reprodução com MediaSession e CarUxRestrictionsManager, áudio em segundo plano durante a direção e proteção de dados sensíveis em navegadores.

O que é skills - Habilidades para Android Automotive?

Esta habilidade orienta desenvolvedores a adaptarem aplicativos Android existentes de streaming de vídeo, jogos e navegadores web para serem executados como 'aplicativos estacionados' (parked apps) nas plataformas Android Auto e Android Automotive OS (AAOS), garantindo a conformidade com as diretrizes de qualidade para apps automotivos do Google Play. Ela cobre desde a configuração inicial do manifesto Android (declaração de categoria, plataformas alvo e recursos de hardware) até a implementação de funcionalidades críticas como navegação de retorno manual, suporte a orientação de tela, gerenciamento de barras de sistema e recortes de exibição, tratamento do ciclo de vida do aplicativo quando o veículo começa a se mover, e a integração com MediaSession e CarUxRestrictionsManager para pausar a reprodução durante a condução. Para navegadores, a habilidade detalha a proteção de dados sensíveis, como senhas e métodos de pagamento, utilizando autenticação biométrica (via BiometricPrompt) e verificação de bloqueio de tela. A habilidade é útil para migrar, construir ou auditar aplicativos para o ecossistema automotivo do Google, guiando o desenvolvedor por cada etapa necessária para aprovação na loja, diferenciando claramente os requisitos para Android Auto e Android Automotive OS. O suporte técnico inclui exemplos de código Kotlin para integração com CarUxRestrictionsManager e ForwardingSimpleBasePlayer para controle de reprodução consciente da distração, além de configurações XML no AndroidManifest.xml.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Adapte aplicativos Android existentes de vídeo, jogos e navegadores web para serem executados como aplicativos estacionados no Android Auto e no Android Automotive OS. Siga estas etapas para atender às diretrizes de qualidade de aplicativos para carros na distribuição pelo Google Play.

Pré-requisitos

  • Comece com um aplicativo Android adaptativo existente em uma das categorias de aplicativos estacionados compatíveis: aplicativos de streaming de vídeo, jogos ou navegadores web.

Glossário

  • Aplicativos estacionados (Parked apps): Aplicativos estacionados são executados no Android Auto e no Android Automotive OS apenas enquanto o veículo está estacionado. As três categorias de estacionados são vídeo, jogos e navegadores; outras categorias não podem ser publicadas como aplicativos estacionados.
  • Android Auto: O Android Auto é um sistema de projeção alimentado pelo telefone. Os aplicativos são executados no telefone do usuário e projetados no display do carro por meio de uma conexão com ou sem fio. O Android Auto é uma plataforma separada do Android Automotive OS.
  • Android Automotive OS: O Android Automotive OS, ou AAOS, é uma variante do Android que é executada diretamente no veículo. O Android Automotive OS é uma plataforma separada do Android Auto.
  • Categoria de Vídeo: Aplicativos de vídeo exibem vídeos em streaming enquanto estacionados. Geralmente disponível no Android Automotive OS; não compatível com Android Auto.
  • Categoria de Jogos: Aplicativos de jogos fornecem gameplay enquanto estacionados. Geralmente disponível no Android Automotive OS e Android Auto.
  • Categoria de Navegadores: Navegadores web permitem que os usuários naveguem na web enquanto estacionados. Disponível em beta no Android Automotive OS; não compatível com Android Auto.
  • Categoria de Mídia: Não é uma categoria estacionada. Aplicativos de mídia reproduzem conteúdo de áudio (música, rádio, audiolivros, excluindo vídeo) enquanto dirige ou está estacionado.
  • Plataforma Android para Carros: Android para Carros é um termo abrangente que consiste em Android Auto e Android Automotive OS.
  • Categorias Geralmente Disponíveis: Permitidas nos canais de teste interno, teste fechado, teste aberto e produção do Google Play para uma plataforma compatível.
  • Categorias Beta: Permitidas nos canais de teste interno ou fechado; canais de teste aberto e produção exigem aceitação em um programa de acesso antecipado.
  • Áudio durante a direção: Um recurso beta no Android Automotive OS que permite que aplicativos de vídeo reproduzam áudio enquanto o veículo está em movimento.
  • Diretrizes de qualidade de aplicativos para carros: Ao auditar um aplicativo de acordo com os critérios Tier 3 (Pronto para carro), Tier 2 (Otimizado para carro) ou Tier 1 (Diferenciado para carro), DEVE verificar as diretrizes de qualidade de aplicativos para carros.
  • Modo de compatibilidade do Android Automotive OS: O modo de compatibilidade (android.software.car.display_compatibility) é um recurso de sistema em veículos selecionados que fornece um affordance de retorno do sistema, renderização de área segura, dimensionamento de densidade e bloqueio opaco durante a condução (movendo atividades para o estado Stopped). O modo de compatibilidade é relevante apenas para aplicativos que suportam Android Automotive OS; não é relevante para aplicativos que suportam apenas Android Auto.

Exploração do código-fonte

Pesquise no código-fonte por arquivos AndroidManifest.xml (ou crie Assets/Plugins/Android/AndroidManifest.xml em projetos Unity), res/xml/automotive_app_desc.xml, build.gradle, build.gradle.kts, ou gradle/libs.versions.toml. Localize players de vídeo existentes, classes MediaSession, chamadas requestedOrientation e manipuladores WindowInsets. A menos que instruído de outra forma pelo usuário, peça permissão antes de adicionar dependências.

Etapa 1: Configurar o manifesto do aplicativo

Declare a categoria do aplicativo, plataformas alvo, requisitos de recursos de hardware e configuração de atividade no AndroidManifest.xml.

1.1: Identificar a categoria do aplicativo

  • Aplicativos de Vídeo: Aplicativos de vídeo DEVEM definir android:appCategory="video" em <application> e NÃO DEVEM incluir app/src/main/res/xml/automotive_app_desc.xml com uses name="video".
  • Jogos: Jogos DEVEM definir android:appCategory="game" em <application>. Declare android.hardware.gamepad com android:required="false" se a entrada do controle for suportada pelo aplicativo.
  • Navegadores: Navegadores DEVEM incluir <category android:name="android.intent.category.APP_BROWSER"/> no MAIN <intent-filter> de uma <activity> exportada (android:exported="true").

1.2: Identificar plataformas alvo e recursos de hardware

  • Android Auto: Aplicativos direcionados ao Android Auto (Android 15+) DEVEM adicionar <category android:name="android.intent.category.CAR_LAUNCHER"/> a um <intent-filter> no arquivo AndroidManifest.xml. Adicione-o ao MAIN <intent-filter> a menos que o usuário especifique um filtro de intenção diferente. NUNCA adicione esta categoria se o aplicativo for direcionado exclusivamente ao Android Automotive OS.
  • Android Automotive OS: Aplicativos direcionados ao Android Automotive OS DEVEM declarar <uses-feature android:name="android.hardware.type.automotive" android:required="false"/> ("false" para canais móveis ou de múltiplos formatos; "true" apenas se o aplicativo for publicado no canal dedicado do Automotive OS) no arquivo AndroidManifest.xml. NUNCA adicione esta tag de recurso se o aplicativo for direcionado exclusivamente ao Android Auto.
  • Recursos de hardware não obrigatórios (DO-1): Para satisfazer os requisitos de recursos do Google Play e DO-1, declare recursos não suportados (android.hardware.wifi, android.hardware.screen.portrait, android.hardware.screen.landscape, android.hardware.camera) com android:required="false", e remova android:required="true" em recursos ausentes em carros.
  • Continuidade de exibição (LS-C1): Configure android:configChanges para screenSize, smallestScreenSize, orientation, screenLayout e density em <activity> para que mover para ou de uma tela distante não recrie a atividade ou cause instabilidade na reprodução.
  • Modo de compatibilidade e distração: Declarar o modo de compatibilidade é opcional e relevante apenas para aplicativos que suportam Android Automotive OS. NUNCA adicione modo de compatibilidade para aplicativos que suportam apenas Android Auto. Adicionar android.hardware.type.automotive desabilita o modo de compatibilidade, a menos que <meta-data android:name="android.software.car.display_compatibility" android:value="true"/> seja adicionado a <application>. Quando um aplicativo declara android.software.car.display_compatibility no AndroidManifest.xml, o aplicativo DEVE verificar PackageManager.hasSystemFeature("android.software.car.display_compatibility") em tempo de execução e ocultar affordances duplicados de retorno ou fechar no aplicativo quando retornar true. Aplicativos estacionados NÃO DEVEM incluir <meta-data android:name="distractionOptimized" android:value="true"/> em qualquer <activity> (DD-2, DD-3).

Etapa 2: Fornecer suporte de navegação de retorno e orientação

2.1: Adicionar affordances de retorno e fechar no aplicativo

Os veículos com Android Automotive OS não são obrigados a ter um botão de retorno de hardware ou software ou navegação por gestos (AN-1). Forneça controles explícitos de retorno e fechar na interface do usuário em cada tela que não seja raiz, incluindo telas de detalhes e players em tela cheia:

  • Se AndroidManifest.xml não declarar android.software.car.display_compatibility: Exiba controles explícitos de retorno e fechar no aplicativo incondicionalmente.
  • Se AndroidManifest.xml declarar android.software.car.display_compatibility com android:value="true": Mostre controles de retorno e fechar no aplicativo apenas quando PackageManager.hasSystemFeature("android.software.car.display_compatibility") retornar false.

2.2: Proteger solicitações de orientação em tempo de execução

Os displays dos veículos têm orientações fixas. Solicitar paisagem em um display de carro fixo em retrato causa letterboxing ou loops de oscilação (DO-1). Remova atributos de manifesto android:screenOrientation codificados e verifique PackageManager.FEATURE_SCREEN_LANDSCAPE e PackageManager.FEATURE_SCREEN_PORTRAIT antes de definir requestedOrientation.

Etapa 3: Adaptar-se às barras do sistema e recortes de exibição irregulares

3.1: Rastrear insets de barras de sistema controláveis

No Android Automotive OS, as montadoras têm permissão para travar as barras do sistema visíveis para que os controles de clima e veículo permaneçam acessíveis (AR-1). Rastreie insets controláveis com OnControllableInsetsChangedListener, oculte apenas barras controláveis e aplique windowInsetsPadding para insets não controláveis statusBars, navigationBars e displayCutout.

3.2: Renderizar com segurança em recortes de exibição irregulares

Para atender ao critério Tier 1 AR-2 em displays de carro curvos ou não retangulares, NUNCA use LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT (0) ou LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES (1). Configure LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS (3) ou LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER (2) usando o qualificador de recurso car em res/values-car-v30/integers.xml:

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

Proteja a interface do usuário interativa, barras de aplicativos e listas roláveis com WindowInsets.safeDrawing.

Etapa 4: Atender aos requisitos de distração do motorista e reprodução de mídia

4.1: Pausar a reprodução em transições de ciclo de vida e bloquear o reinício durante a condução

Quando um veículo começa a se mover, o sistema operacional cobre as atividades estacionadas com uma sobreposição de bloqueio e aciona onPause (e onStop em veículos com modo de compatibilidade). Para satisfazer DD-2, DD-3 e MC-1:

  1. Pause a reprodução em ON_PAUSE ou ON_STOP usando LifecycleEventEffect de androidx.lifecycle:lifecycle-runtime-compose.
  2. Exponha um MediaSession (androidx.media3:media3-session) com comandos de reprodução, pausa ou parada e metadados de item (MC-1), e o libere em onCleared.
  3. Adicione useLibrary("android.car") em build.gradle.kts, envolva ExoPlayer em ForwardingSimpleBasePlayer, escute CarUxRestrictionsManager, pause a reprodução quando isRequiresDistractionOptimization se tornar true, e remova COMMAND_PLAY_PAUSE em getState para que os controles externos do MediaSession não possam retomar a reprodução durante a condução:
@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: Suportar áudio em segundo plano durante a direção (recurso beta opcional)

Como este é um recurso beta opcional, NUNCA implemente este recurso a menos que o usuário o solicite. Para implementar o recurso:

  1. Declare <uses-feature android:name="com.android.car.background_audio_while_driving" android:required="false" /> no AndroidManifest.xml, junto com as permissões FOREGROUND_SERVICE e FOREGROUND_SERVICE_MEDIA_PLAYBACK.
  2. Verifique o suporte do veículo em tempo de execução com CarFeatures.isFeatureEnabled(context, CarFeatures.FEATURE_BACKGROUND_AUDIO_WHILE_DRIVING) de androidx.car.app:app. Defina shouldPreventPlay apenas quando !isBackgroundAudioWhileDrivingSupported && restrictions.isRequiresDistractionOptimization.
  3. Hospede o MediaSession e o player dentro de um MediaSessionService exportado com android:foregroundServiceType="mediaPlayback", e conecte-se da interface do usuário usando MediaController.Builder e buildAsync.

Etapa 5: Proteger dados sensíveis em aplicativos de navegador

Como os veículos são dispositivos compartilhados, os navegadores DEVEM bloquear o acesso a senhas salvas e métodos de pagamento, a menos que estejam protegidos por um bloqueio de perfil (SD-1). Antes de sincronizar senhas ou dados de pagamento com o veículo, os navegadores DEVEM solicitar que o usuário se autentique e exibir um aviso na tela do carro informando que seus dados serão sincronizados com o carro (SD-2).

Verifique se um PIN, padrão ou senha foi definido usando KeyguardManager, abra Settings.ACTION_SECURITY_SETTINGS se não estiver definido e autentique com BiometricPrompt usando apenas BiometricManager.Authenticators.DEVICE_CREDENTIAL (os veículos não possuem 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)
}

Etapa 6: Verificar a implementação

Compile o aplicativo usando ./gradlew assembleDebug. Encontre e corrija quaisquer erros de compilação.

Habilidades Relacionadas