Suporte de exibição

Confira abaixo as atualizações feitas nessas áreas específicas da Rede de Display:

Redimensionar atividades e telas

Para indicar que um app pode não oferecer suporte ao modo de várias janelas ou ao redimensionamento, atividades usam o atributo resizeableActivity=false. Comum Os problemas encontrados por aplicativos quando as atividades são redimensionadas incluem:

  • Uma atividade pode ter uma configuração diferente do app ou de outra componente não visual. Um erro comum é ler as métricas de exibição do app contexto. Os valores retornados não serão ajustados para as métricas de área visível no qual atividade é exibida.
  • Uma atividade pode não processar o redimensionamento e falhar, mostrar uma interface distorcida, ou perder o estado devido ao reinício sem salvar o estado da instância.
  • Um aplicativo pode tentar usar coordenadas de entrada absolutas (em vez dessas em relação à posição da janela), o que pode interromper a entrada várias janelas.

No Android 7 (e versões mais recentes), é possível configurar um app resizeableActivity=false para executar sempre no modo de tela cheia. Em neste caso, a plataforma impede que atividades não redimensionáveis sejam divididas tela. Se o usuário tentar invocar uma atividade não redimensionável da tela de início enquanto já está no modo de tela dividida, a plataforma sai desse modo e inicia a atividade não redimensionável no modo de tela cheia.

Apps que definem explicitamente esse atributo como false no manifesto não pode ser iniciado no modo de várias janelas, a menos que a compatibilidade for aplicado:

  • A mesma configuração é aplicada ao processo, que contém todas as atividades e não atividade.
  • A configuração aplicada atende aos requisitos do CDD para compatibilidade com apps é exibido.

No Android 10, a plataforma ainda impede atividades não redimensionáveis passem para o modo de tela dividida, mas podem ser escalonado temporariamente se a atividade declarar um aspecto ou uma orientação fixa proporção. Caso contrário, a atividade será redimensionada para preencher toda a tela, como no Android. 9 e inferior.

A implementação padrão aplica a seguinte política:

Quando uma atividade declarada como incompatível com o modo de várias janelas por o uso do atributo android:resizeableActivity e quando isso de atividade atende a uma das condições descritas abaixo, quando a aplicação configuração de tela deve mudar, a atividade e o processo são salvos com o configuração original, e o usuário tem affordance para reiniciar o processo do app para usar a configuração de tela atualizada.

  • É uma orientação fixa pela aplicação de android:screenOrientation
  • O app tem uma proporção máxima ou mínima padrão por nível de segmentação da API ou declare a proporção explicitamente

Essa figura mostra uma atividade não redimensionável com uma proporção declarada. Ao dobrar o dispositivo, a janela é reduzida para se ajustar à área, enquanto mantendo a proporção com o efeito letterbox adequado. Além disso, um será fornecida ao usuário sempre que a área de exibição do a atividade for alterada.

Ao desdobrar o dispositivo, a configuração, o tamanho e a proporção do atividade não mudam, mas a opção de reiniciar a atividade é exibida.

Quando resizeableActivity não estiver definido (ou estiver definido como true), o app é totalmente compatível com redimensionamento.

Implementação

Uma atividade não redimensionável com orientação ou proporção fixa é chamada Modo de compatibilidade de tamanho (SCM) no código. A condição é definida em ActivityRecord#shouldUseSizeCompatMode(): Quando uma atividade do SCM é for iniciado, a configuração relacionada à tela (como tamanho ou densidade) será fixa na configuração de substituição solicitada, para que a atividade não seja mais dependente na configuração de tela atual.

Se a atividade do SCM não puder preencher toda a tela, ela será alinhada na parte superior e centralizada horizontalmente. Os limites de atividade são calculados AppWindowToken#calculateCompatBoundsTransformation():

Quando uma atividade do SCM usa uma configuração de tela diferente da contêiner (por exemplo, a tela é redimensionada ou a atividade é movida para outro display), ActivityRecord#inSizeCompatMode() é verdadeiro e SizeCompatModeActivityController (na interface do sistema) recebe o para mostrar o botão de reinicialização do processo.

Tamanhos e proporções de exibição

