Compatibilidade com dobráveis triplos e na horizontal

Um dispositivo dobrável no modo paisagem nas posições fechada e totalmente aberta ao lado de um dispositivo triplo nas posições fechada e totalmente aberta.

Os desenvolvedores costumam enfrentar dificuldades únicas ao criar aplicativos para dispositivos dobráveis, especialmente dispositivos como o Samsung Trifold ou o Pixel Fold original, que abre no formato paisagem (rotation_0 = paisagem). Os erros dos desenvolvedores incluem:

  • Suposições incorretas sobre a orientação do dispositivo
  • Casos de uso esquecidos
  • Falha ao recalcular ou armazenar em cache valores em todas as mudanças de configuração

Problemas específicos relacionados ao dispositivo:

  • Uma incompatibilidade na orientação natural do dispositivo entre as telas interna e da capa (pressupostos com base em rotation_0 = retrato), fazendo com que os apps falhem ao dobrar e desdobrar.
  • Diferentes densidades de tela e tratamento incorreto da mudança de configuração de densidade
  • Problemas de visualização da câmera causados pela dependência do sensor de câmera na orientação natural

Para oferecer uma experiência do usuário de alta qualidade em dispositivos dobráveis, concentre-se nas seguintes áreas críticas:

  • Determine a orientação do app com base na área real da tela que ele ocupa, não na orientação física do dispositivo.
  • Atualize as prévias da câmera para gerenciar corretamente a orientação do dispositivo e as proporções, evitar prévias laterais e impedir imagens esticadas ou cortadas.
  • Mantenha a continuidade do app durante a dobra ou o desdobramento do dispositivo retendo o estado com ViewModel ou abordagens semelhantes, ou processando manualmente mudanças de densidade e orientação da tela, o que evita reinicializações do app ou perda de estado.
  • Para apps que usam sensores de movimento, ajuste o sistema de coordenadas para se alinhar à orientação atual da tela e evite suposições com base em rotation_0 = retrato, garantindo interações precisas do usuário.

Criar adaptável

Se o app já for adaptável e seguir o nível otimizado (Nível 2) descrito nas diretrizes de qualidade de apps para telas grandes, ele vai funcionar bem em dispositivos dobráveis. Caso contrário, antes de verificar os detalhes específicos dos dispositivos dobráveis triplos e horizontais, revise os seguintes conceitos básicos de desenvolvimento adaptável do Android.

Layouts adaptáveis

A interface precisa processar não apenas diferentes tamanhos de tela, mas também mudanças em tempo real na proporção, como desdobrar e entrar nos modos de várias janelas ou janelas de computador. Consulte Sobre layouts adaptáveis para mais orientações sobre como:

  • Projetar e implementar layouts adaptáveis
  • Ajustar a navegação principal do app com base no tamanho da janela
  • Usar classes de tamanho de janela para adaptar a interface do app
  • Simplifique a implementação de layouts canônicos, como lista-detalhe, usando as APIs Jetpack.
Um app com efeito letterbox em um dispositivo dobrável aberto e o mesmo app em tela cheia com um layout adaptável em outro dispositivo dobrável aberto.
Figura 1. Diferença entre layouts não adaptáveis (com barras pretas) e adaptáveis.

Classes de tamanho de janela

Os dispositivos dobráveis, incluindo os dobráveis na horizontal e os triplos, podem alternar entre classes de tamanho de janela compacta, média e expandida instantaneamente. Entender e implementar essas classes garante que o app mostre os componentes de navegação e a densidade de conteúdo corretos para o estado atual do dispositivo.

Representação de um app em dispositivos dimensionados para as classes de tamanho de janela compacta, média e expandida.
Figura 2. Classes de tamanho de janela.

O exemplo a seguir usa a biblioteca adaptável do Material 3 para determinar quanto espaço o app tem disponível. Primeiro, ele invoca a função currentWindowAdaptiveInfo() e depois usa os layouts correspondentes para as três classes de tamanho de janela:

val adaptiveInfo = currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)
val windowSizeClass = adaptiveInfo.windowSizeClass

when {
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND) -> // Large
  windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) -> // Medium
  else -> // Compact
}

Para mais informações, consulte Usar classes de tamanho de janela.

Qualidade de apps para telas grandes

Seguir o Nível 2 (otimizado para telas grandes) ou o Nível 1 (diferenciado para telas grandes) das diretrizes de qualidade de apps para telas grandes garante que seu app ofereça uma experiência do usuário interessante em dispositivos dobráveis triplos, dobráveis horizontais e outros dispositivos de tela grande. As diretrizes abrangem verificações críticas em vários níveis para passar de uma experiência adaptativa para uma diferenciada.

Android 16 e versões mais recentes

Em apps direcionados ao Android 16 (nível 36 da API) e versões mais recentes, o sistema ignora restrições de orientação, redimensionamento e proporção em telas com largura mínima >= 600 dp. Os apps preenchem toda a janela de exibição, independente da proporção ou da orientação preferida do usuário, e o modo de compatibilidade letterbox não é mais usado.

Considerações especiais

Os dispositivos dobráveis em três partes e no modo paisagem apresentam comportamentos de hardware exclusivos que exigem um tratamento específico, principalmente em relação a sensores, visualização da câmera e continuidade da configuração (retenção do estado ao dobrar, desdobrar ou redimensionar).

Visualização da câmera

Um problema comum em dispositivos dobráveis na orientação paisagem ou em cálculos de proporção (em cenários como várias janelas, janelas de computador ou telas conectadas) é quando a visualização da câmera aparece esticada, de lado, cortada ou girada.

Proposições incompatíveis

Esse problema costuma acontecer em dispositivos de tela grande e dobráveis porque os apps podem presumir relações fixas entre recursos da câmera, como proporção e orientação do sensor, e recursos do dispositivo, como orientação do dispositivo e orientação natural.

Novos formatos desafiam essa proposição. Um dispositivo dobrável pode mudar o tamanho da tela e a proporção sem que a rotação do dispositivo seja alterada. Por exemplo, ao abrir um dispositivo, a proporção muda, mas se o usuário não girar o dispositivo, a rotação dele permanece a mesma. Se um app presumir que a proporção está relacionada à rotação do dispositivo, ele poderá girar ou dimensionar incorretamente a visualização da câmera. O mesmo pode acontecer se um app presumir que a orientação do sensor da câmera corresponde à orientação retrato do dispositivo, o que nem sempre é verdade para dispositivos dobráveis no modo paisagem.

Solução 1: Jetpack CameraX (melhor)

A solução mais simples e robusta é usar a biblioteca CameraX do Jetpack. O elemento de interface PreviewView foi projetado para processar automaticamente todas as complexidades de prévia:

  • O PreviewView se ajusta corretamente à orientação do sensor, à rotação do dispositivo e ao dimensionamento.
  • Ela mantém a proporção da imagem da câmera, geralmente centralizando e cortando (FILL_CENTER).
  • Você pode definir o tipo de escala como FIT_CENTER para adicionar barras pretas à visualização, se necessário.

Para mais informações, consulte Implementar uma prévia na documentação do CameraX.

Solução 2: CameraViewfinder

Se você estiver usando uma base de código Camera2, a biblioteca CameraViewfinder (compatível com versões anteriores até o nível 21 da API) será outra solução moderna. Ele simplifica a exibição do feed da câmera usando um TextureView ou SurfaceView e aplicando todas as transformações necessárias (proporção, escala e rotação) para você.

Para mais informações, consulte a postagem do blog Apresentação do visor da câmera e o guia do desenvolvedor Visualização da câmera.

Solução 3: implementação manual do Camera2

