Sfocature delle finestre

In Android 12, sono disponibili API pubbliche per l'implementazione di effetti di sfocatura della finestra, come la sfocatura dello sfondo e la sfocatura dietro.

Le sfocature delle finestre, o sfocature tra finestre, vengono utilizzate per sfocare lo schermo dietro la finestra specificata. Esistono due tipi di sfocatura della finestra, che possono essere utilizzati per ottenere effetti visivi diversi:

  • Sfocatura dello sfondo ti consente di creare finestre con sfondi sfocati, creando un effetto vetro smerigliato.

  • Sfocatura sfondo ti consente di sfocare l'intero schermo dietro una finestra (di dialogo), creando un effetto di profondità di campo.

I due effetti possono essere utilizzati separatamente o combinati, come mostrato nella figura seguente:

solo sfocatura dello sfondo

a

sfocatura solo dietro

b

sfocatura dietro e sfocatura sfondo

c

Figura 1. Solo sfocatura sfondo (a), solo sfocatura dietro (b), sfocatura sfondo e sfocatura dietro (c)

La funzionalità di sfocatura della finestra funziona su tutte le finestre, il che significa che funziona anche quando c'è un'altra app dietro la finestra. Questo effetto non è lo stesso dell'effetto di rendering sfocato, che sfoca i contenuti all'interno della stessa finestra. Le sfocature delle finestre sono utili per finestre di dialogo, riquadri inferiori e altre finestre mobili.

Implementazione

Sviluppatori di app

Gli sviluppatori di app devono fornire un raggio di sfocatura per creare un effetto sfocato. Il raggio di sfocatura controlla la densità della sfocatura, ovvero più alto è il raggio, più densa è la sfocatura. Una sfocatura di 0 px significa nessuna sfocatura. Per la sfocatura dietro, un raggio di 20 px crea un buon effetto di profondità di campo, mentre un raggio di sfocatura dello sfondo di 80 px crea un buon effetto vetro smerigliato. Evita raggi di sfocatura superiori a 150 px, in quanto ciò influirà in modo significativo sulle prestazioni.

Per ottenere l'effetto sfocatura desiderato e aumentare la leggibilità, scegli un valore del raggio di sfocatura integrato da un livello di colore traslucido.

Sfocatura sfondo

Utilizza la sfocatura dello sfondo nelle finestre mobili per creare un effetto di sfondo della finestra che è un'immagine sfocata dei contenuti sottostanti. Per aggiungere uno sfondo sfocato alla finestra:

  1. Chiama Window#setBackgroundBlurRadius(int) per impostare un raggio di sfocatura dello sfondo. In alternativa, nel tema della finestra, imposta R.attr.windowBackgroundBlurRadius.

  2. Imposta R.attr.windowIsTranslucent su true per rendere la finestra traslucida. La sfocatura viene disegnata sotto la superficie della finestra, quindi la finestra deve essere traslucida per rendere visibile la sfocatura.

  3. (Facoltativo) Chiama Window#setBackgroundDrawableResource(int) per aggiungere un elemento disegnabile di sfondo della finestra rettangolare con un colore traslucido. In alternativa, nel tema della finestra, imposta R.attr.windowBackground.

  4. Per una finestra con angoli arrotondati, determina gli angoli arrotondati per l'area sfocata impostando un ShapeDrawable con angoli arrotondati come drawable dello sfondo della finestra.

  5. Gestisci gli stati di sfocatura attivati e disattivati. Per saperne di più, consulta la sezione Linee guida per l'utilizzo della sfocatura della finestra nelle app.

Sfocatura dietro

La sfocatura dietro sfoca l'intero schermo dietro la finestra. Questo effetto viene utilizzato per attirare l'attenzione dell'utente sui contenuti della finestra sfocando tutto ciò che si trova sullo schermo dietro la finestra.

Per sfocare i contenuti dietro la finestra, segui questi passaggi:

  1. Aggiungi FLAG_BLUR_BEHIND ai flag della finestra per attivare la sfocatura sullo sfondo. In alternativa, nel tema della finestra, imposta R.attr.windowBlurBehindEnabled.

  2. Chiama WindowManager.LayoutParams#setBlurBehindRadius per impostare un raggio di sfocatura posteriore. In alternativa, nel tema della finestra, imposta R.attr.windowBlurBehindRadius.

  3. (Facoltativo) Scegli un importo di attenuazione complementare.

  4. Gestisci gli stati di sfocatura attivati e disattivati. Per saperne di più, consulta la sezione Linee guida per l'utilizzo della sfocatura della finestra nelle app.

Linee guida per l'utilizzo della sfocatura della finestra nelle app

Il supporto della sfocatura delle finestre dipende da quanto segue:

  • Versione di Android: le API di sfocatura delle finestre sono disponibili solo su Android 12 e versioni successive. Controlla l'SDK del dispositivo per la versione di Android.

  • Prestazioni grafiche: i dispositivi con GPU meno performanti potrebbero scegliere di non supportare le sfocature delle finestre.

  • Stato del sistema: il server di sistema potrebbe disattivare temporaneamente le sfocature delle finestre in fase di runtime, ad esempio durante la modalità di risparmio batteria, durante la riproduzione di determinati tipi di contenuti video o a causa di una sostituzione dello sviluppatore.

