La finestra si offusca

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

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

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

  • Sfoca dietro 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

UN

sfocatura solo dietro

B

sfocatura dietro e sfocatura dello sfondo

C

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

La funzione 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 è uguale all'effetto di rendering sfocatura , che sfoca il contenuto 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 sfocato. Il raggio di sfocatura controlla quanto è densa la sfocatura, ovvero maggiore è 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, poiché ciò influirà in modo significativo sulle prestazioni.

Per ottenere l'effetto di sfocatura desiderato e aumentare la leggibilità, scegliere un valore del raggio di sfocatura integrato con uno strato di colore traslucido.

Sfocatura dello sfondo

Utilizza la sfocatura dello sfondo sulle finestre mobili per creare un effetto di sfondo della finestra che rappresenti un'immagine sfocata del contenuto sottostante. Per aggiungere uno sfondo sfocato alla tua finestra, procedi come segue:

  1. Chiama Window#setBackgroundBlurRadius(int) per impostare un raggio di sfocatura dello sfondo. Oppure, 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. Facoltativamente, chiama Window#setBackgroundDrawableResource(int) per aggiungere uno sfondo di finestra rettangolare disegnabile con un colore traslucido. Oppure, nel tema della finestra, imposta R.attr.windowBackground .

  4. Per una finestra con angoli arrotondati, determinare gli angoli arrotondati per l'area sfocata impostando un oggetto ShapeDrawable con angoli arrotondati come sfondo disegnabile della finestra.

  5. Gestisci gli stati di attivazione e disattivazione della sfocatura. Fare riferimento alla sezione Linee guida per utilizzare la sfocatura della finestra nelle app per ulteriori informazioni.

Sfocatura dietro

La sfocatura dietro sfoca l'intero schermo dietro la finestra. Questo effetto viene utilizzato per dirigere l'attenzione dell'utente verso il contenuto della finestra sfocando qualsiasi cosa sullo schermo dietro la finestra.

Per sfocare il contenuto dietro la finestra, procedi nel seguente modo:

  1. Aggiungi FLAG_BLUR_BEHIND ai flag della finestra, per abilitare la sfocatura dietro. Oppure, nel tema della finestra, imposta R.attr.windowBlurBehindEnabled .

  2. Chiama WindowManager.LayoutParams#setBlurBehindRadius per impostare una sfocatura dietro il raggio. Oppure, nel tema della finestra, imposta R.attr.windowBlurBehindRadius .

  3. Facoltativamente, scegli un importo dim complementare .

  4. Gestisci gli stati di attivazione e disattivazione della sfocatura. Fare riferimento alla sezione Linee guida per utilizzare la sfocatura della finestra nelle app per ulteriori informazioni.

Linee guida per utilizzare la sfocatura della finestra nelle app

Il supporto per la sfocatura di Windows dipende da quanto segue:

  • Versione Android: le API di sfocatura di Windows sono disponibili solo su Android 12 e versioni successive. Controlla l'SDK del dispositivo per la versione 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 esecuzione, ad esempio durante la modalità di risparmio della batteria, durante la riproduzione di determinati tipi di contenuti video o a causa di un intervento dello sviluppatore.

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

  • Aggiungi un ascoltatore tramite WindowManager#addCrossWindowBlurEnabledListener , per avvisarti quando le sfocature delle finestre sono abilitate o disabilitate. Inoltre, utilizza WindowManager#isCrossWindowBlurEnabled per verificare se le sfocature delle finestre sono attualmente abilitate.

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

    Quando le sfocature sono abilitate, lo sfondo della finestra dovrebbe essere traslucido per rendere visibile la sfocatura. In questo stato, quando le sfocature vengono disabilitate, il contenuto della finestra si sovrappone direttamente al contenuto della finestra sottostante, rendendo meno leggibile la finestra sovrapposta. Per evitare questo effetto, quando le sfocature delle finestre sono disabilitate, adatta l'interfaccia utente dell'app come segue:

    • Per la sfocatura dello sfondo, aumenta l'alfa dello sfondo disegnabile della finestra, rendendolo più opaco.

    • Per sfocare dietro, aggiungi un livello attenuato con una quantità attenuata maggiore.

Esempio di sfocatura dietro e sfocatura dello sfondo

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

Il seguente esempio di MainActivity.java è una finestra di dialogo con un raggio di sfocatura dietro di 20 px e un raggio di sfocatura dello sfondo di 80 px. Ha gli angoli arrotondati, definiti in xml nello sfondo disegnabile della finestra. Gestisce correttamente diverse versioni di Android, diversi dispositivi (che potenzialmente non supportano la sfocatura delle finestre) e le modifiche abilitate o disabilitate dalla sfocatura in runtime. Garantisce che il contenuto della finestra di dialogo sia leggibile in una qualsiasi di queste condizioni regolando l'alfa disegnabile 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 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 sfocata 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à 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 le sfocature delle finestre.

Per verificare se il tuo dispositivo può supportare le sfocature delle finestre, procedi come segue:

  • 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 fotogrammi. Abilita le sfocature delle finestre solo sui dispositivi testati con potenza GPU sufficiente.

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

Dopo esserti assicurato che il tuo dispositivo possa supportare le sfocature delle finestre, imposta il seguente sysprop del flinger di superficie:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Validazione

Per verificare che la finestra dell'app venga gestita correttamente quando si passa dallo stato sfocatura abilitata a quello disabilitato, attenersi alla seguente procedura:

  1. Apri l'interfaccia utente sfocata.

  2. Abilita o disabilita la sfocatura della finestra attivando e disattivando la sfocatura della finestra .

  3. Verificare che l'interfaccia utente della finestra cambi da e verso lo stato sfocato come previsto.

Attiva e disattiva la sfocatura della finestra

Per testare il rendering dell'interfaccia utente della finestra con l'effetto sfocatura della finestra, abilitare o disabilitare 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 le sfocature delle finestre sono attualmente abilitate, esegui adb shell wm disable-blur su un dispositivo rooted.

Risoluzione dei problemi

Utilizzare quanto segue come guida per la risoluzione dei problemi durante la convalida.

Nessuna sfocatura disegnata

  • Verifica che le sfocature siano attualmente abilitate e che il tuo hardware le supporti. Fare riferimento a 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 la tua applicazione sull'emulatore Android 12. Per configurare un emulatore Android, fare riferimento a Configurazione di 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 abilita le sfocature

  • Controlla se il dispositivo è in modalità di risparmio energetico o se sta utilizzando 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 entro i limiti della finestra

Gli aggiornamenti dall'ascoltatore non vengono applicati sullo schermo

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