Desfoque de janela

No Android 12, as APIs públicas estão disponíveis para implementar efeitos de desfoque de janela (como desfoque de fundo e desfoque por trás). Observe que, embora você possa ver o desfoque da janela também chamado de desfoque entre janelas no código, na documentação do desenvolvedor ou na notação da interface do usuário, o desfoque entre janelas é a mesma coisa que o desfoque da janela.

Com essas APIs, você pode desfocar o que estiver atrás de sua própria janela. Você pode criar janelas com fundos desfocados, criando um efeito de vidro fosco, ou mostrar janelas com a tela inteira atrás delas desfocadas, criando um efeito de profundidade de campo. Você também pode combinar os dois efeitos.

apenas desfoque de fundo

1

borrão atrás apenas

2

atrás e desfoque de fundo

3

Figura 1. Apenas desfoque de fundo (1), desfoque apenas atrás (2), desfoque de fundo e desfoque atrás (3)

O recurso de desfoque de janela funciona em todas as janelas, o que significa que também funciona quando há outro aplicativo atrás da janela que você está visualizando. Isso não é o mesmo que um efeito de renderização de desfoque , que desfoca o conteúdo dentro de uma janela no mesmo aplicativo. Os desfoques de janela são úteis para diálogos e folhas inferiores e outras janelas flutuantes.

É importante observar que esse recurso usa recursos de GPU significativos. Portanto, embora esteja disponível para todos os dispositivos Android, ele só é compatível com os dispositivos que possuem potência de GPU suficiente.

Implementação

OEMs e parceiros

Os desfoques de janela são desabilitados por padrão. Para habilitar a funcionalidade de desfoque nos dispositivos, faça o seguinte:

  • Certifique-se de que o dispositivo pode lidar com a carga extra da GPU - a operação de desfoque é cara e em dispositivos de baixo custo, pode causar queda de quadros. Ative isso apenas em dispositivos com potência de GPU suficiente.
  • Certifique-se de que seu librenderengine implemente a lógica de desfoque - o mecanismo de renderização padrão do Android 12 faz, mas qualquer mecanismo de renderização personalizado deve implementar a própria lógica de desfoque.
  • Habilite desfoques definindo o seguinte sysprop de defletor de superfície:
# enable surface flinger window blurs
PRODUCT_PROPERTY_OVERRIDES += \
       ro.surface_flinger.supports_background_blur=1

Desenvolvedores de terceiros

Consulte a seção Exemplos e Fonte para ver o código de exemplo. Desfoque de janela pode ser desabilitado em tempo de execução pelo servidor do sistema. Portanto, um aplicativo deve fornecer uma versão substituta e sem borrões. Caso contrário, se os desfoques não forem renderizados porque foram desabilitados, o plano de fundo da janela poderá ficar tão transparente que o conteúdo dentro da janela se tornará ilegível. Se seu aplicativo não fornecer uma versão de aplicativo substituto, verifique se a interface do usuário funciona com desfoques ativados e desativados. Estas são as três condições sob as quais os desfoques podem ser desativados a qualquer momento:

  1. O dispositivo está executando o Android 11 ou inferior. Como os desfoques da janela estão disponíveis apenas em dispositivos Android 12 e superior, os aplicativos devem implementar uma alternativa de experiência de fallback e sem desfoque para dispositivos que executam o Android 11 e inferior.
  2. O dispositivo não oferece suporte a desfoques de janela porque são caros, portanto, os dispositivos de baixo custo podem perder quadros ao renderizá-los. Para esses casos, os aplicativos devem fornecer uma experiência de fallback sem borrões.
  3. O servidor do sistema (por exemplo, durante o modo de economia de bateria ou devido a uma configuração do desenvolvedor ou modo de túnel) desabilita o desfoque em tempo de execução.

Os pontos 2 e 3 acima são relatados por um ouvinte registrado com WindowManager.addCrossWindowBlurEnabledListener . Se seus aplicativos usarem as APIs de desfoque, registre esse ouvinte e atualize sua interface do usuário sempre que o ouvinte for chamado, se você quiser usar uma interface do usuário diferente para os estados habilitado para desfoque e desabilitado para desfoque. Quando é registrado, o ouvinte é chamado imediatamente para informar se os desfoques estão ativados no momento.

Implemente as funcionalidades de desfoque usando os seguintes métodos:

Exemplos e fonte

public class BlurActivity extends Activity {
   private final int mBackgroundBlurRadius = 150;
   private final Drawable mBackgroundDrawableWithBlur;
   private final Drawable mBackgroundDrawableNoBlur;

   private final int mBlurBehindRadius = 50;
   private final float mDimAmountWithBlur = 0.1f;
   private final float mDimAmountNoBlur = 0.6f;