Per rendere la tua app compatibile con le varie versioni di Android, i dispositivi e gli stati del sistema, segui queste linee guida:

  • Aggiungi un listener tramite WindowManager#addCrossWindowBlurEnabledListener, per ricevere una notifica quando le sfocature della finestra sono attive o disattive. Inoltre, utilizza WindowManager#isCrossWindowBlurEnabled per verificare se le sfocature delle finestre sono attualmente attive.

  • Implementa due versioni per lo sfondo della finestra, per adattarsi allo stato abilitato o disabilitato delle sfocature delle finestre.

    Quando le sfocature sono attivate, lo sfondo della finestra deve essere traslucido per rendere visibile la sfocatura. In questo stato, quando le sfocature vengono disattivate, i contenuti della finestra si sovrappongono direttamente ai contenuti della finestra sottostante, rendendo la finestra sovrapposta meno leggibile. Per evitare questo effetto, quando le sfocature delle finestre sono disattivate, adatta la UI dell'app nel seguente modo:

    • Per la sfocatura dello sfondo, aumenta il valore alfa del drawable dello sfondo della finestra, rendendolo più opaco.

    • Per la sfocatura dello sfondo, aggiungi un livello di oscuramento con un valore di oscuramento più alto.

Esempio di sfocatura dietro e sfocatura dello sfondo

Questa sezione fornisce un esempio pratico di un'attività che utilizza sia la sfocatura dietro che la sfocatura dello sfondo.

Il seguente esempio di MainActivity.java è una finestra di dialogo con una sfocatura dietro un raggio di 20 px e un raggio di sfocatura dello sfondo di 80 px. Ha angoli arrotondati, definiti in XML nel drawable dello sfondo della finestra. Gestisce correttamente diverse versioni di Android, diversi dispositivi (che potenzialmente non supportano le sfocature delle finestre) e modifiche all'attivazione o alla disattivazione della sfocatura in fase di runtime. Garantisce che i contenuti della finestra di dialogo siano leggibili in qualsiasi di queste condizioni regolando l'alfa del drawable dello sfondo della finestra e la quantità di attenuazione della finestra.

public class MainActivity extends Activity {

    private final int mBackgroundBlurRadius = 80;
    private final int mBlurBehindRadius = 20;

    // We set a different dim amount depending on whether window blur is enabled or disabled
    private final float mDimAmountWithBlur = 0.1f;
    private final float mDimAmountNoBlur = 0.4f;

    // We set a different alpha depending on whether window blur is enabled or disabled
    private final int mWindowBackgroundAlphaWithBlur = 170;
    private final int mWindowBackgroundAlphaNoBlur = 255;

    // Use a rectangular shape drawable for the window background. The outline of this drawable
    // dictates the shape and rounded corners for the window background blur area.
    private Drawable mWindowBackgroundDrawable;

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

        mWindowBackgroundDrawable = getDrawable(R.drawable.window_background);
        getWindow().setBackgroundDrawable(mWindowBackgroundDrawable);

        if (buildIsAtLeastS()) {
            // Enable blur behind. This can also be done in xml with R.attr#windowBlurBehindEnabled
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

            // Register a listener to adjust window UI whenever window blurs are enabled/disabled
            setupWindowBlurListener();
        } else {
            // Window blurs are not available prior to Android S
            updateWindowForBlurs(false /* blursEnabled */);
        }

        // Enable dim. This can also be done in xml, see R.attr#backgroundDimEnabled
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    /**
     * Set up a window blur listener.
     *
     * Window blurs might be disabled at runtime in response to user preferences or system states
     * (e.g. battery saving mode). WindowManager#addCrossWindowBlurEnabledListener allows to
     * listen for when that happens. In that callback we adjust the UI to account for the
     * added/missing window blurs.
     *
     * For the window background blur we adjust the window background drawable alpha:
     *     - lower when window blurs are enabled to make the blur visible through the window
     *       background drawable
     *     - higher when window blurs are disabled to ensure that the window contents are readable
     *
     * For window blur behind we adjust the dim amount:
     *     - higher when window blurs are disabled - the dim creates a depth of field effect,
     *       bringing the user's attention to the dialog window
     *     - lower when window blurs are enabled - no need for a high alpha, the blur behind is
     *       enough to create a depth of field effect
     */
    @RequiresApi(api = Build.VERSION_CODES.S)
    private void setupWindowBlurListener() {
        Consumer<Boolean> windowBlurEnabledListener = this::updateWindowForBlurs;
        getWindow().getDecorView().addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }

                    @Override
                    public void onViewDetachedFromWindow(View v) {
                        getWindowManager().removeCrossWindowBlurEnabledListener(
                                windowBlurEnabledListener);
                    }
                });
    }

    private void updateWindowForBlurs(boolean blursEnabled) {
        mWindowBackgroundDrawable.setAlpha(blursEnabled && mBackgroundBlurRadius > 0 ?
                mWindowBackgroundAlphaWithBlur : mWindowBackgroundAlphaNoBlur);
        getWindow().setDimAmount(blursEnabled && mBlurBehindRadius > 0 ?
                mDimAmountWithBlur : mDimAmountNoBlur);

        if (buildIsAtLeastS()) {
            // Set the window background blur and blur behind radii
            getWindow().setBackgroundBlurRadius(mBackgroundBlurRadius);
            getWindow().getAttributes().setBlurBehindRadius(mBlurBehindRadius);
            getWindow().setAttributes(getWindow().getAttributes());
        }
    }

    private static boolean buildIsAtLeastS() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
    }
}

Per creare angoli arrotondati per la finestra, definiamo lo sfondo della finestra in res/drawable/window_background.xml come ShapeDrawable con angoli arrotondati con raggio di 20 dp come segue:

<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
    <corners android:radius="20dp"/>
    <solid android:color="#AAAAAA"/>
</shape>

Le sfocature della finestra sfocano i contenuti della finestra sottostante l'attività. L'immagine sfocata viene disegnata sotto questa finestra di attività, quindi la finestra di attività deve essere traslucida per consentire la visibilità della sfocatura. Per rendere la finestra traslucida, impostiamo R.attr.windowIsTranslucent nel tema dell'attività come segue:

<style name="Theme.BlurryDialog" parent="Theme.MaterialComponents.Dialog">
    <item name="android:windowIsTranslucent">true</item>
</style>

OEM e partner

Per avere l'effetto sfocatura delle finestre su un dispositivo, l'OEM deve dichiarare che il dispositivo supporta le sfocature delle finestre.

Per controllare se il dispositivo supporta le sfocature delle finestre:

  • Assicurati che il dispositivo possa gestire il carico aggiuntivo della GPU. I dispositivi di fascia bassa potrebbero non essere in grado di gestire il carico aggiuntivo, il che può causare la perdita di frame. Attiva le sfocature delle finestre solo sui dispositivi testati con potenza della GPU sufficiente.

  • Se hai un motore di rendering personalizzato, assicurati che implementi la logica di sfocatura. Il motore di rendering predefinito di Android 12 implementa la logica di sfocatura in BlurFilter.cpp.

Dopo aver verificato che il dispositivo supporta le sfocature delle finestre, imposta il seguente sysprop di SurfaceFlinger:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Convalida

Per verificare che la finestra dell'app venga gestita correttamente quando si passa dallo stato con sfocatura abilitata a quello con sfocatura disabilitata, segui questi passaggi:

  1. Apri l'interfaccia utente con la sfocatura.

  2. Attiva o disattiva le sfocature delle finestre attivando e disattivando la sfocatura delle finestre.

  3. Verifica che l'interfaccia utente della finestra passi dallo stato sfocato a quello normale e viceversa come previsto.

Attivare e disattivare la sfocatura della finestra

Per testare il rendering dell'interfaccia utente della finestra con l'effetto di sfocatura, attiva o disattiva le sfocature utilizzando uno dei seguenti metodi:

  • Dalle opzioni sviluppatore:

    Impostazioni -> Sistema -> Opzioni sviluppatore -> Rendering con accelerazione hardware -> Consenti sfocature a livello di finestra

  • Dal terminale su un dispositivo rooted:

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

Per verificare se il tuo dispositivo Android 12+ supporta le sfocature delle finestre e se sono attualmente attive, esegui adb shell wm disable-blur su un dispositivo rooted.

Risoluzione dei problemi

Utilizza le seguenti informazioni come guida per la risoluzione dei problemi durante la convalida.

Nessun sfocatura disegnata

  • Verifica che le sfocature siano attualmente attive e che l'hardware le supporti. Consulta l'articolo Attivare e disattivare la sfocatura della finestra.

  • Assicurati di impostare un colore di sfondo della finestra traslucido. Un colore di sfondo opaco della finestra nasconde l'area sfocata.

Il dispositivo di test non supporta le sfocature delle finestre

  • Testa l'applicazione sull'emulatore Android 12. Per configurare un emulatore Android, consulta Configurare un emulatore Android. Qualsiasi dispositivo virtuale Android creato con l'emulatore supporta le sfocature delle finestre.

Nessun angolo arrotondato

L'aggiornamento dell'opzione sviluppatore non attiva le sfocature

  • Controlla se il dispositivo è in modalità di risparmio energetico o se utilizza il tunneling multimediale. Su alcuni dispositivi TV, le sfocature delle finestre potrebbero essere disattivate anche durante la riproduzione video.

Sfocatura dello sfondo disegnata a schermo intero, non all'interno dei limiti della finestra

Gli aggiornamenti del listener non vengono applicati sullo schermo

  • Gli aggiornamenti del listener potrebbero essere applicati a un'istanza della finestra precedente. Controlla se la finestra viene eliminata e ricreata con l'aggiornamento del listener corretto.