Sfocature delle finestre

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

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

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

  • Sfocatura dello sfondo 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 sfondo

a

sfocatura solo dietro

b

sfocatura dietro e sfocatura sfondo

c

Figura 1. Solo sfocatura dello sfondo (a), solo sfocatura dietro (b), sfocatura dello 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 della sfocatura, 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 di sfocatura. Il raggio di sfocatura controlla la densità della sfocatura, ovvero maggiore è il raggio, maggiore è la densità della 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 di sfocatura desiderato e aumentare la leggibilità, scegli un valore del raggio di sfocatura integrato con uno strato di colore traslucido.

Sfocatura sfondo

Utilizza la sfocatura dello sfondo sulle finestre mobili per creare un effetto di sfondo della finestra, ovvero 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 consentire la visualizzazione della sfocatura.

  3. Se vuoi, chiama Window#setBackgroundDrawableResource(int) per aggiungere un drawable 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 elemento drawable dello sfondo della finestra.

  5. Gestisci gli stati di sfocatura abilitati e disabilitati. Per saperne di più, consulta la sezione Linee guida per l'utilizzo della sfocatura delle finestre nelle app.

Sfocatura dietro

La sfocatura dello sfondo sfoca l'intero schermo dietro la finestra. Questo effetto viene utilizzato per indirizzare l'attenzione dell'utente verso i 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 dello sfondo. In alternativa, nel tema della finestra, imposta R.attr.windowBlurBehindEnabled.

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

  3. Facoltativamente, scegli un livello di oscuramento complementare.

  4. Gestisci gli stati di sfocatura abilitati e disabilitati. Per saperne di più, consulta la sezione Linee guida per l'utilizzo della sfocatura delle finestre nelle app.

Linee guida per l'utilizzo della sfocatura delle finestre 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à Basso consumo, durante la riproduzione di determinati tipi di contenuto video o a causa di un override dello sviluppatore.

Per rendere la tua app compatibile con le 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 vengono attivate o disattivate. Inoltre, utilizza WindowManager#isCrossWindowBlurEnabled per verificare se le sfocature delle finestre sono attualmente attive.

  • Implementa due versioni per lo sfondo della finestra, per adattarle allo stato attivato o disattivato delle sfocature della finestra.

    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 come segue:

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

    • Per la sfocatura dietro, aggiungi un livello di oscuramento con un valore di oscuramento più elevato.

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.

L'esempio seguente di MainActivity.java è una finestra di dialogo con un raggio di sfocatura posteriore di 20 px e un raggio di sfocatura dello sfondo di 80 px. Ha angoli arrotondati, definiti in XML nell'elemento drawable dello sfondo della finestra. Gestisce correttamente le diverse versioni di Android, i diversi dispositivi (che potrebbero non supportare le sfocature delle finestre) e le modifiche di attivazione o disattivazione della sfocatura di runtime. In questo modo, i contenuti della finestra di dialogo sono leggibili in qualsiasi condizione, regolando l'alpha disegnabile dello sfondo della finestra e la quantità di oscuramento 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 sotto 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 la sfocatura delle finestre su un dispositivo, l'OEM deve dichiarare che il dispositivo supporta la sfocatura delle finestre.

Per verificare se il tuo dispositivo supporta le sfocature delle finestre, segui questi passaggi:

  • 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 frame persi. Attiva le sfocature delle finestre solo sui dispositivi testati con una 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 SurfaceFlinger sysprop:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Convalida

Per verificare che la finestra dell'app venga gestita correttamente quando passi dallo stato di sfocatura attivata a quello di sfocatura disattivata e viceversa, segui questi passaggi:

  1. Apri la UI con la sfocatura.

  2. Attiva o disattiva la sfocatura delle finestre attivando e disattivando l'opzione Sfocatura finestra.

  3. Verifica che la UI della finestra passi da uno stato sfocato a uno non sfocato e viceversa, come previsto.

Attiva e disattiva la sfocatura della finestra

Per testare il rendering della UI della finestra con l'effetto di sfocatura della 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 le sfocature delle finestre e se queste 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.

Nessuna sfocatura disegnata

  • Verifica che le sfocature siano attualmente attive e che il tuo hardware le supporti. Consulta l'articolo Attiva e disattiva 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, consulta Configura un emulatore Android. Qualsiasi Android Virtual Device 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 di video.

Sfocatura dello sfondo disegnata a schermo intero, non entro i 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.