Se não for possível usar o CameraX ou o CameraViewfinder, calcule manualmente a orientação e a proporção e verifique se os cálculos são atualizados a cada mudança de configuração:

  • Receba a orientação do sensor da câmera (por exemplo, 0, 90, 180, 270 graus) de CameraCharacteristics.
  • Acessar a rotação atual da tela do dispositivo (por exemplo, 0, 90, 180, 270 graus).
  • Use esses dois valores para determinar as transformações necessárias para seu SurfaceView ou TextureView.
  • Confira se a proporção da saída Surface corresponde à proporção da prévia da câmera para evitar distorções.
  • O app de câmera pode estar sendo executado em uma parte da tela, no modo de várias janelas ou de janela para computador ou em uma tela conectada. Por isso, o tamanho da tela não deve ser usado para determinar as dimensões do visor da câmera. Em vez disso, use métricas da janela.

Para mais informações, consulte o guia para desenvolvedores Visualização da câmera e o vídeo Seu app Câmera em diferentes formatos.

Solução 4: realizar ações básicas da câmera usando uma intent

Se você não precisa de muitos recursos de câmera, uma solução simples e direta é realizar ações básicas, como capturar uma foto ou um vídeo usando o app de câmera padrão do dispositivo. Não é necessário fazer a integração com uma biblioteca de câmera. Em vez disso, use uma intent.

Para mais informações, consulte Intents da câmera.

Configuração e continuidade

Os dispositivos dobráveis aumentam a versatilidade da interface, mas podem iniciar mais mudanças de configuração do que os não dobráveis. O app precisa gerenciar essas mudanças de configuração e as combinações delas, como rotação, dobra/desdobramento e redimensionamento de janela em modos de várias janelas ou desktop, mantendo ou restaurando o estado do app. Por exemplo, os apps precisam manter a seguinte continuidade:

  • Estado do app sem falhas ou mudanças disruptivas para os usuários (por exemplo, ao trocar de tela ou enviar o app para segundo plano)
  • Posição de rolagem dos campos roláveis
  • Texto digitado em campos de texto e estado do teclado
  • Posição de reprodução de mídia para que a reprodução seja retomada de onde parou quando a mudança de configuração foi iniciada

As mudanças de configuração que são acionadas com frequência incluem screenSize, smallestScreenSize, screenLayout, orientation, density, fontScale, touchscreen e keyboard.

Consulte android:configChanges e Gerenciar mudanças de configuração. Para mais informações sobre como gerenciar o estado do app, consulte Salvar estados da interface.

Mudanças na configuração de densidade

As telas interna e externa de dispositivos dobráveis triplos e horizontais podem ter densidades de pixels diferentes. Portanto, gerenciar a mudança de configuração para density requer mais atenção. Normalmente, o Android reinicia a atividade quando a densidade da tela muda, o que pode causar perda de dados. Para evitar que o sistema reinicie a atividade, declare o processamento de densidade no manifesto e gerencie a mudança de configuração de forma programática no app.

Configuração do AndroidManifest.xml

  • density: declara que o app vai processar a mudança de densidade da tela.
  • Outras mudanças de configuração: também é bom declarar outras mudanças de configuração que ocorrem com frequência, por exemplo, screenSize, orientation, keyboardHidden, fontScale e assim por diante.

Declarar a densidade (e outras mudanças de configuração) impede que o sistema reinicie a atividade e, em vez disso, chama onConfigurationChanged().

Implementação de onConfigurationChanged()

Quando uma mudança de densidade ocorre, é necessário atualizar os recursos (como recarregar bitmaps ou recalcular tamanhos de layout) no callback:

  • Verifique se o DPI mudou para newConfig.densityDpi.
  • Redefina visualizações personalizadas, elementos gráficos personalizados e assim por diante para a nova densidade.

Itens de recursos a serem processados

  • Recurso de imagem: substitua bitmaps e elementos gráficos por recursos específicos de densidade ou ajuste a escala diretamente.
  • Unidade de layout (conversão de dp para px): recalcular tamanho da visualização, margem e padding
  • Tamanho da fonte e do texto: reaplique o tamanho do texto da unidade sp
  • Desenho personalizado de View/Canvas: atualize os valores baseados em pixels usados para desenhar Canvas

Como determinar a orientação do app

