Flous sur les fenêtres

Sous Android 12, des API publiques sont disponibles pour implémenter des effets de floutage des fenêtres, tels que le flou d'arrière-plan et le flou en arrière-plan.

Le floutage transversal permet de flouter l'écran derrière une fenêtre donnée. Il existe deux types de floutage de fenêtre, qui peuvent être utilisés pour obtenir différents effets visuels :

  • L'option Flou d'arrière-plan vous permet de créer des fenêtres avec des arrière-plans floutés, créant ainsi un effet de verre dépoli.

  • Flou derrière vous permet de flouter l'intégralité de l'écran derrière une fenêtre (de dialogue), créant ainsi un effet de profondeur de champ.

Les deux effets peuvent être utilisés séparément ou combinés, comme illustré dans la figure suivante :

floutage de l'arrière-plan uniquement

a

flou derrière uniquement

B

flou derrière et flou d'arrière-plan

c

Figure 1 : Flou d'arrière-plan uniquement (a), Flou d'arrière-plan uniquement (b), flou d'arrière-plan et flou derrière (c)

La fonctionnalité de floutage des fenêtres s'exécute sur toutes les fenêtres, ce qui signifie qu'elle fonctionne également lorsqu'une autre application se trouve derrière votre fenêtre. Cet effet est différent de l'effet de floutage, qui floute le contenu à l'intérieur de la même fenêtre. Le floutage des fenêtres est utile pour les boîtes de dialogue, les bottom sheets et les autres fenêtres flottantes.

Implémentation

Développeurs d'applications

Les développeurs d'applications doivent indiquer un rayon de floutage pour créer un effet de flou. Le rayon du flou contrôle la densité du flou. Autrement dit, plus le rayon est élevé, plus le flou est dense. Avec un flou de 0 px, pas de flou. Pour le floutage en arrière-plan, un rayon de 20 px crée un bon effet de profondeur de champ, tandis qu'un rayon de floutage de l'arrière-plan de 80 px crée un bon effet de verre dépoli. Évitez d'utiliser des rayons de flou supérieurs à 150 px, car cela affectera considérablement les performances.

Pour obtenir l'effet de flou souhaité et améliorer la lisibilité, choisissez une valeur de rayon du flou complétée par une couche de couleur translucide.

Flou d'arrière-plan

Utilisez le floutage de l'arrière-plan sur les fenêtres flottantes pour créer un effet d'arrière-plan de fenêtre, qui est une image floutée du contenu sous-jacent. Pour ajouter un arrière-plan flou à votre fenêtre, procédez comme suit :

  1. Appelez Window#setBackgroundBlurRadius(int) pour définir un rayon de floutage de l'arrière-plan. Vous pouvez également définir R.attr.windowBackgroundBlurRadius dans le thème de la fenêtre.

  2. Définissez R.attr.windowIsTranslucent sur "true" pour rendre la fenêtre transparente. Le flou est dessiné sous la surface de la fenêtre. La fenêtre doit donc être translucide pour que le flou soit visible.

  3. Vous pouvez également appeler Window#setBackgroundDrawableResource(int) pour ajouter un drawable d'arrière-plan de fenêtre rectangulaire avec une couleur translucide. Vous pouvez également définir R.attr.windowBackground dans le thème de la fenêtre.

  4. Pour une fenêtre aux coins arrondis, déterminez les coins arrondis de la zone floutée en définissant un ShapeDrawable avec des coins arrondis comme drawable d'arrière-plan de la fenêtre.

  5. Gérer les états de flou activé et désactivé. Pour en savoir plus, consultez la section Consignes d'utilisation du floutage de fenêtre dans les applications.

Flou derrière

Le flou derrière floute tout l'écran derrière la fenêtre. Cet effet permet de diriger l'attention de l'utilisateur vers le contenu de la fenêtre en floutant tout ce qui se trouve à l'écran derrière la fenêtre.

