Como gerenciar janelas

O ChromeOS oferece suporte a apps Android em várias janelas. O sistema renderiza apps em contêineres de janela cujo tamanho é determinado pelo formato do dispositivo, como mostrado na Figura 1.

Figura 1. Uma janela de app em diferentes dispositivos.

É importante projetar layouts que funcionem com diferentes tamanhos de tela. Se você seguir as diretrizes do Android para oferecer suporte a diferentes tamanhos de tela, seu app também vai funcionar bem ao ser executado no ChromeOS.

Esta página mostra como garantir que a janela do app seja iniciada corretamente, seja redimensionada com facilidade e exiba todo o conteúdo quando o tamanho mudar.

Tamanho inicial de inicialização

Os apps podem solicitar o tamanho inicial da inicialização das seguintes maneiras:

  • Use um tamanho de inicialização somente em ambientes de área de trabalho. Isso ajuda o gerenciador de janelas a informar os limites e a orientação corretos. Para indicar uma preferência usada no modo de área de trabalho, adicione as seguintes metatags na <activity>:
<meta-data android:name="WindowManagerPreference:FreeformWindowSize"
           android:value="[phone|tablet|maximize]" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation"
           android:value="[portrait|landscape]" />
  • Use limites de inicialização estáticos. Use <layout> dentro da entrada de manifesto da atividade para especificar um tamanho inicial "fixo", como no exemplo abaixo:
<layout android:defaultHeight="500dp"
            android:defaultWidth="600dp"
            android:gravity="top|end"
            android:minHeight="450dp"
            android:minWidth="300dp" />
  • Use limites de inicialização dinâmicos. Uma atividade pode criar e usar ActivityOptions.setLaunchBounds(Rect) ao criar uma nova atividade. Ao especificar um retângulo vazio, seu app pode ser maximizado.

Redimensionar janelas

No ChromeOS, os usuários podem redimensionar a janela de um app da maneira normal: arrastando o canto inferior direito, conforme mostrado na Figura 2.

Figura 2. Uma janela redimensionável do app.

Há duas opções para processar o redimensionamento de janela ao usar a classe View:

  • Responda a mudanças de configuração dinamicamente chamando onConfigurationChanged(..). Por exemplo, você pode adicionar android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" ao manifesto da atividade. Para mais informações sobre como processar mudanças de configuração, leia Gerenciar mudanças de configuração.
  • Deixar o sistema reiniciar a atividade. Nesse caso, implemente onSaveInstanceState e use o componente de arquitetura ViewModel para restaurar o estado salvo anterior.

Ao usar o Jetpack Compose, o comportamento de redimensionamento depende de como sua atividade está configurada. Se ele processar as mudanças dinamicamente, uma recomposição será acionada quando o tamanho da janela mudar. Se a atividade for reiniciada pelo sistema, uma composição inicial vai ocorrer após a reinicialização. De qualquer maneira, é importante criar layouts do Compose que se adaptem às mudanças de tamanho da janela. Não presuma tamanhos fixos.

Dimensões da janela

Faça com que suas atividades leiam as dimensões da janela sempre que iniciarem e organizem o conteúdo de acordo com a configuração atual.

Para determinar a configuração atual, chame getResources().getConfiguration() na atividade atual. Não use a configuração da atividade em segundo plano ou do recurso do sistema. A atividade em segundo plano não tem um tamanho, e a configuração do sistema pode conter várias janelas com tamanhos e orientações conflitantes. Portanto, nenhum dado utilizável pode ser extraído.

Os tamanhos da janela e da tela não são iguais. Para ver o tamanho da janela no DP, use Activity.getResources().getConfiguration().screenWidth e Activity.getResources().getConfiguration().screenHeight. Você provavelmente nunca precisará usar o tamanho da tela.

Limites de conteúdo

Os limites de conteúdo de uma janela podem mudar após o redimensionamento. Por exemplo, a área dentro da janela usada pelo app pode mudar se a janela ficar grande demais para caber na tela. Siga as seguintes diretrizes:

  • Os apps que usam o processo de layout do Android são automaticamente dispostos no espaço disponível.
  • Os apps nativos precisam ler a área disponível e monitorar as mudanças de tamanho para evitar ter elementos de interface inacessíveis. Chame os métodos a seguir para determinar o tamanho inicial disponível para essa superfície:

    • NativeActivity.mLastContent[X/Y/Width/Height]()
    • findViewById(android.R.id.content).get[Width/Height]()

    O monitoramento contínuo pode ser feito usando um observador:

    • NativeActivity.onContentRectChangedNative()
    • NativeActivity.onGlobalLayout()
    • Adicionar um listener a view.addOnLayoutChangeListener(findViewById(android.R.id.content))

    Se o app estiver pré-dimensionando a arte, faça isso sempre que a resolução mudar.

Redimensionamento em formato livre