Nunca confie na rotação do dispositivo físico ao criar um app adaptável, porque ela será ignorada em dispositivos de tela grande, e um app no modo de várias janelas pode ter uma orientação diferente da do dispositivo. Em vez disso, use Configuration.orientation ou WindowMetrics para identificar se o app está no momento na orientação paisagem ou retrato com base no tamanho da janela.

Solução 1: usar Configuration.orientation

Essa propriedade identifica a orientação em que seu app está sendo mostrado.

Solução 2: usar WindowMetrics#getBounds()

Você pode acessar os limites da tela atual do app e verificar a largura e a altura para determinar a orientação.

Se você precisar limitar a orientação do app em smartphones (ou nas telas externas de dispositivos dobráveis), mas não em dispositivos de tela grande, consulte Restringir a orientação do app em smartphones.

Posturas e modos de exibição

Posições e estados dobráveis, como de mesa e HALF_OPENED, são compatíveis com dobráveis no modo retrato e paisagem. No entanto, os modelos dobráveis em três partes não têm suporte para a postura de mesa e não podem ser usados HALF_OPENED. Os folhetos dobrados em três partes oferecem uma tela maior para uma experiência única do usuário quando totalmente desdobrados.

Para diferenciar seu app em dispositivos dobráveis que oferecem suporte a HALF_OPENED, use APIs do Jetpack WindowManager, como FoldingFeature.

Saiba mais sobre posturas, estados e suporte para prévia da câmera em dispositivos dobráveis nos seguintes guias para desenvolvedores:

Os dispositivos dobráveis oferecem experiências de visualização únicas. O modo de tela traseira e o Dual Screen permitem criar recursos especiais de exibição para dispositivos dobráveis, como a prévia da selfie de câmera traseira e telas interna e externa simultâneas. Para mais informações, consulte:

Bloqueio da orientação para a orientação natural do sensor

Para casos de uso muito específicos, principalmente apps que precisam ocupar toda a tela sem relação com o estado dobrado do dispositivo, a flag nosensor permite bloquear o app na orientação natural do dispositivo. Por exemplo, em um Pixel Fold, a orientação natural do dispositivo quando dobrado é retrato, enquanto a orientação natural quando desdobrado é paisagem. Adicionar a flag nosensor força o app a ficar bloqueado no modo retrato quando executado na tela externa e no modo paisagem quando executado na tela interna.

<activity
  android:name=".MainActivity"
  android:screenOrientation="nosensor">

Remapeamento de jogos e sensores de XR

Para jogos e apps de XR, os dados brutos do sensor (como giroscópio ou acelerômetro) são fornecidos no sistema de coordenadas fixo do dispositivo. Se o usuário girar o dispositivo para jogar na horizontal, os eixos do sensor não vão girar com a tela, resultando em controles incorretos.

Para corrigir esse problema, verifique o Display.getRotation() atual e remapeie os eixos de acordo com a rotação:

  • Rotação 0: x=x, y=y
  • Rotação 90: x=-y, y=x
  • Rotação de 180 graus: x=-x, y=-y
  • Rotação de 270: x=y, y=-x

Para vetores de rotação (usados em apps de bússola ou XR), use SensorManager.remapCoordinateSystem() para mapear a direção da lente da câmera ou a parte de cima da tela para os novos eixos com base na rotação atual.

Compatibilidade de apps

Os aplicativos precisam seguir as diretrizes de qualidade para garantir a compatibilidade em todos os formatos e telas conectadas. Se um aplicativo não puder obedecer às diretrizes, os fabricantes de dispositivos poderão implementar tratamentos de compatibilidade, embora isso possa prejudicar a experiência do usuário.

Para mais informações, consulte a lista abrangente de soluções alternativas de compatibilidade fornecidas na plataforma, principalmente aquelas relacionadas a prévia da câmera, substituições e mudanças na API do Android 16 que podem mudar o comportamento do app.

Para saber mais sobre como criar apps adaptáveis, consulte Qualidade de apps para telas grandes.