O Android 10 oferece suporte a novas proporções desde altas proporções de telas longas e finas para proporções de 1:1. Os apps podem definir ApplicationInfo#maxAspectRatio e os ApplicationInfo#minAspectRatio da tela em que ser capaz de lidar.

proporções de apps no Android 10

Figura 1. Exemplos de proporções de apps com suporte no Android 10

As implementações de dispositivos podem ter telas secundárias com tamanhos e resoluções menores do que as exigidas pelo Android 9 e anteriores (mínimo de 2.5 polegadas de largura ou altura, mínimo de 320 DP para smallestScreenWidth), mas apenas atividades que sejam compatíveis com essas telas pequenas podem ser posicionadas ali.

Os aplicativos podem aceitar declarando um tamanho mínimo compatível menor que ou igual ao tamanho de exibição de destino. Use as APIs android:minHeight e Atributos de layout da atividade android:minWidth no AndroidManifest para fazer isso.

Políticas de display

O Android 10 separa e move algumas telas políticas da implementação padrão de WindowManagerPolicy no PhoneWindowManager para classes por tela, como:

  • Estado e rotação da tela
  • Algumas teclas e rastreamento de eventos de movimento
  • Interface do sistema e janelas de decoração

No Android 9 e versões anteriores, a classe PhoneWindowManager processava políticas de exibição, estado e configurações, rotação, frame de janela decorativa e muito mais. O Android 10 move a maior parte disso para a classe DisplayPolicy, exceto para rastreamento de rotação, que tem foi movido para DisplayRotation.

Configurações da janela de exibição

No Android 10, a configuração por tela configuração de janelamento foi expandida para incluir:

  • Modo de janelamento de exibição padrão
  • Valores de overscan
  • Rotação do usuário e modo de rotação
  • Modo de tamanho, densidade e dimensionamento forçados
  • Modo de remoção de conteúdo (quando a tela é removida)
  • Suporte a decorações do sistema e IME

A classe DisplayWindowSettings contém configurações para estas . Eles são mantidos no disco da partição /data da display_settings.xml sempre que uma configuração for alterada. Para detalhes, consulte DisplayWindowSettings.AtomicFileStorage e DisplayWindowSettings#writeSettings(). Os fabricantes de dispositivos podem fornecer valores padrão em display_settings.xml para o dispositivo configuração do Terraform. No entanto, como o arquivo está armazenado em /data, lógica adicional pode ser necessária para restaurar o arquivo se ele for apagado por uma exclusão permanente.

Por padrão, o Android 10 usa DisplayInfo#uniqueId como um identificador para uma tela ao persistir nas configurações. uniqueId deve ser preenchido em todas as telas. Em Além disso, ele é estável para telas físicas e de rede. Também é possível usar a porta de uma tela física como identificador, que pode ser definido em DisplayWindowSettings#mIdentifier: A cada gravação, todas as configurações são gravadas, para que seja seguro atualizar a chave usada para uma entrada de exibição armazenamento. Para mais detalhes, consulte Identificadores de exibição estáticos.

As configurações são mantidas no diretório /data para fins de histórico motivos. Originalmente, eles eram usados para manter configurações definidas pelo usuário, como rotação da tela.

Identificadores de exibição estáticos

O Android 9 (e versões anteriores) não fornecia identificadores estáveis para telas no de análise de dados em nuvem. Quando uma tela foi adicionada ao sistema, Display#mDisplayId ou DisplayInfo#displayId eram gerada para essa tela, incrementando um contador estático. Se o sistema e removermos a mesma tela, resultou em um ID diferente.

Se um dispositivo tiver várias telas disponíveis na inicialização, elas poderão ser recebe identificadores diferentes, dependendo do tempo. Enquanto o Android 9 (e antes) incluía DisplayInfo#uniqueId, não tinha informações para diferenciar as telas porque as telas físicas eram identificados como local:0 ou local:1, para representar e o monitor integrado e o externo.

O Android 10 muda a DisplayInfo#uniqueId para adicionar um identificador estável e diferenciar entre ambientes locais, exibições virtuais.

Tipo de exibição Formato
Local
local:<stable-id>
Rede
network:<mac-address>
Virtual
virtual:<package-name-and-name>

