Confira abaixo as atualizações feitas nessas áreas específicas de exibição:
Decorações do sistema
O Android 10 adiciona suporte para configurar telas secundárias para mostrar determinadas decorações do sistema, como plano de fundo, barra de navegação e tela de início. Por padrão, a tela principal mostra todas as decorações do sistema, e as telas secundárias mostram as que estão ativadas. O suporte a um editor de método de entrada (IME) pode ser definido separadamente de outras decorações do sistema.
Use DisplayWindowSettings#setShouldShowSystemDecorsLocked()
para adicionar suporte a decorações do sistema em uma tela específica ou fornecer
um valor padrão em /data/system/display_settings.xml
. Para conferir exemplos,
consulte Mostrar as configurações da janela.
Implementação
O DisplayWindowSettings#setShouldShowSystemDecorsLocked()
também é exposto em
WindowManager#setShouldShowSystemDecors()
para testes. Acionar esse método
com a intenção de ativar decorações do sistema não adiciona janelas de decoração que estavam
ausentes anteriormente nem as remove se elas estavam presentes. Na maioria
dos casos, a mudança no suporte a decorações do sistema só entra em vigor após a
reinicialização do dispositivo.
As verificações de suporte a decorações do sistema na base de código da WindowManager
geralmente passam por DisplayContent#supportsSystemDecorations()
, enquanto
as verificações de serviços externos (como a interface do sistema para conferir se a barra de navegação
precisa ser mostrada) usam WindowManager#shouldShowSystemDecors()
.
Para entender o que é controlado por essa configuração, explore os pontos de chamada desses
métodos.
Janelas de decoração da IU do sistema
O Android 10 adiciona suporte a janelas de decoração do sistema
apenas para a barra de navegação, porque ela é essencial
para navegar entre atividades e apps. Por padrão, a barra de navegação mostra
as affordances "Voltar" e "Página inicial". Essa inclusão só será incluída se a tela de destino oferecer suporte
a decorações do sistema (consulte DisplayWindowSettings
).
A barra de status é uma janela do sistema mais complicada, porque também contém a aba de notificações, as configurações rápidas e a tela de bloqueio. No Android 10, a barra de status não tem suporte para telas secundárias. Portanto, as notificações, as configurações e a proteção de teclado completa estão disponíveis apenas na tela principal.
A janela do sistema Visão geral/Recentes não tem suporte em telas secundárias. No Android 10, o AOSP só mostra Recents na tela padrão e contém atividades de todas as telas. Quando iniciada a partir de "Recentes", uma atividade que estava em uma tela secundária é mostrada na parte frontal dessa tela por padrão. Essa abordagem tem alguns problemas conhecidos, como não atualizar imediatamente quando os apps aparecem em outras telas.
Implementação
Para implementar outros recursos da IU do sistema, os fabricantes de dispositivos precisam usar um único componente da IU do sistema que detecta a adição/remoção de telas e apresenta o conteúdo apropriado.
Um componente da IU do sistema que oferece suporte a várias telas (MD, na sigla em inglês) precisa processar os seguintes casos:
- Inicialização de várias telas na inicialização
- Tela adicionada durante a execução
- Tela removida no momento da execução
Quando a interface do sistema detecta a adição de uma tela antes da WindowManager, ela cria
uma condição de corrida. Isso pode ser evitado implementando um callback personalizado do
WindowManager para a interface do sistema quando uma tela é adicionada em vez de se inscrever em
eventos DisplayManager.DisplayListener
. Para uma implementação de referência,
consulte CommandQueue.Callbacks#onDisplayReady
para suporte à barra de navegação
e WallpaperManagerInternal#onDisplayReady
para papéis de parede.
Além disso, o Android 10 oferece estas atualizações:
- A classe
NavigationBarController
controla todas as funcionalidades específicas para barras de navegação. - Para conferir uma barra de navegação personalizada, consulte
CarStatusBar
. TYPE_NAVIGATION_BAR
não está mais restrito a uma única instância e pode ser usado por tela.IWindowManager#hasNavigationBar()
foi atualizado para incluir o parâmetrodisplayId
apenas para a interface do sistema.
Tela de início
No Android 10, cada tela configurada para oferecer suporte
a decorações do sistema tem uma pilha inicial dedicada para atividades da tela de início com o tipo
WindowConfiguration#ACTIVITY_TYPE_HOME
, por padrão. Cada tela
usa uma instância separada da atividade do iniciador.
Figura 1. Exemplo de inicializador de várias telas para
platform/development/samples/MultiDisplay
A maioria das telas de início atuais não oferece suporte a várias instâncias e não é otimizada
para tamanhos de tela grandes. Além disso, um tipo diferente de experiência é esperado
em telas secundárias/externas. Para fornecer uma atividade dedicada para telas
secundárias, o Android 10 apresenta a categoria SECONDARY_HOME
em filtros de
intent. As instâncias dessa atividade são usadas em todas as telas compatíveis com decorações
do sistema, uma para cada tela.
<activity> ... <intent-filter> <category android:name="android.intent.category.SECONDARY_HOME" /> ... </intent-filter> </activity>
A atividade precisa ter um modo de inicialização que não impeça várias
instâncias e que possa se adaptar a diferentes tamanhos de tela. O modo de inicialização
não pode ser singleInstance
ou singleTask
.
Implementação
No Android 10, RootActivityContainer#startHomeOnDisplay()
seleciona automaticamente o componente e a intent desejados, dependendo da tela
em que a tela inicial é iniciada. RootActivityContainer#resolveSecondaryHomeActivity()
contém a lógica para procurar o componente de atividade da tela de início, dependendo da tela de início
selecionada no momento, e pode usar o padrão do sistema, se necessário (consulte
ActivityTaskManagerService#getSecondaryHomeIntent()
).
Restrições de segurança
Além das restrições que se aplicam a atividades em telas secundárias, para evitar que um app malicioso crie uma tela virtual com decorações do sistema ativadas e leia informações sensíveis do usuário da plataforma, o iniciador aparece apenas em telas virtuais pertencentes ao sistema. O iniciador não exibe conteúdo em telas virtuais que não são do sistema.
Planos de fundo
No Android 10 (e versões mais recentes), os planos de fundo têm suporte em telas secundárias:
Figura 2. Plano de fundo interativo em telas internas (acima) e externas (abaixo)
Os desenvolvedores podem declarar suporte ao recurso de plano de fundo fornecendo
android:supportsMultipleDisplays="true"
na
definição XML WallpaperInfo
. Os desenvolvedores de plano de fundo também
precisam carregar recursos usando o contexto de exibição em
WallpaperService.Engine#getDisplayContext()
.
O framework cria uma instância de WallpaperService.Engine
por tela, de modo que cada mecanismo tenha a própria superfície e contexto de exibição. O
desenvolvedor precisa garantir que cada mecanismo possa ser renderizado de forma independente, em
taxas de frames diferentes, respeitando a VSYNC.
Selecionar planos de fundo para telas individuais
O Android 10 não oferece suporte direto à plataforma para selecionar planos de fundo
para telas individuais. Para isso, é necessário um identificador de tela estável
para manter as configurações de plano de fundo por tela.
O Display#getDisplayId()
é dinâmico, então não há garantia de que uma
tela física terá o mesmo ID após a reinicialização.
No entanto, o Android 10 adicionou DisplayInfo.mAddress
,
que contém identificadores estáveis para telas físicas e pode ser usado para uma implementação
completa no futuro. Infelizmente, é tarde demais para implementar a lógica
para o Android 10. A solução sugerida:
- Use a API
WallpaperManager
para definir os planos de fundo. WallpaperManager
é obtido de um objetoContext
, e cada objetoContext
tem informações sobre a tela correspondente (Context#getDisplay()/getDisplayId()
). Portanto, é possível extrairdisplayId
de uma instânciaWallpaperManager
sem adicionar novos métodos.- No framework, use
displayId
obtido de um objetoContext
e mapeie-o para um identificador estático (como uma porta de uma tela física). Use o identificador estático para manter o plano de fundo escolhido.
Essa solução alternativa usa implementações atuais para seletores de plano de fundo. Se ele for aberto em uma tela específica e usar o contexto correto, quando ele for chamado para definir um plano de fundo, o sistema poderá identificar automaticamente a tela.
Se for necessário definir o plano de fundo para uma tela que não seja a atual, crie um novo objeto Context
para a tela de destino
(Context#createDisplayContext
) e receba a
instância WallpaperManager
dessa tela.
Restrições de segurança
O sistema não vai mostrar planos de fundo em telas virtuais que não sejam dele. Isso ocorre devido a uma preocupação de segurança de que um app malicioso possa criar uma tela virtual com suporte a decorações do sistema ativadas e ler informações sensíveis do usuário na superfície (como uma foto pessoal).
Implementação
No Android 10, as interfaces IWallpaperConnection#attachEngine()
e IWallpaperService#attach()
aceitam o
parâmetro displayId
para criar conexões por tela.
WallpaperManagerService.DisplayConnector
encapsula um mecanismo de plano de fundo
e uma conexão por tela. No WindowManager, os controladores de plano de fundo são
criados para cada objeto DisplayContent
na construção, em vez de um
único WallpaperController
para todas as telas.
Algumas das implementações de método WallpaperManager
públicas (como
WallpaperManager#getDesiredMinimumWidth()
) foram atualizadas para calcular
e fornecer informações para as exibições correspondentes.
A WallpaperInfo#supportsMultipleDisplays()
e um atributo de recurso
correspondente foram adicionados para que os desenvolvedores de apps possam informar quais
planos de fundo estão prontos para várias telas.
Se o serviço de plano de fundo mostrado na tela padrão não oferecer suporte a várias telas, o sistema mostrará o plano de fundo padrão nas telas secundárias.
Figura 3. Lógica de plano de fundo alternativo para telas secundárias