Pour flouter le contenu derrière votre fenêtre, procédez comme suit :

  1. Ajoutez FLAG_BLUR_BEHIND aux indicateurs de fenêtre pour activer le floutage en arrière-plan. Vous pouvez également définir R.attr.windowBlurBehindEnabled dans le thème de la fenêtre.

  2. Appelez WindowManager.LayoutParams#setBlurBehindRadius pour définir un flou derrière le rayon. Vous pouvez également définir R.attr.windowBlurBehindRadius dans le thème de la fenêtre.

  3. Vous pouvez également choisir un montant de dimension complémentaire.

  4. Gérer les états "Flou" activé et désactivé. Pour en savoir plus, consultez la section Consignes d'utilisation du floutage de fenêtre dans les applications.

Consignes concernant l'utilisation du flou des fenêtres dans les applications

La prise en charge du floutage des fenêtres dépend des éléments suivants:

  • Version d'Android: les API de floutage de Windows ne sont disponibles que sur Android 12 ou version ultérieure. Vérifiez la version Android du SDK de l'appareil.

  • Performances graphiques: les appareils avec des GPU moins performants peuvent choisir de ne pas prendre en charge le floutage des fenêtres.

  • État du système: le serveur système peut désactiver temporairement les floutages de fenêtre au moment de l'exécution, par exemple en mode Économie de batterie, pendant la lecture de certains types de contenus vidéo ou à la suite d'un remplacement défini par le développeur.

Pour que votre application soit compatible avec les versions d'Android, les appareils et les états système, suivez ces consignes:

  • Ajoutez un écouteur via WindowManager#addCrossWindowBlurEnabledListener pour être averti lorsque le floutage de la fenêtre est activé ou désactivé. De plus, utilisez WindowManager#isCrossWindowBlurEnabled pour vérifier si le floutage des fenêtres est actuellement activé.

  • Implémentez deux versions pour l'arrière-plan de la fenêtre, afin de tenir compte de l'état activé ou désactivé des floutages de fenêtre.

    Lorsque les floutages sont activés, l'arrière-plan de la fenêtre doit être translucide pour que le flou soit visible. Dans cet état, lorsque les flous sont désactivés, le contenu de la fenêtre se superpose directement au contenu de la fenêtre sous-jacente, ce qui rend la fenêtre superposée moins lisible. Pour éviter un tel effet, lorsque le floutage de la fenêtre est désactivé, adaptez l'UI de l'application comme suit:

    • Pour le floutage de l'arrière-plan, augmentez l'alpha du drawable d'arrière-plan de la fenêtre, ce qui le rend plus opaque.

    • Pour flouter l'arrière-plan, ajoutez un calque de masquage avec un niveau de masquage plus élevé.

Exemple de floutage derrière et d'arrière-plan

Cette section fournit un exemple pratique d'activité qui utilise à la fois le floutage derrière et le flou d'arrière-plan.

L'exemple suivant de MainActivity.java est une boîte de dialogue avec un rayon de flou derrière de 20 px et un rayon de flou d'arrière-plan de 80 px. Ses angles sont arrondis, définis en XML dans le drawable d'arrière-plan de la fenêtre. Il gère correctement les différentes versions d'Android, les différents appareils (qui ne sont pas forcément compatibles avec le floutage de fenêtre) et les modifications d'activation ou de désactivation du floutage d'exécution. Il garantit que le contenu de la boîte de dialogue est lisible dans l'une de ces conditions en ajustant la valeur alpha du drawable d'arrière-plan de la fenêtre et la quantité d'assombrissement de la fenêtre.

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;
    }
}

Pour créer des angles arrondis pour la fenêtre, nous définissons l'arrière-plan de la fenêtre dans res/drawable/window_background.xml en tant que ShapeDrawable avec des coins arrondis dont le rayon est de 20 dp, comme suit:

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