Além das atualizações no uniqueId, DisplayInfo.address contém DisplayAddress, um identificador de exibição estável durante as reinicializações. No Android 10, DisplayAddress oferece suporte a imagens e telas de rede. DisplayAddress.Physical contém uma versão estável ID de exibição (igual ao uniqueId) e pode ser criada com DisplayAddress#fromPhysicalDisplayId()

O Android 10 também oferece um método conveniente para receber informações da porta (Physical#getPort()). Esse método pode ser usado o framework para identificar telas estaticamente. Por exemplo, ele é usado em DisplayWindowSettings). DisplayAddress.Network contém o endereço MAC e pode ser criado com DisplayAddress#fromMacAddress()

Essas adições permitem que os fabricantes de dispositivos identifiquem telas em imagens estáticas configurações de várias telas e para definir diferentes configurações e recursos do sistema usando identificadores de exibição estáticos, como portas para telas físicas. Esses estão ocultos e devem ser usados somente dentro de system_server:

Com um ID de tela HWC (que pode ser opaco e nem sempre estável), esse retorna o número da porta de 8 bits (específico da plataforma) que identifica uma conector físico para saída de exibição, bem como o blob EDID da tela. O SurfaceFlinger extrai informações do fabricante ou do modelo do EDID para gerar os IDs de exibição estáveis de 64 bits expostos ao framework. Se esse método não for compatível ou ocorrer erros, o SurfaceFlinger voltará para o modo MD legado, em que DisplayInfo#address é nulo e DisplayInfo#uniqueId está codificado, conforme descrito acima.

Para verificar se esse recurso é compatível, execute:

$ dumpsys SurfaceFlinger --display-id
# Example output.
Display 21691504607621632 (HWC display 0): port=0 pnpId=SHP displayName="LQ123P1JX32"
Display 9834494747159041 (HWC display 2): port=1 pnpId=HWP displayName="HP Z24i"
Display 1886279400700944 (HWC display 1): port=2 pnpId=AUS displayName="ASUS MB16AP"

Usar mais de duas telas

No Android 9 (e versões anteriores), o SurfaceFlinger e o DisplayManagerService presumiu a existência de no máximo duas telas físicas com IDs codificados como 0 e 1.

A partir do Android 10, o SurfaceFlinger poderia aproveitar uma API Hardware Composer (HWC) para gerar IDs de exibição estáveis, o que permite gerenciar um número arbitrário de telas físicas. Para saber mais, consulte Identificadores de exibição estáticos.

O framework pode procurar o token IBinder de um endereço físico exibidas por SurfaceControl#getPhysicalDisplayToken após a obtenção o ID de tela de 64 bits de SurfaceControl#getPhysicalDisplayIds ou de um evento de hotplug DisplayEventReceiver.

No Android 10 (e versões anteriores), a tela interna principal é TYPE_INTERNAL e todas as telas secundárias estão sinalizadas como TYPE_EXTERNAL independentemente do tipo de conexão. Portanto, telas internas adicionais são tratadas como externas. Como solução alternativa, o código específico do dispositivo pode fazer suposições sobre DisplayAddress.Physical#getPort se o HWC for conhecido e a alocação da porta é previsível.

Essa limitação foi removida no Android 11 (e versões mais recentes).

  • No Android 11, a primeira tela relatada durante a inicialização é a tela principal. O tipo de conexão (interna ou externa) é irrelevante. No entanto, ainda é verdade que a tela principal não pode ser desconectada e segue esse ele deve, na prática, ser uma tela interna. Alguns smartphones dobráveis têm várias telas internas.
  • As telas secundárias estão categorizadas corretamente como Display.TYPE_INTERNAL ou Display.TYPE_EXTERNAL (anteriormente conhecido como Display.TYPE_BUILT_IN e Display.TYPE_HDMI, respectivamente), dependendo do tipo de conexão.
.

Implementação

No Android 9 e versões anteriores, as telas são identificadas por IDs de 32 bits, em que 0 é a tela interna, 1 é a tela externa, [2, INT32_MAX] são telas virtuais HWC, e -1 representa uma tela inválida ou não HWC.

No Android 10 e versões mais recentes, as telas têm versões estáveis e IDs persistentes, que permitem o SurfaceFlinger e o DisplayManagerService para rastrear mais de duas telas e reconhecer telas já vistas. Se o dispositivo HWC oferece suporte a IComposerClient.getDisplayIdentificationData e fornece de identificação, o SurfaceFlinger analisa a estrutura EDID e aloca os dados IDs de exibição de 64 bits para telas físicas e virtuais de HWC. Os IDs são expressos usando um tipo de opção, em que o valor nulo representa uma tela inválida ou uma veiculação exibição. Sem suporte a HWC, o SurfaceFlinger retorna ao comportamento legado com pelo menos na maioria das duas telas físicas.

Foco por tela

Para oferecer suporte a várias origens de entrada que segmentam telas individuais ao mesmo momento, o Android 10 pode ser configurado para oferecer suporte a vários janelas em foco, no máximo uma por tela. Isso é destinado apenas a usuários tipos de dispositivos quando vários usuários interagem com o mesmo dispositivo ao mesmo tempo, tempo e usar diferentes métodos ou dispositivos de entrada, como o Android Automotivo.

É altamente recomendável que esse recurso não esteja ativado para dispositivos comuns, incluindo dispositivos multitelas ou aqueles usados para desktops experiências Isso ocorre principalmente devido a uma preocupação com a segurança que pode fazer com que os usuários para saber qual janela tem o foco de entrada.

Imagine o usuário que insere informações seguras em um campo de entrada de texto, talvez fazendo login em um app bancário ou digitando texto que contenha dados confidenciais informações imprecisas ou inadequadas. Um aplicativo malicioso pode criar uma exibição virtual fora da tela com onde executar uma atividade, também com um campo de entrada de texto. Legítimos e atividades maliciosas têm foco e exibem um indicador de entrada ativo (cursor piscando).

No entanto, como a entrada de um teclado (hardware ou software) é inserida apenas a atividade principal (o aplicativo que foi lançado mais recentemente), por criando uma tela virtual escondida, um aplicativo malicioso pode captar a entrada do usuário, mesmo ao usar um teclado de software na tela principal do dispositivo.

Usar o com.android.internal.R.bool.config_perDisplayFocusEnabled para definir o foco por tela.

Compatibilidade

Problema:no Android 9 e versões anteriores, no máximo uma janela no tem foco de cada vez.

Solução: no caso raro em que duas janelas do mesmo processo seria focado, o sistema fornece foco apenas para a janela que está mais acima na ordem Z. Essa restrição foi removida para apps que segmentam A partir do Android 10, espera-se que eles possam oferecem suporte a várias janelas sendo focadas simultaneamente.

Implementação

WindowManagerService#mPerDisplayFocusEnabled controla o disponibilidade desse recurso. Em ActivityManager, ActivityDisplay#getFocusedStack() agora é usado em vez de global o rastreamento em uma variável. ActivityDisplay#getFocusedStack() determina o foco com base na ordem Z em vez de armazenar o valor em cache. Isso é para que apenas uma origem, a WindowManager, precisa rastrear a ordem Z das atividades.

ActivityStackSupervisor#getTopDisplayFocusedStack() faz uma abordagem semelhante nos casos em que a pilha mais focada no sistema precisam ser identificados. As pilhas são percorridas de cima para baixo, buscando para a primeira pilha qualificada.

O app InputDispatcher agora pode ter várias janelas em foco (uma por tela). Se um evento de entrada for específico da tela, ele será despachado para a janela em foco na tela correspondente. Caso contrário, será enviado para a janela em foco na tela em foco, que é a tela que o usuário tenha interagido mais recentemente.

Consulte InputDispatcher::mFocusedWindowHandlesByDisplay e InputDispatcher::setFocusedDisplay(). Os apps focados também são atualizados. separadamente em InputManagerService por meio de NativeInputManager::setFocusedApplication():

No WindowManager, as janelas em foco também são rastreadas separadamente. Consulte DisplayContent#mCurrentFocus e DisplayContent#mFocusedApp e os respectivos usos. Foco relacionado os métodos de rastreamento e atualização foram movidos WindowManagerService para DisplayContent.