   private Consumer<Boolean> mCrossWindowBlurEnabledListener = enabled -> {
       getWindow().setBackgroundDrawable(
               enabled ? mBackgroundDrawableWithBlur : mBackgroundDrawableNoBlur);
       getWindow().setDimAmount(enabled ? mDimAmountWithBlur : mDimAmountNoBlur);
   };

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.blur_activity);

       mBackgroundDrawableWithBlur = getContext().getResources().getDrawable(
               R.drawable.window_background_with_blur);
       mBackgroundDrawableNoBlur = getContext().getResources().getDrawable(
               R.drawable.window_background_no_blur);

       if (Android version >= Android S) {
           getWindow().addFlags(
                   WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
           window.getAttributes().setBlurBehindRadius(mBlurBehindRadius);
           window.setBackgroundBlurRadius(mBackgroundBlurRadius);
           getWindow().getDecorView().addOnAttachStateChangeListener(
                                         new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                                     blurEnabledListener);
                    }

                       @Override
                   public void onViewDetachedFromWindow(View v) {
                       getWindowManager().removeCrossWindowBlurEnabledListener(
                                                      blurEnabledListener);
                     }
           });
       }
       getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
   }

Ativar e desativar o desfoque da janela

Há duas maneiras de permitir e não permitir desfoques de janela.

  1. Da interface do usuário:

    Configurações -> Sistema -> Opções do desenvolvedor -> Renderização acelerada por hardware -> Permitir desfoques no nível da janela

  2. Do terminal (o dispositivo deve estar enraizado):

adb shell wm disable-blur 1 # 1 disables window blurs, 0 allows them

Você só pode ativar ou desativar a funcionalidade de desfoque da janela se o seu dispositivo tiver a capacidade de suportar desfoques. (Dispositivos que não suportam desfoques de janela não podem habilitar o recurso.) Por padrão, os desfoques são habilitados em dispositivos que os suportam.

Ao habilitar desfoques para seus dispositivos, considere que outras coisas, como modo de economia de bateria ou encapsulamento multimídia, podem desativá-los. Os borrões são ativados quando todas as condições necessárias são atendidas – eles são suportados e nada os desativa. Para ver se o estado atual da funcionalidade de desfoque está "ativado", use o comando adb shell wm disable-blur .

Validação

Para garantir que sua versão dos recursos de desfoque funcione como você pretendia, implemente a lógica da interface do usuário para que ela redesenhe os elementos da interface do usuário sempre que blurEnabled for alterado (conforme relatado por addCrossWindowBlurEnabledListener ).

  1. Abra a interface do usuário que tem desfoque.
  2. Use as etapas fornecidas para Ativar e desativar o desfoque da janela na interface do usuário ou pela CLI.
  3. Verifique se a interface do usuário muda de e para uma sem desfoque conforme o esperado.

Solução de problemas

Use o seguinte como um guia para solução de problemas durante a validação.

Nenhum desfoque desenhado

  • Verifique se os desfoques estão ativados no momento (e se seu hardware os suporta) usando a CLI ou navegando até Configurações .

    1. Use o comando adb shell wm disable-blur , que imprime se os desfoques são suportados nesse dispositivo e se estão ativados no momento.
    2. Navegue até Configurações -> Sistema -> Opções do desenvolvedor -> Renderização acelerada por hardware -> Permitir desfoques no nível da janela . Se você não encontrar a opção lá, os desfoques não são compatíveis com seu dispositivo.
  • Certifique-se de definir uma cor de fundo de janela translúcida; uma cor de fundo de janela opaca oculta (cobre) a área desfocada.

O dispositivo de teste não suporta desfoque de janela

  • Teste seu aplicativo no emulador do Android 12. Para configurar um emulador Android, consulte as instruções Configurar um emulador Android . Qualquer dispositivo virtual Android que você criar com o emulador suportará a desfocagem da janela.

Sem cantos arredondados

  • Defina os cantos arredondados definindo um desenhável de fundo de janela - Window#setBackgroundDrawable . Isso determina o contorno da área de desfoque.

Atualizar a opção do desenvolvedor não permite desfoques

  • Verifique se o dispositivo está no modo de economia de bateria, se está usando encapsulamento multimídia (para TV) ou se outra coisa está desativando a funcionalidade de desfoque.

Desfoque de fundo desenhado em tela cheia, fora dos limites da janela

  • Certifique-se de que sua janela esteja marcada como flutuante - android:windowIsFloating
  • Certifique-se de ter definido um desenhável de fundo de janela - Window#setBackgroundDrawable . Isso determina o contorno da área de desfoque.

As atualizações do ouvinte não são aplicadas na tela

  • Verifique se a janela está sendo destruída e recriada enquanto a instância que está sendo operada pelo ouvinte não é atualizada. As atualizações do ouvinte podem estar sendo aplicadas a uma instância de janela antiga.