Le floutage de la fenêtre floute le contenu de la fenêtre sous l'activité. L'image floutée est dessinée sous cette fenêtre d'activité. La fenêtre d'activité doit donc être transparente pour que le floutage soit visible. Pour rendre la fenêtre translucide, nous définissons R.attr.windowIsTranslucent dans le thème de l'activité comme suit:

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

OEM et partenaires

Pour que le floutage de fenêtre soit disponible sur un appareil, l'OEM doit déclarer que l'appareil est compatible avec le floutage de fenêtre.

Pour vérifier si votre appareil est compatible avec le floutage des fenêtres, procédez comme suit :

  • Assurez-vous que l'appareil peut gérer la charge supplémentaire du GPU. Les appareils d'entrée de gamme risquent de ne pas pouvoir gérer la charge supplémentaire, ce qui peut entraîner une perte de frames. N'activez le floutage des fenêtres que sur les appareils testés qui disposent d'un GPU suffisamment puissant.

  • Si vous disposez d'un moteur de rendu personnalisé, assurez-vous qu'il met en œuvre la logique de floutage. Le moteur de rendu par défaut d'Android 12 implémente la logique de floutage dans BlurFilter.cpp.

Une fois que vous vous êtes assuré que votre appareil peut prendre en charge le floutage des fenêtres, définissez le sysprop de flinger de surface suivant:

PRODUCT_VENDOR_PROPERTIES += \
       ro.surface_flinger.supports_background_blur=1

Validation

Pour vérifier que la fenêtre de votre application est correctement gérée lors du basculement entre les états de floutage activé et désactivé, procédez comme suit :

  1. Ouvrez l'interface utilisateur floutée.

  2. Activez ou désactivez le floutage des vitres en activant ou en désactivant le floutage des vitres.

  3. Vérifiez que l'UI de la fenêtre passe de l'état flou à l'état flou comme prévu.

Activer et désactiver le flou des vitres

Pour tester le rendu de l'interface utilisateur de la fenêtre avec l'effet de floutage de la fenêtre, activez ou désactivez le floutage à l'aide de l'une des méthodes suivantes :

  • Dans les options pour les développeurs :

    Paramètres > Système > Options pour les développeurs > Affichage accéléré par le matériel > Autoriser le floutage au niveau de la fenêtre

  • Depuis le terminal d'un appareil en mode root :

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

Pour vérifier si votre appareil Android 12 ou version ultérieure est compatible avec le floutage des fenêtres et si celui-ci est actuellement activé, exécutez adb shell wm disable-blur sur un appareil en mode root.

Dépannage

Utilisez le guide suivant pour résoudre les problèmes lors de la validation.

Aucun flou dessiné

  • Vérifiez que les flous sont actuellement activés et que votre matériel les prend en charge. Consultez Activer et désactiver le floutage des vitres.

  • Assurez-vous d'avoir défini une couleur d'arrière-plan translucide pour la fenêtre. Une couleur d'arrière-plan opaque de la fenêtre masque la zone floutée.

L'appareil de test n'est pas compatible avec le floutage des fenêtres

  • Testez votre application sur l'émulateur Android 12. Pour configurer un émulateur Android, consultez Configurer un émulateur Android. Tout appareil virtuel Android que vous créez avec l'émulateur est compatible avec le floutage de la fenêtre.

Pas d'angles arrondis

La mise à jour de l'option pour les développeurs n'active pas le floutage

  • Vérifiez si l'appareil est en mode Économie de batterie ou s'il utilise un tunnel multimédia. Sur certains téléviseurs, le floutage des fenêtres peut également être désactivé pendant la lecture de la vidéo.

Flou d'arrière-plan dessiné en plein écran, mais pas dans les limites de la fenêtre

Les mises à jour de l'écouteur ne sont pas appliquées à l'écran

  • Les mises à jour de l'écouteur peuvent être appliquées à une ancienne instance de fenêtre. Vérifiez si la fenêtre est détruite et recréée avec la mise à jour de l'écouteur appropriée.