O ChromeOS permite que qualquer janela seja redimensionada livremente: o usuário pode mudar a largura, a altura e a posição de uma janela na tela. Muitos apps para Android são criados sem o redimensionamento livre. Considere estes problemas:

  • A posição da tela pode mudar. Sempre use o sistema para realizar transformações de coordenadas de janela para tela e de tela para janela.
  • Se você estiver usando o sistema de visualização do Android, o layout da janela mudará automaticamente com uma mudança de tamanho.
  • Se você não usa o sistema de visualização e controla a superfície, seu app precisa processar as mudanças de tamanho por conta própria.
  • Para aplicativos nativos, use os membros mLastContent ou a visualização de conteúdo para determinar o tamanho inicial.
  • Quando o app estiver em execução, detecte eventos onContentRectChangedNative ou onGlobalLayout para reagir a mudanças de tamanho.
  • Quando o tamanho do app mudar, redimensione ou recarregue layouts e artes e atualize as áreas de entrada.

Modo de tela cheia

O modo de tela cheia funciona da mesma forma que no Android. Se a janela não estiver cobrindo a tela inteira, as solicitações de tela cheia (ocultando todos os elementos da interface do sistema) serão ignoradas. Quando o app for maximizado os métodos normais de tela cheia, layouts e funções serão executados. Isso ocultará os elementos da IU do sistema (barra de controle da janela e a estante).

Orientação da tela

A orientação mais comum de um app para Android é retrato, porque é assim que a maioria dos smartphones é usada. Embora a orientação retrato seja indicada para smartphones, não é adequada para laptops e tablets, em que é preferível a orientação paisagem. Para ter os melhores resultados para seu app, ofereça suporte para as duas orientações.

Alguns apps Android presumem que, quando um dispositivo é mantido no modo retrato, o valor da rotação é Surface.ROTATION_0. Isso pode acontecer na maioria dos dispositivos Android. No entanto, quando o app está em um determinado modo ARC, o valor de rotação para a orientação retrato pode não ser Surface.ROTATION_0.

Para ter um valor de rotação preciso ao ler o acelerômetro ou sensores semelhantes, use o método Display.getRotation() e troque o eixo corretamente.

A atividade raiz e a orientação

Uma janela do Chromebook consiste em uma pilha de janelas de atividade. Todas as janelas da pilha têm o mesmo tamanho e orientação.

Mudanças repentinas de orientação e tamanho são confusas em um ambiente de área de trabalho. O gerenciador de janelas do Chromebook evita isso de maneira semelhante ao modo lado a lado do Android: a atividade na parte de baixo da pilha controla os atributos de todas as atividades acima dela. Isso pode levar a situações inesperadas em que uma atividade recém-iniciada que é retrato e não redimensionável se torna paisagem e redimensionável.

O modo de dispositivo tem efeito aqui: no modo tablet, a orientação não é bloqueada e cada janela preserva a própria orientação, como é normal no Android.

Diretrizes de orientação

Siga estas diretrizes para gerenciar a orientação:

  • Se você oferecer compatibilidade a apenas um modo, adicione as informações ao manifesto para que o gerenciador de janelas saiba disso antes de iniciar o aplicativo. Ao especificar a orientação, especifique também as orientações do sensor, quando possível. Os Chromebooks geralmente são conversíveis, e um app de cabeça para baixo é uma experiência ruim para o usuário.
  • Tente manter uma única orientação selecionada. Evite solicitar uma orientação no manifesto e definir outra programaticamente mais tarde.
  • Tenha cuidado ao mudar a orientação com base no tamanho da janela. O usuário pode ficar preso em uma pequena janela de retrato e não conseguir retornar a uma janela de paisagem maior.
  • Há controles de janela no Chrome para alternar entre todos os layouts disponíveis. Ao escolher a opção de orientação correta, você garante que o usuário tenha o layout certo depois de iniciar o app. Se um app estiver disponível nas orientações de retrato e paisagem, use o padrão de paisagem, se possível. Depois de definida, essa opção será memorizada em cada app.
  • Evite mudanças de orientação desnecessárias. Por exemplo, se a orientação da atividade for retrato, mas o app chamar setRequestedOrientation(LANDSCAPE) durante a execução, isso causará redimensionamento desnecessário da janela, o que é chato para o usuário e pode reiniciar o app, já que ele não consegue processar essa ação. É melhor definir a orientação uma vez, por exemplo, no manifesto e mudá-la se necessário.

Outras considerações

Confira outras coisas a serem consideradas ao trabalhar com apps Android no ChromeOS:

  • Não chame finish() no método onDestroy da sua atividade. Isso faz com que o app seja fechado após o redimensionamento e não seja reiniciado.
  • Não use tipos de janela incompatíveis, como TYPE_KEYGUARD e TYPE_APPLICATION_MEDIA.
  • Agilize as reinicializações da atividade armazenando em cache objetos alocados anteriormente.
  • Se você não quiser que o usuário redimensione o app, especifique android:resizeableActivity=false no arquivo de manifesto.
  • Teste o app para garantir que ele processe corretamente as mudanças no tamanho da janela.