Sfocature finestre

In Android 12, sono disponibili API pubbliche per implementare gli effetti di sfocatura delle finestre, ad esempio la sfocatura dello sfondo.

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

  • La sfocatura sfondo consente di creare finestre con sfondi sfocati, creando un effetto vetro satinato.

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

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

solo sfocatura sfondo

a

sfoca solo dietro

B

sfocatura dietro e sfocatura sfondo

C

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

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

Implementazione

Sviluppatori di app

Gli sviluppatori di app devono fornire un raggio di sfocatura per creare un effetto sfocatura. Il raggio di sfocatura controlla la densità della sfocatura, ovvero più elevato è il raggio, più intensa sarà la sfocatura. Un valore di sfocatura pari a 0 px indica che non è presente 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 valori di raggio di sfocatura superiori a 150 pixel, in quanto influiscono notevolmente sul rendimento.

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

Sfocatura sfondo

Utilizza la sfocatura dello sfondo nelle finestre mobili per creare un effetto di sfondo della finestra, ovvero un'immagine sfocata dei contenuti sottostanti. Per aggiungere uno sfondo sfocato per la 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.

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

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

  5. Gestire gli stati di attivazione e disattivazione della sfocatura. Per ulteriori informazioni, consulta la sezione Linee guida per l'utilizzo della sfocatura delle finestre 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 gli elementi sullo schermo dietro la finestra.

Per sfocare i contenuti dietro la finestra:

  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 una sfocatura dietro il raggio. In alternativa, nel tema della finestra, imposta R.attr.windowBlurBehindRadius.

  3. Se vuoi, puoi scegliere una quantità di luminosità complementare.

  4. Gestire gli stati di attivazione e disattivazione della sfocatura. Per ulteriori informazioni, consulta la sezione Linee guida per l'utilizzo dell'effetto sfocatura della finestra nelle app.

Linee guida per usare la sfocatura delle finestre nelle app

Il supporto per la sfocatura delle finestre dipende da quanto segue:

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

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

  • Stato del sistema: il server di sistema potrebbe disattivare temporaneamente l'effetto sfocatura della finestra in fase di esecuzione, ad esempio in modalità di risparmio batteria, durante la riproduzione di determinati tipi di contenuti video o a causa di un'override dello sviluppatore.

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

  • Aggiungi un listener tramite WindowManager#addCrossWindowBlurEnabledListener per ricevere una notifica quando le sfocature delle finestre sono attivate o disattivate. Inoltre, utilizza WindowManager#isCrossWindowBlurEnabled per chiedere se le sfocature delle finestre sono attualmente abilitate.

  • Implementa due versioni per lo sfondo della finestra, in base allo stato attivo o disattivato delle sfocature delle finestre.

    Quando le sfocature sono attivate, lo sfondo della finestra deve essere trasparente per rendere visibile la sfocatura. In questo stato, quando le sfocature vengono disattivate, i contenuti della finestra si sovrappongono direttamente a quelli della finestra sottostante, rendendo la finestra sovrapposta meno leggibile. Per evitare questo effetto, quando l'effetto sfocatura delle finestre è disabilitato, adatta l'interfaccia utente dell'app come segue:

    • Per la sfocatura dello sfondo, aumenta l'alpha dell'elemento drawable dello sfondo della finestra, rendendolo più opaco.

    • Per una sfocatura dello sfondo, aggiungi un livello di attenuazione più alto.

Esempio di sfocatura dietro e sfocatura sfondo

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

Il seguente esempio di MainActivity.java è una finestra di dialogo con un raggio di sfocatura dietro il raggio di 20 px e un raggio di sfocatura dello sfondo di 80 px. Ha gli angoli arrotondati, definiti in XML nello sfondo della finestra drawable. Gestisce correttamente versioni diverse di Android, dispositivi diversi (che potenzialmente non supportano l'effetto sfocatura della finestra) e modifiche all'attivazione o alla disattivazione della sfocatura in fase di runtime. Garantisce che i contenuti delle finestre di dialogo siano leggibili in una qualsiasi di queste condizioni regolando l'alpha del rendering 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 i bordi arrotondati della finestra, definiamo lo sfondo della finestra in res/drawable/window_background.xml come ShapeDrawable con bordi arrotondati con raggio 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 delle finestre sfocano il contenuto della finestra sotto l'attività. L'immagine sfumata viene disegnata sotto questa finestra di attività, pertanto 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à in questo modo:

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

OEM e partner

Per avere la sfocatura della finestra su un dispositivo, l'OEM deve dichiarare che il dispositivo supporta la sfocatura della finestra.

Per verificare se il dispositivo è in grado di supportare le sfocature delle finestre, procedi nel seguente modo:

  • 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, causando la caduta dei frame. Attiva l'effetto sfocatura delle finestre solo sui dispositivi testati con potenza GPU sufficiente.

  • Se disponi di un motore di rendering personalizzato, assicurati che quest'ultimo 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 sia in grado di supportare le sfocature delle finestre, imposta la seguente flangia sysprop:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Convalida

Per verificare che la finestra dell'app sia gestita correttamente quando passi dallo stato attivato a quello disattivato, procedi nel seguente modo:

  1. Apri l'interfaccia utente con l'effetto sfocatura.

  2. Attiva o disattiva l'effetto sfocatura delle finestre attivando e disattivando l'opzione.

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

Attivare e disattivare la sfocatura della finestra

Per verificare in che modo l'interfaccia utente delle finestre viene visualizzata con l'effetto sfocature finestra, 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 o versioni successive supporta la sfocatura delle finestre e se questa è attualmente attiva, esegui adb shell wm disable-blur su un dispositivo rooted.

Risoluzione dei problemi

Fai riferimento a quanto segue come guida per la risoluzione dei problemi durante la convalida.

Nessuna sfocatura applicata

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

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

Il dispositivo di test non supporta le sfocature delle finestre

  • Testa la tua applicazione sull'emulatore Android 12. Per configurare un emulatore Android, leggi l'articolo Configurare un emulatore Android. Qualsiasi dispositivo virtuale Android creato con l'emulatore supporta le sfocature.

Nessun angolo arrotondato

L'aggiornamento dell'opzione sviluppatore non attiva le sfocature

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

Sfocatura sfondo tracciata a schermo intero, non entro i margini della finestra

Gli aggiornamenti dall'ascoltatore non vengono applicati sullo schermo

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